grooph 0.4.0 → 0.4.1
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/THIRD-PARTY-NOTICES.md +1 -1
- package/dist/app/assets/{App-CFO6bPna.js → App-48y1Ec5B.js} +4 -4
- package/dist/app/assets/{EmbedApp-B5LWao3x.js → EmbedApp-390Z2d4x.js} +1 -1
- package/dist/app/assets/{ExportPanel-VWus7GM3.js → ExportPanel-Ca3wBB38.js} +1 -1
- package/dist/app/assets/{Import-YEKofx4_.js → Import-ByMI7Uz9.js} +1 -1
- package/dist/app/assets/brakes-BJPDrrJT.js +1 -0
- package/dist/app/assets/{builtins-Cbs5iQtH.js → builtins-D_22fKRF.js} +1 -1
- package/dist/app/assets/{graph-more-BKW9C4-h.js → graph-more-393HTgQE.js} +1 -1
- package/dist/app/assets/{graph-stage-CWh3OWga.js → graph-stage-BkrQGQ-z.js} +1 -1
- package/dist/app/assets/{graph-views-tFUJK-be.js → graph-views-COQF_QTQ.js} +2 -2
- package/dist/app/assets/{index-BoSi6XYh.js → index-CeaKwKuU.js} +2 -2
- package/dist/app/assets/{screens-YUd2HaLm.js → screens-aIjMSzZg.js} +7 -7
- package/dist/app/assets/{templates-DvzLa5sE.js → templates-CoNTzuuz.js} +2 -2
- package/dist/app/assets/{units-DRaa5U2m.js → units-DOIUgOIU.js} +1 -1
- package/dist/app/assets/{views-DCEDX6Qx.js → views-CLwg5VNv.js} +1 -1
- package/dist/app/grooph-app.json +1 -1
- package/dist/app/index.html +2 -2
- package/dist/app/routes.json +20 -20
- package/dist/bundle/grooph.js +320 -42
- package/package.json +1 -1
- package/dist/app/assets/brakes-9E9PsV_Z.js +0 -1
package/THIRD-PARTY-NOTICES.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Third-party notices
|
|
2
2
|
|
|
3
|
-
grooph 0.4.
|
|
3
|
+
grooph 0.4.1 is under the MIT license (`LICENSE`). Two of its files are built files that hold other people's code, and this page carries those people's notices, as their licenses ask. It is written by the build from what the builds themselves say went into each file, not from a list kept by hand.
|
|
4
4
|
|
|
5
5
|
## In the app (`dist/app/`), which `grooph watch` serves
|
|
6
6
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/compile-BAvi-rd0.js","assets/share-BzIzB4EY.js","assets/groups-CjEPiwfv.js","assets/Import-
|
|
2
|
-
import{a as e,c as t,n,r,s as i,t as a}from"./index-
|
|
3
|
-
`).toLowerCase()};function Le(e,t){let n=e.template;if(t.kind.length>0&&!t.kind.includes(n.kind)||t.cost.length>0&&!t.cost.includes(n.profile.cost)||t.speed.length>0&&!t.speed.includes(n.profile.speed)||t.rigor.length>0&&!t.rigor.includes(n.profile.rigor)||t.tags.length>0&&!t.tags.every(e=>(n.tags??[]).includes(e)))return!1;let r=Fe(t.q);if(r.length===0)return!0;let i=Ie(e);return r.every(e=>i.includes(e))}function Re(e,t,n){let r=e.template,i=t.template,a=r.title.localeCompare(i.title);if(n===`name`)return a;let o=e=>w[n][e.profile[n]],s=n===`cost`?1:-1;return(o(r)-o(i))*s||a}function ze(e,t){return e.filter(e=>Le(e,t)).sort((e,n)=>Re(e,n,t.sort))}function Be(e){let t=new Map;for(let n of e)for(let e of n.template?.tags??[])t.set(e,(t.get(e)??0)+1);return[...t].sort((e,t)=>t[1]-e[1]||e[0].localeCompare(t[0])).map(([e])=>e)}var z=(e,t)=>e.includes(t)?e.filter(e=>e!==t):[...e,t],B=`grooph.templates.browse`,Ve=e=>Array.isArray(e)&&e.every(e=>typeof e==`string`);function He(){try{let e=localStorage.getItem(B);if(e===null)return L;let t=JSON.parse(e),n=(e,t)=>Ve(e)?e.filter(e=>t===void 0||t.includes(e)):[];return{q:typeof t.q==`string`?t.q:``,kind:n(t.kind,[`graph`,`fragment`]),cost:n(t.cost,[`low`,`medium`,`high`]),speed:n(t.speed,[`fast`,`medium`,`slow`]),rigor:n(t.rigor,[`light`,`standard`,`high`]),tags:n(t.tags),sort:typeof t.sort==`string`&&t.sort in R?t.sort:`name`,open:t.open===!0}}catch{return L}}function Ue(e){try{Pe(e)&&!e.open?localStorage.removeItem(B):localStorage.setItem(B,JSON.stringify(e))}catch{}}async function We(){let e=await O();return E((await e.templates.list()).map(e=>e.doc))}async function Ge(e){return(await(await O()).templates.get(e))?.doc}async function Ke(e,t={}){if(!e.template)throw Error(`"${e.id}" has no template block`);if(C(e))throw Error(`"${e.id}" carries errors; Yours keeps only templates that validate`);let n=await O(),r=await n.templates.get(e.id);if(r&&!t.replace)return{exists:r.doc};let i=r?Math.max(r.doc.version,e.version)+1:e.version,a={id:e.id,doc:{...structuredClone(e),version:i},savedAt:Date.now()};return await n.templates.put(a),{saved:a,replaced:r!==void 0}}async function qe(e){await(await O()).templates.delete(e)}var Je=e=>`${e.id}.grooph.json`,Ye=e=>v(e),V=(e,t,n=!1)=>`#/templates/${e}/${encodeURIComponent(t)}${n?`/use`:``}`,Xe=[];function Ze(){let[e,t]=(0,k.useState)(T);return(0,k.useEffect)(()=>{if(e!==void 0)return;let n=!0;return S().then(e=>n&&t(e),()=>n&&t(null)),()=>{n=!1}},[]),e}function Qe(){let[e,t]=(0,k.useState)(null),[n,r]=(0,k.useState)(He);(0,k.useEffect)(()=>Ue(n),[n]),(0,k.useEffect)(()=>{let e=!0;return We().then(n=>e&&t(n)),()=>{e=!1}},[]);let i=Ze(),a=i??Xe,o=(0,k.useMemo)(()=>[...e??[],...a],[e,a]),s=(0,k.useMemo)(()=>Be(o),[o]),c=(0,k.useMemo)(()=>ze(e??[],n),[e,n]),l=(0,k.useMemo)(()=>ze(a,n),[a,n]),u=c.length+l.length,[d,f]=(0,k.useState)(b),p=(0,k.useRef)(null),m=()=>{f(`asking`),te().then(f,()=>f(null)).then(()=>setTimeout(()=>p.current?.focus()))},h=o.length,g=Ne(n),[_,v]=(0,k.useState)(!1),y=_?s:s.filter((e,t)=>t<$e||n.tags.includes(e)),S=(e,t)=>r(n=>({...n,[e]:t}));return i===void 0?(0,F.jsx)(`div`,{className:`loading`,children:`Opening…`}):(0,F.jsxs)(`div`,{className:`library templates`,children:[(0,F.jsxs)(`header`,{className:`screen-head`,children:[(0,F.jsx)(`a`,{className:`icon-btn`,href:`#/`,"aria-label":`All graphs`,children:(0,F.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`M15 5 8 12l7 7`})})}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h1`,{children:`Templates`}),(0,F.jsx)(`p`,{className:`muted`,children:`Start a graph from one, or insert one into a graph you have open.`})]})]}),(0,F.jsxs)(`div`,{className:`browse`,role:`search`,children:[(0,F.jsxs)(`div`,{className:`browse-row`,children:[(0,F.jsx)(`input`,{type:`search`,className:`input browse-q`,placeholder:`Search templates`,"aria-label":`Search templates`,value:n.q,onChange:e=>S(`q`,e.target.value),autoComplete:`off`,enterKeyHint:`search`}),(0,F.jsxs)(`button`,{type:`button`,className:`btn browse-toggle${g>0?` is-on`:``}`,"aria-expanded":n.open,"aria-controls":`browse-filters`,onClick:()=>S(`open`,!n.open),children:[`Filters`,g>0?(0,F.jsx)(`span`,{className:`browse-count`,children:g}):null]})]}),(0,F.jsxs)(`div`,{className:`browse-row browse-meta`,children:[(0,F.jsx)(`span`,{className:`muted browse-shown`,role:`status`,"aria-live":`polite`,children:u===h?`${h} templates`:`${u} of ${h}`}),(0,F.jsxs)(`label`,{className:`browse-sort`,children:[(0,F.jsx)(`span`,{className:`muted`,children:`Sort`}),(0,F.jsx)(`select`,{className:`input`,"aria-label":`Sort by`,value:n.sort,onChange:e=>S(`sort`,e.target.value),children:Object.keys(R).map(e=>(0,F.jsx)(`option`,{value:e,children:R[e]},e))})]}),Pe(n)?null:(0,F.jsx)(`button`,{type:`button`,className:`link browse-clear`,onClick:()=>r({...L,open:n.open}),children:`Clear`})]}),n.open?(0,F.jsxs)(`div`,{className:`browse-filters`,id:`browse-filters`,children:[(0,F.jsx)(H,{label:`Kind`,options:[`graph`,`fragment`],text:e=>e===`graph`?`Whole graph`:`Fragment`,on:n.kind,onToggle:e=>S(`kind`,z(n.kind,e))}),[`cost`,`speed`,`rigor`].map(e=>(0,F.jsx)(H,{label:e[0].toUpperCase()+e.slice(1),options:D[e],text:e=>e[0].toUpperCase()+e.slice(1),title:t=>x[e][t],level:t=>w[e][t],on:n[e],onToggle:t=>S(e,z(n[e],t))},e)),s.length>0?(0,F.jsx)(H,{label:`Tags`,options:y,text:e=>e,on:n.tags,onToggle:e=>S(`tags`,z(n.tags,e)),more:s.length>$e?(0,F.jsx)(`button`,{type:`button`,className:`chip chip-small chip-more`,"aria-expanded":_,onClick:()=>v(e=>!e),children:_?`Fewer tags`:`All ${s.length} tags`}):null}):null]}):null]}),e&&e.length>0&&c.length>0?(0,F.jsxs)(`section`,{"aria-labelledby":`yours-title`,children:[(0,F.jsx)(`h2`,{className:`list-title`,id:`yours-title`,children:`Yours`}),(0,F.jsx)(U,{source:`yours`,docs:c})]}):null,l.length>0?(0,F.jsxs)(`section`,{"aria-labelledby":`builtin-title`,children:[(0,F.jsx)(`h2`,{className:`list-title`,id:`builtin-title`,children:`Built-in`}),(0,F.jsx)(U,{source:`built-in`,docs:l})]}):null,i===null?(0,F.jsx)(`p`,{className:`muted templates-hint`,role:`status`,children:`The built-in templates could not be fetched. They need a connection the first time. Yours are listed.`}):null,u===0?(0,F.jsxs)(`p`,{className:`muted templates-hint browse-none`,role:`status`,children:[`No template matches.`,` `,(0,F.jsx)(`button`,{type:`button`,className:`link`,onClick:()=>r({...L,open:n.open}),children:`Clear the search and filters`})]}):null,(0,F.jsxs)(`section`,{"aria-labelledby":`plans-title`,children:[(0,F.jsx)(`h2`,{className:`list-title`,id:`plans-title`,children:`Plans`}),(0,F.jsx)(`p`,{className:`muted templates-hint`,children:ee}),(0,F.jsx)(`p`,{className:`muted templates-hint`,role:`status`,tabIndex:-1,ref:p,children:d&&d!==`asking`?`${d.length} plans, listed whole: the search and filters above are for the templates.`:(0,F.jsxs)(F.Fragment,{children:[d===null?`The plans could not be fetched. They need a connection the first time. `:null,(0,F.jsx)(`button`,{type:`button`,className:`btn`,disabled:d===`asking`,onClick:m,children:d===null?`Try again`:d===`asking`?`Fetching the plans…`:`Show the plans`})]})}),d&&d!==`asking`?(0,F.jsx)(U,{source:`plan`,docs:d}):null]}),e&&e.length===0?(0,F.jsxs)(`p`,{className:`muted templates-hint`,children:[(0,F.jsx)(`strong`,{children:`Yours`}),` is empty. Save a graph, or some of its nodes, as a template from the Graph panel of the editor, or import a template file from the graph list.`]}):null]})}var $e=8;function H({label:e,options:t,text:n,title:r,level:i,on:a,onToggle:o,more:s}){return(0,F.jsxs)(`div`,{className:`browse-group`,role:`group`,"aria-label":e,children:[(0,F.jsx)(`span`,{className:`browse-group-label`,children:e}),(0,F.jsxs)(`div`,{className:`chips browse-chips`,children:[t.map(e=>(0,F.jsxs)(`button`,{type:`button`,className:`chip chip-small${a.includes(e)?` chip-on`:``}`,"aria-pressed":a.includes(e),"aria-label":r?r(e):void 0,onClick:()=>o(e),children:[i?(0,F.jsxs)(`span`,{className:`meter`,"aria-hidden":`true`,"data-level":i(e),children:[(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{})]}):null,n(e)]},e)),s]})]})}function U({source:e,docs:t}){return(0,F.jsx)(`ul`,{className:`template-list`,"aria-label":e===`yours`?`Your templates`:e===`plan`?`Plan templates`:`Built-in templates`,children:t.map(t=>{let n=t.template;return(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{className:`template-row${je(t)?` has-long-glyph`:``}`,href:V(e,t.id),"data-template":t.id,children:[(0,F.jsx)(I,{doc:t,className:`template-glyph`,decorative:!0}),(0,F.jsxs)(`span`,{className:`template-text`,children:[(0,F.jsxs)(`span`,{className:`template-title`,children:[n.title,n.kind===`fragment`?(0,F.jsx)(`span`,{className:`badge badge-quiet`,children:`fragment`}):null,e===`plan`?(0,F.jsx)(`span`,{className:`badge badge-quiet`,children:`plan`}):null]}),(0,F.jsxs)(`span`,{className:`template-when`,children:[(0,F.jsx)(`span`,{className:`template-label`,children:`Use when`}),` `,n.whenToUse]}),e===`plan`?null:(0,F.jsx)(et,{profile:n.profile})]})]})},t.id)})})}function et({profile:e}){return(0,F.jsx)(`ul`,{className:`template-meters`,"aria-label":`Profile`,children:[`cost`,`speed`,`rigor`].map(t=>(0,F.jsxs)(`li`,{className:`template-meter`,"aria-label":x[t][e[t]],title:x[t][e[t]],children:[(0,F.jsxs)(`span`,{className:`meter`,"aria-hidden":`true`,"data-level":w[t][e[t]],children:[(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{})]}),(0,F.jsx)(`span`,{className:`template-meter-word`,"aria-hidden":`true`,children:t})]},t))})}var W=`https://github.com/ryanjosephkamp/grooph`,G=`/grooph/docs/`,K=[{id:`grooph`,label:`Grooph`,dot:`oklch(0.85 0.14 165)`},{id:`meteor`,label:`Meteor`,dot:`oklch(0.9 0.2 124)`}],tt=`groophTheme`,nt=()=>K.find(e=>e.id===document.documentElement.dataset.theme)?.id??K[0].id;function rt(){return(0,F.jsxs)(`svg`,{viewBox:`0 0 32 32`,"aria-hidden":`true`,children:[(0,F.jsx)(`rect`,{width:`32`,height:`32`,rx:`8.5`}),(0,F.jsx)(`path`,{d:`M13.5 12.5 19 21M18.5 12.5 13 21M14 11h4`}),(0,F.jsx)(`circle`,{cx:`10`,cy:`11`,r:`4`}),(0,F.jsx)(`circle`,{cx:`22`,cy:`11`,r:`4`}),(0,F.jsx)(`circle`,{cx:`16`,cy:`23`,r:`4`})]})}var it=()=>(0,F.jsx)(`svg`,{viewBox:`0 0 20 20`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`m4.5 10.5 3.5 3.5 7.5-8`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})});function at(){let[e,t]=(0,k.useState)(!1),[n,r]=(0,k.useState)(nt),i=(0,k.useRef)(null),a=(0,k.useRef)(null),o=()=>{e&&(t(!1),a.current?.focus())};return(0,k.useEffect)(()=>{let e=Array.from(document.querySelectorAll(`meta[name="theme-color"]`)),t=e.map(e=>e.content),n=i.current?getComputedStyle(i.current).backgroundColor:``;if(n)for(let t of e)t.content=n;return()=>e.forEach((e,n)=>e.content=t[n])},[n]),(0,F.jsx)(`header`,{className:`site-header has-menu`,ref:i,onKeyDown:e=>e.key===`Escape`&&o(),children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`a`,{className:`site-logo`,href:`#/`,children:[(0,F.jsx)(rt,{}),(0,F.jsx)(`span`,{children:`grooph`})]}),(0,F.jsxs)(`button`,{className:`site-menu-toggle`,type:`button`,ref:a,"aria-expanded":e,"aria-controls":`site-nav`,onClick:()=>t(!e),children:[(0,F.jsx)(`svg`,{viewBox:`0 0 20 20`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`M3.5 6h13M3.5 10h13M3.5 14h13`,fill:`none`,stroke:`currentColor`,strokeWidth:`1.8`,strokeLinecap:`round`})}),`Menu`]}),(0,F.jsx)(`nav`,{className:`site-nav land-nav${e?` is-open`:``}`,id:`site-nav`,"aria-label":`grooph`,onClick:()=>t(!1),children:(0,F.jsxs)(`ul`,{children:[(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`#/templates`,children:`Templates`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:G,children:`Docs`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}field-guide/`,children:`Field guide`})}),(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{href:W,rel:`noopener`,children:[`Source`,(0,F.jsx)(`svg`,{viewBox:`0 0 20 20`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`M11.5 3.5h5v5M16.5 3.5l-7 7M14.5 12v3.5a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1H8`,fill:`none`,stroke:`currentColor`,strokeWidth:`1.8`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,F.jsx)(`span`,{className:`sr-only`,children:` (GitHub)`})]})})]})}),(0,F.jsx)(ot,{theme:n,onTheme:r})]})})}function ot({theme:e,onTheme:t}){let[n,r]=(0,k.useState)(!1),i=(0,k.useRef)(null),a=(0,k.useRef)(null),o=(0,k.useRef)([]),s=K.findIndex(t=>t.id===e);(0,k.useEffect)(()=>{if(!n)return;o.current[s]?.focus();let e=e=>{i.current?.contains(e.target)||r(!1)};return document.addEventListener(`pointerdown`,e),()=>document.removeEventListener(`pointerdown`,e)},[n,s]);let c=()=>{r(!1),a.current?.focus()},l=e=>{e===K[0].id?delete document.documentElement.dataset.theme:document.documentElement.dataset.theme=e;try{localStorage.setItem(tt,e)}catch{}let n=new URL(location.href);n.searchParams.has(`theme`)&&(n.searchParams.delete(`theme`),history.replaceState(history.state,``,n)),t(e),c()};return(0,F.jsxs)(`div`,{className:`site-theme`,ref:i,children:[(0,F.jsxs)(`button`,{className:`site-theme-toggle`,type:`button`,ref:a,"aria-label":`Theme: ${K[s].label}`,"aria-haspopup":`menu`,"aria-expanded":n,"aria-controls":`site-theme-list`,onClick:()=>r(!n),onKeyDown:e=>{(e.key===`ArrowDown`||e.key===`ArrowUp`)&&(e.preventDefault(),r(!0))},children:[(0,F.jsx)(`span`,{className:`site-theme-dot`,"aria-hidden":`true`}),(0,F.jsx)(`span`,{className:`site-theme-label`,children:`Theme`})]}),(0,F.jsxs)(`ul`,{className:`site-theme-list`,id:`site-theme-list`,role:`menu`,"aria-label":`Theme`,hidden:!n,onKeyDown:e=>{let t=o.current.indexOf(document.activeElement),n=e.key===`ArrowDown`?(t+1)%q:e.key===`ArrowUp`?(t-1+q)%q:e.key===`Home`?0:e.key===`End`?q-1:-1;n>=0?(e.preventDefault(),o.current[n]?.focus()):e.key===`Escape`?(e.stopPropagation(),c()):e.key===`Tab`&&r(!1)},children:[K.map((t,n)=>(0,F.jsx)(`li`,{role:`none`,children:(0,F.jsxs)(`button`,{type:`button`,role:`menuitemradio`,"aria-checked":t.id===e,tabIndex:-1,ref:e=>void(o.current[n]=e),onClick:()=>l(t.id),children:[(0,F.jsx)(`span`,{className:`site-theme-dot`,style:{"--dot":t.dot},"aria-hidden":`true`}),t.label,(0,F.jsx)(it,{})]})},t.id)),(0,F.jsx)(`li`,{role:`none`,children:(0,F.jsxs)(`button`,{type:`button`,role:`menuitem`,"aria-haspopup":`menu`,tabIndex:-1,"data-pictures":``,ref:e=>void(o.current[K.length]=e),onClick:e=>{e.currentTarget.dataset.pressed=``,r(!1)},children:[(0,F.jsx)(`span`,{className:`site-theme-dot`,style:{"--dot":`#0000`},"aria-hidden":`true`}),`Picture theme`]})})]})]})}var q=K.length+1,st=`/grooph/assets/site-icons.v1.svg`,ct=[{href:`https://ryanjosephkamp.github.io/`,name:`Ryan Kamp’s website`,title:`Website`,icon:`globe`},{href:`https://github.com/ryanjosephkamp/`,name:`Ryan Kamp on GitHub`,title:`GitHub`,icon:`github`},{href:`https://www.linkedin.com/in/rjk1999`,name:`Ryan Kamp on LinkedIn`,title:`LinkedIn`,icon:`linkedin`},{href:`https://x.com/ryanjosephkamp`,name:`Ryan Kamp on X`,title:`X`,icon:`x`},{href:`https://m.youtube.com/@RyanJosephKamp`,name:`Ryan Kamp on YouTube`,title:`YouTube`,icon:`youtube`}];function lt(){return(0,F.jsx)(`footer`,{className:`site-footer land-foot`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`div`,{children:[(0,F.jsxs)(`a`,{className:`site-logo`,href:`#/`,children:[(0,F.jsx)(rt,{}),(0,F.jsx)(`span`,{children:`grooph`})]}),(0,F.jsx)(`p`,{children:`Loop graphs for coding agents. Graphs live in this browser on this device. Nothing is sent anywhere.`})]}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h2`,{children:`Use it`}),(0,F.jsxs)(`ul`,{children:[(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`#/templates`,children:`Templates`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}quickstart/`,children:`Quickstart`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}field-guide/`,children:`Field guide`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:G,children:`Docs`})})]})]}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h2`,{children:`Help and contact`}),(0,F.jsxs)(`ul`,{children:[(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${W}/issues`,rel:`noopener`,children:`Report a bug or suggest a feature`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}community/`,children:`Community loops`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:W,rel:`noopener`,children:`Source on GitHub`})})]})]}),(0,F.jsxs)(`div`,{className:`site-credit`,children:[(0,F.jsxs)(`p`,{className:`site-made`,children:[`Made by `,(0,F.jsx)(`a`,{href:`https://ryanjosephkamp.github.io/`,children:`Ryan Kamp`})]}),(0,F.jsx)(`ul`,{className:`site-social`,"aria-label":`Ryan Kamp online`,children:ct.map(e=>(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:e.href,"aria-label":e.name,title:e.title,children:(0,F.jsx)(`svg`,{"aria-hidden":`true`,children:(0,F.jsx)(`use`,{href:`${st}#${e.icon}`})})})},e.href))}),(0,F.jsxs)(`a`,{className:`site-sponsor`,href:`https://github.com/sponsors/ryanjosephkamp`,children:[(0,F.jsx)(`svg`,{"aria-hidden":`true`,children:(0,F.jsx)(`use`,{href:`${st}#heart`})}),`Sponsor on GitHub`]})]}),(0,F.jsxs)(`p`,{className:`site-fine`,children:[`Every feature is free; sponsorship is optional and never unlocks anything. MIT license, © 2026 Ryan Kamp. This site uses no cookies, analytics or third-party requests. Fonts: Atkinson Hyperlegible Next and Mono, SIL Open Font License.`,` `,(0,F.jsx)(`a`,{href:`${W}#license-and-author`,rel:`noopener`,children:`Credits`})]})]})})}function ut({children:e}){let[t,n]=(0,k.useState)(`idle`),[r,i]=(0,k.useState)(null),[a,o]=(0,k.useState)(680),s=(0,k.useRef)(null);return(0,k.useEffect)(()=>{if(r===null)return;let e=e=>{let t=e.data;e.origin===location.origin&&e.source===s.current?.contentWindow&&t?.grooph===`embed-height`&&Number(t.height)>0&&o(Math.min(Number(t.height),4e3))};return addEventListener(`message`,e),()=>removeEventListener(`message`,e)},[r]),r===null?(0,F.jsxs)(F.Fragment,{children:[e,(0,F.jsxs)(`p`,{className:`land-play`,children:[(0,F.jsxs)(`button`,{type:`button`,className:`btn`,disabled:t===`loading`,onClick:async()=>{n(`loading`);try{let e=await fetch(`/grooph/demo/run.txt`);if(!e.ok)throw Error(String(e.status));i((await e.text()).trim()),n(`idle`)}catch{n(`failed`)}},children:[(0,F.jsx)(`span`,{"aria-hidden":`true`,children:`▶`}),` Watch a recorded run`]}),(0,F.jsx)(`span`,{className:`muted`,role:`status`,children:t===`loading`?`Fetching the run…`:t===`failed`?`The run could not be fetched. It needs a network the first time.`:``})]})]}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(`iframe`,{ref:s,className:`land-run-frame`,title:`A recorded run of the heterogeneous critic template, played step by step`,src:`/grooph/#/embed?d=${r}&play=1`,style:{height:a}}),(0,F.jsxs)(`figcaption`,{className:`muted`,children:[`A run Claude Code made on 20 September, replayed from its own notes. The critic fails the first round, the builder goes again, and the run halts at the human gate.`,` `,(0,F.jsx)(`button`,{type:`button`,className:`link-button`,onClick:()=>i(null),children:`Back to the picture`})]})]})}var J=`review-gate`,dt=`/grooph-design a builder and a critic that loop until the checkout tests pass, and ask me before merging`,ft,Y=()=>n(`front`,()=>r(()=>import(`./front-BRl7rl-u.js`),[])).then(e=>ft=e),pt=600;function mt(){let[e,t]=(0,k.useState)(ft),[n,r]=(0,k.useState)(!1);return(0,k.useEffect)(()=>{if(e)return;let n=!0,i=setTimeout(()=>n&&r(!0),pt);return Y().then(e=>n&&t(e),()=>n&&r(!0)),()=>{n=!1,clearTimeout(i)}},[]),e??(n?null:void 0)}var ht=[`No account`,`Works on a phone`,`Opens offline after a first visit`,`Graphs stay on your device`],X=`${G}field-guide/poster.svg`;function gt({device:e}){let[t,n]=(0,k.useState)(!0),r=mt();return r===void 0?(0,F.jsx)(`div`,{className:`loading`,children:`Opening…`}):(0,F.jsxs)(`div`,{className:`land`,children:[(0,F.jsx)(at,{}),(0,F.jsxs)(`main`,{children:[(0,F.jsx)(`section`,{className:`land-hero`,"aria-label":`What grooph is`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`div`,{className:`land-hero-title`,children:[(0,F.jsx)(`p`,{className:`land-chip`,children:`Free and open source`}),(0,F.jsxs)(`h1`,{className:`land-headline`,children:[`Loop graphs `,(0,F.jsx)(`span`,{children:`for coding agents.`})]})]}),(0,F.jsxs)(`div`,{className:`land-hero-text`,children:[(0,F.jsx)(`p`,{className:`land-lede`,children:`Draw who builds, who checks, where a person decides and when the work stops. grooph checks that every loop names a stop, then compiles the graph into a package a Claude Code session runs. Your harness runs it; grooph never does.`}),(0,F.jsxs)(`div`,{className:`land-cta`,children:[(0,F.jsx)(`a`,{className:`btn btn-primary`,href:V(`built-in`,J),children:`Open the template`}),(0,F.jsx)(`a`,{className:`btn`,href:`#/templates`,children:`See all twenty`})]}),(0,F.jsx)(`ul`,{className:`land-promise`,"aria-label":`About the app`,children:ht.map(e=>(0,F.jsxs)(`li`,{children:[(0,F.jsx)(it,{}),e]},e))})]}),r?(0,F.jsx)(`figure`,{className:`land-figure`,children:(0,F.jsxs)(ut,{children:[(0,F.jsx)(`div`,{className:`land-picture`,role:`img`,"aria-label":`The review gate template as a graph: a builder, a critic, a human merge approval and a stop, in one loop of at most four rounds`,dangerouslySetInnerHTML:{__html:r.HERO_SVG}}),(0,F.jsxs)(`figcaption`,{className:`muted`,children:[`The `,(0,F.jsx)(`a`,{href:V(`built-in`,J),children:`review gate`}),` template, drawn by grooph.`]})]})}):null]})}),(0,F.jsx)(`section`,{className:`land-section`,children:(0,F.jsx)(`div`,{className:`site-wrap`,children:(0,F.jsxs)(`ul`,{className:`land-claims`,"aria-label":`What grooph does`,children:[(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`strong`,{children:`Every loop names its stop.`}),` The validator refuses a loop without one and warns when a loop has no cap. Where a graph asks for it, it refuses a critic that shares the builder’s context, and it refuses a step marked irreversible with no human gate before it.`]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`strong`,{children:`The graph is the contract.`}),` The package tells the session to run it as drawn: named subagents, stops in order, a halt at every human gate. grooph does not enforce it while it runs; eighteen of twenty recorded runs pass the checks of it, and two say why they do not.`]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`strong`,{children:`Every run is asked for a record.`}),` Notes, rounds and why it stopped, in a folder a monitor reads. A halted run goes on when a person answers.`]})]})})}),(0,F.jsx)(`section`,{className:`land-section land-alt land-start`,"aria-labelledby":`land-start-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsx)(`h2`,{id:`land-start-title`,className:`land-h2`,children:`Two ways to start`}),(0,F.jsxs)(`div`,{className:`land-ways`,children:[(0,F.jsxs)(`div`,{className:`land-way`,children:[(0,F.jsx)(`h3`,{children:`Ask your agent`}),(0,F.jsxs)(`p`,{children:[`In Claude Code, with grooph `,(0,F.jsx)(`a`,{href:`${G}quickstart/`,children:`installed`}),`, describe the work. The session proposes one to three graphs, sends a link to compare them on your phone, and places the package you pick.`]}),(0,F.jsx)(vt,{text:dt})]}),(0,F.jsxs)(`div`,{className:`land-way`,children:[(0,F.jsx)(`h3`,{children:`Open a template`}),(0,F.jsx)(`p`,{children:`Twenty templates, each with a recorded run of its own. Open one, fill in its blanks, and export the package or the graph.`}),(0,F.jsxs)(`div`,{className:`land-way-actions`,children:[(0,F.jsx)(`a`,{className:`btn btn-primary`,href:V(`built-in`,J),children:`Open the review gate`}),(0,F.jsx)(`a`,{className:`btn`,href:`#/templates`,children:`Browse all`})]})]})]}),(0,F.jsx)(`div`,{className:`land-device`,children:e??(0,F.jsx)(_t,{})})]})}),(0,F.jsx)(`section`,{className:`land-section land-strip`,"aria-labelledby":`land-strip-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsx)(`h2`,{id:`land-strip-title`,className:`land-h2`,children:`Loop shapes`}),r?(0,F.jsx)(`ul`,{className:`land-strip-list`,"aria-label":`Templates`,children:r.TILES.map(e=>(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{className:`land-tile`,href:V(`built-in`,e.id),children:[(0,F.jsx)(Me,{svg:e.glyph,long:e.long,className:`land-tile-glyph${e.long?` is-wide`:``}`,decorative:!0}),(0,F.jsx)(`span`,{className:`land-tile-title`,children:e.title})]})},e.id))}):null,(0,F.jsxs)(`div`,{className:`land-poster`,children:[t?(0,F.jsx)(`a`,{href:X,"aria-label":`Open the poster of the twenty loop shapes`,children:(0,F.jsx)(`img`,{src:X,width:`1200`,height:`800`,loading:`lazy`,decoding:`async`,alt:`The poster: twenty loop shapes, each drawn with its name and when to reach for it`,onError:()=>n(!1)})}):null,(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h3`,{children:`Twenty shapes on one page`}),(0,F.jsxs)(`p`,{className:`land-guide-line`,children:[`All twenty, with what each one’s recorded run showed: `,(0,F.jsx)(`a`,{href:`${G}field-guide/`,children:`the field guide`}),`, and`,` `,(0,F.jsx)(`a`,{href:X,children:`a poster of the shapes`}),`.`]})]})]})]})}),(0,F.jsx)(`section`,{className:`land-section land-alt land-more`,"aria-labelledby":`land-more-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsx)(`h2`,{id:`land-more-title`,className:`land-h2`,children:`More than a drawing`}),(0,F.jsxs)(`ul`,{className:`land-more-list`,children:[(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`h3`,{children:`Put a graph on any page`}),(0,F.jsxs)(`p`,{children:[`One line of HTML shows a live graph a reader can pan, zoom and tap, or a recorded run that plays. `,(0,F.jsx)(`a`,{href:`${G}exports/`,children:`How to embed`}),`.`]})]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`h3`,{children:`See what is running`}),(0,F.jsxs)(`p`,{children:[`A hook records when each session and subagent starts and stops, and nothing they say. A screen shows it live.`,` `,(0,F.jsx)(`a`,{href:`${G}subagents/`,children:`How it works`}),`.`]})]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`h3`,{children:`Map work across sessions`}),(0,F.jsxs)(`p`,{children:[`Sessions, the people they work with, and what carries work between them, drawn and checked.`,` `,(0,F.jsx)(`a`,{href:`${G}operation-map/`,children:`Operation maps`}),`.`]})]})]})]})}),(0,F.jsx)(`section`,{className:`land-section land-honest`,"aria-labelledby":`land-honest-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`h2`,{id:`land-honest-title`,className:`land-h2`,children:[`What is shown, `,(0,F.jsx)(`mark`,{children:`and what is not`})]}),(0,F.jsxs)(`p`,{children:[`In twenty recorded runs a session stopped where its graph said, at a passed bar or a human gate, and left a record; eighteen of the twenty pass the project’s checks. No round cap or budget is on record as firing. In a paired comparison on four small tasks the package showed no quality advantage over a prompt derived from it. grooph runs no agent, calls no model and needs no hosted service.`,` `,(0,F.jsx)(`a`,{href:`${G}claims/`,children:`Every claim and its evidence`}),`.`]})]})})]}),(0,F.jsx)(lt,{})]})}function _t(){return(0,F.jsx)(`p`,{className:`land-device-line`,children:(0,F.jsx)(`a`,{className:`btn`,href:`#/`,children:`Your graphs`})})}function vt({text:e}){let[t,n]=(0,k.useState)(null);return(0,F.jsxs)(`div`,{className:`copy-line`,children:[(0,F.jsx)(`code`,{className:`copy-line-text`,children:e}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-small`,"aria-label":`Copy the line for Claude Code`,onClick:async()=>n(await De(e)?`Copied. Paste it into Claude Code.`:`Could not copy. Select the line and copy it.`),children:`Copy`}),(0,F.jsx)(`span`,{className:`copy-line-said muted`,role:`status`,children:t})]})}function yt({className:e=``}){let t=ve();if(!t)return null;let n=t.result===`granted`;return(0,F.jsxs)(`div`,{className:`persist-notice ${n?`is-granted`:`is-denied`} ${e}`,role:`status`,children:[(0,F.jsx)(`p`,{children:n?(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(`strong`,{children:`Storage kept.`}),` This browser agreed not to clear grooph’s data to free space.`]}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(`strong`,{children:`Storage not guaranteed.`}),` This browser may clear grooph’s data when space runs low. Keep backups: Export, then Download graph.`]})}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:ge,children:`Got it`})]})}function bt({toast:e,onDone:t}){return(0,k.useEffect)(()=>{if(!e)return;let n=window.setTimeout(t,6e3);return()=>window.clearTimeout(n)},[e,t]),e?(0,F.jsxs)(`div`,{className:`toast`,role:`status`,children:[(0,F.jsx)(`span`,{children:e.text}),e.undo?(0,F.jsx)(`button`,{type:`button`,className:`toast-action`,onClick:()=>{e.undo(),t()},children:`Undo`}):null]},e.id):null}var xt=e=>{let t=Date.now()-e;return t<6e4?`just now`:t<36e5?`${Math.floor(t/6e4)} min ago`:t<864e5?`${Math.floor(t/36e5)} h ago`:new Date(e).toLocaleDateString()},St=()=>n(`Import`,()=>r(()=>import(`./Import-YEKofx4_.js`),__vite__mapDeps([3,4,1,5,6]))),Ct=e=>e?.scrollIntoView({block:`nearest`});function wt({runs:e}){return(0,F.jsx)(`ul`,{className:`run-rows`,"aria-label":`Runs`,children:e.map(e=>{let t=c(e.bundle.notes,e.bundle.working);return(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{className:`run-row`,href:re(e.key),children:[(0,F.jsxs)(`span`,{className:`run-row-name`,children:[`Run `,(0,F.jsx)(`span`,{className:`mono`,children:e.run})]}),(0,F.jsx)(`span`,{className:`run-row-meta`,children:s(t)})]})},e.key)})})}function Tt({open:e}){let[t,n]=(0,k.useState)(null),[r,i]=(0,k.useState)([]),[a,o]=(0,k.useState)(!0),[s,c]=(0,k.useState)(null),[l,u]=(0,k.useState)(null),[d,f]=(0,k.useState)(null),[m,g]=(0,k.useState)(null),[_,v]=(0,k.useState)(null),y=(0,k.useRef)(null),[b,x]=(0,k.useState)(null),S=(0,k.useCallback)(async()=>{n(await ae()),i(await ce()),o((await O()).persistent)},[]);(0,k.useEffect)(()=>void S(),[S]);let C={open:e,route:h,problem:c,offer:v,close:()=>x(null)},w=(e,t)=>void St().then(t,()=>c({name:e,issues:[],what:`The part of grooph that opens it could not be fetched. It needs a connection the first time: try again when you have one.`})),T=e=>{e&&w(e.name,async t=>t.importText(await e.text(),e,C))};(0,k.useEffect)(()=>{let e=e=>{let t=e.clipboardData?.getData(`text/plain`);t&&e.target instanceof Element&&!e.target.closest(`input, textarea, select`)&&St().then(e=>e.openPasted(t,C,!0),()=>void 0)};return window.addEventListener(`paste`,e),()=>window.removeEventListener(`paste`,e)});let E=async(e,t)=>{let n=await Ke(e,{replace:t});if(`exists`in n){v(e=>e&&{...e,exists:n.exists});return}v(null),location.hash=V(`yours`,n.saved.id)},D=(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`div`,{className:`library-actions`,children:[(0,F.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-large`,onClick:async()=>{e((await le()).key,!0)},children:`New graph`}),(0,F.jsx)(`a`,{className:`btn btn-large`,href:`#/templates`,children:`Templates`}),(0,F.jsxs)(`label`,{className:`btn btn-large file-btn`,children:[`Import .grooph.json`,(0,F.jsx)(`input`,{ref:y,type:`file`,accept:`.json,application/json`,onChange:e=>{T(e.target.files?.[0]),e.target.value=``}})]}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-large`,onClick:()=>w(`what you paste`,e=>x(t=>t?null:e.PasteBox)),children:`Paste a document`})]}),b?(0,F.jsx)(b,{host:C}):null,a?null:(0,F.jsx)(`p`,{className:`notice`,role:`status`,children:`This browser is not letting grooph store anything, so graphs last until the tab closes. Download them from Export to keep them.`}),(0,F.jsx)(yt,{}),_?(0,F.jsxs)(`div`,{className:`offer`,role:`alert`,ref:Ct,children:[(0,F.jsxs)(`p`,{children:[(0,F.jsxs)(`strong`,{children:[_.name,` is a template:`]}),` `,_.doc.template.title,_.doc.template.kind===`fragment`?` (a fragment)`:``,`.`,` `,_.refusal?`It carries errors, so it cannot go into Yours; grooph template add refuses it too. Open it as a graph to fix it.`:`Add it to Yours to use it from Templates.`]}),_.refusal?(0,F.jsx)(`pre`,{className:`issue-lines`,children:_.refusal.issues.map(p).join(`
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/compile-BAvi-rd0.js","assets/share-BzIzB4EY.js","assets/groups-CjEPiwfv.js","assets/Import-ByMI7Uz9.js","assets/index-CeaKwKuU.js","assets/templates-CoNTzuuz.js","assets/runs-DcjRi7S6.js","assets/EmbedApp-390Z2d4x.js","assets/EmbedApp-CWb_HGpW.css","assets/screens-aIjMSzZg.js","assets/screens-DWbqIw6l.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{a as e,c as t,n,r,s as i,t as a}from"./index-CeaKwKuU.js";import{D as o,F as s,I as c,Rt as l,Tt as u,b as d,cn as f,fn as p,i as m,n as h,r as g,rn as _,sn as v,tt as y}from"./share-BzIzB4EY.js";import{d as b,i as x,l as S,m as C,n as w,o as T,p as E,r as D,t as ee,u as te}from"./templates-CoNTzuuz.js";import{A as ne,S as re,c as ie,f as ae,j as O,l as oe,m as se,r as ce,s as le,u as ue}from"./runs-DcjRi7S6.js";var k=t(e(),1),de=String.raw`^(?!#\/(?:run\?live$|live$|run\/[^?]+$|templates$|embed(?:\?|$)|templates\/(?:built-in|yours|plan)\/[^/?]+(?:\/use)?$|g\/[^/?]+(?:\?new)?$|open\?))`,fe=String.raw`^#\/templates(?:$|\/built-in\/[^/?]+(?:\/use)?$)`,pe=`grooph.persistence`;function me(){try{let e=localStorage.getItem(pe);return e?JSON.parse(e):null}catch{return null}}function A(e){try{localStorage.setItem(pe,JSON.stringify(e))}catch{}j=e;for(let e of N)e()}var j=me(),M=!1,N=new Set;async function he(){if(!(j!==null||M)){M=!0;try{let e=typeof navigator<`u`?navigator.storage:void 0;if(!e||typeof e.persist!=`function`){A({result:`unsupported`,seen:!1});return}A({result:typeof e.persisted==`function`&&await e.persisted()||await e.persist()?`granted`:`denied`,seen:!1})}catch{A({result:`denied`,seen:!1})}finally{M=!1}}}function ge(){j&&A({...j,seen:!0})}var _e=e=>(N.add(e),()=>N.delete(e));function ve(){let e=(0,k.useSyncExternalStore)(_e,()=>j);return e&&!e.seen?e:null}ne(()=>void he());var P;function ye(){return n(`compile`,()=>r(()=>import(`./compile-BAvi-rd0.js`),__vite__mapDeps([0,1,2]))).then(e=>P=e)}var be=()=>P!==void 0;function xe(e){let t=e.target?.harness,n=t!==void 0&&_.includes(t)?t:`claude-code`,r=f(e);if(!r.doc)return{ok:!1,target:t??`(none)`,reason:`schema`,issues:r.issues};let i=y(r.doc,{forExport:!0});if(i.some(e=>e.severity===`error`))return{ok:!1,target:t??`(none)`,reason:`rules`,issues:i};if(!P)return;let a=P.keptFolder(r.doc.id);if(a!==void 0)return{ok:!1,target:n,reason:`id`,issues:[],said:a};let o=P.tryCompile(r.doc,n);return o.ok?{ok:!0,target:n,result:o.result}:{ok:!1,target:t??`(none)`,reason:`rules`,issues:o.issues}}function Se(e){let t={};for(let[n,r]of Object.entries(e))t[n]=g(r);return new Uint8Array(m(t,{level:6}))}var Ce=e=>v(e),we=e=>`${e.id||`graph`}.grooph.json`,Te=(e,t)=>`${e.id||`graph`}-${t}.zip`;function Ee(e,t,n){let r=URL.createObjectURL(new Blob([t],{type:n})),i=document.createElement(`a`);i.href=r,i.download=e,i.rel=`noopener`,document.body.append(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(r),1e4)}async function De(e){try{return await navigator.clipboard.writeText(e),!0}catch{let t=document.createElement(`textarea`);t.value=e,t.setAttribute(`readonly`,``),t.style.position=`fixed`,t.style.opacity=`0`,document.body.append(t),t.select();let n=document.execCommand(`copy`);return t.remove(),n}}var F=a(),Oe=300,ke=new WeakMap;function Ae(e){let t=ke.get(e);if(!t){let n=d(e);t={svg:n,long:Number(/viewBox="\S+ \S+ (\S+) \S+"/.exec(n)?.[1]??0)>Oe},ke.set(e,t)}return t}var je=e=>Ae(e).long;function I({doc:e,className:t,decorative:n=!1}){return(0,F.jsx)(Me,{...Ae(e),className:t,decorative:n})}function Me({svg:e,long:t,className:n,decorative:r=!1}){return(0,F.jsx)(`span`,{className:`glyph${n?` ${n}`:``}${t?` is-long`:``}`,"aria-hidden":r||void 0,dangerouslySetInnerHTML:{__html:e}})}var L={q:``,kind:[],cost:[],speed:[],rigor:[],tags:[],sort:`name`,open:!1},R={name:`Name`,cost:`Cost, low first`,speed:`Speed, fast first`,rigor:`Rigor, high first`},Ne=e=>e.kind.length+e.cost.length+e.speed.length+e.rigor.length+e.tags.length,Pe=e=>e.q.trim()===``&&Ne(e)===0&&e.sort===`name`,Fe=e=>e.toLowerCase().split(/\s+/).filter(e=>e!==``),Ie=e=>{let t=e.template;return[t.title,t.summary,t.whenToUse,...t.tags??[],e.id].join(`
|
|
3
|
+
`).toLowerCase()};function Le(e,t){let n=e.template;if(t.kind.length>0&&!t.kind.includes(n.kind)||t.cost.length>0&&!t.cost.includes(n.profile.cost)||t.speed.length>0&&!t.speed.includes(n.profile.speed)||t.rigor.length>0&&!t.rigor.includes(n.profile.rigor)||t.tags.length>0&&!t.tags.every(e=>(n.tags??[]).includes(e)))return!1;let r=Fe(t.q);if(r.length===0)return!0;let i=Ie(e);return r.every(e=>i.includes(e))}function Re(e,t,n){let r=e.template,i=t.template,a=r.title.localeCompare(i.title);if(n===`name`)return a;let o=e=>w[n][e.profile[n]],s=n===`cost`?1:-1;return(o(r)-o(i))*s||a}function ze(e,t){return e.filter(e=>Le(e,t)).sort((e,n)=>Re(e,n,t.sort))}function Be(e){let t=new Map;for(let n of e)for(let e of n.template?.tags??[])t.set(e,(t.get(e)??0)+1);return[...t].sort((e,t)=>t[1]-e[1]||e[0].localeCompare(t[0])).map(([e])=>e)}var z=(e,t)=>e.includes(t)?e.filter(e=>e!==t):[...e,t],B=`grooph.templates.browse`,Ve=e=>Array.isArray(e)&&e.every(e=>typeof e==`string`);function He(){try{let e=localStorage.getItem(B);if(e===null)return L;let t=JSON.parse(e),n=(e,t)=>Ve(e)?e.filter(e=>t===void 0||t.includes(e)):[];return{q:typeof t.q==`string`?t.q:``,kind:n(t.kind,[`graph`,`fragment`]),cost:n(t.cost,[`low`,`medium`,`high`]),speed:n(t.speed,[`fast`,`medium`,`slow`]),rigor:n(t.rigor,[`light`,`standard`,`high`]),tags:n(t.tags),sort:typeof t.sort==`string`&&t.sort in R?t.sort:`name`,open:t.open===!0}}catch{return L}}function Ue(e){try{Pe(e)&&!e.open?localStorage.removeItem(B):localStorage.setItem(B,JSON.stringify(e))}catch{}}async function We(){let e=await O();return E((await e.templates.list()).map(e=>e.doc))}async function Ge(e){return(await(await O()).templates.get(e))?.doc}async function Ke(e,t={}){if(!e.template)throw Error(`"${e.id}" has no template block`);if(C(e))throw Error(`"${e.id}" carries errors; Yours keeps only templates that validate`);let n=await O(),r=await n.templates.get(e.id);if(r&&!t.replace)return{exists:r.doc};let i=r?Math.max(r.doc.version,e.version)+1:e.version,a={id:e.id,doc:{...structuredClone(e),version:i},savedAt:Date.now()};return await n.templates.put(a),{saved:a,replaced:r!==void 0}}async function qe(e){await(await O()).templates.delete(e)}var Je=e=>`${e.id}.grooph.json`,Ye=e=>v(e),V=(e,t,n=!1)=>`#/templates/${e}/${encodeURIComponent(t)}${n?`/use`:``}`,Xe=[];function Ze(){let[e,t]=(0,k.useState)(T);return(0,k.useEffect)(()=>{if(e!==void 0)return;let n=!0;return S().then(e=>n&&t(e),()=>n&&t(null)),()=>{n=!1}},[]),e}function Qe(){let[e,t]=(0,k.useState)(null),[n,r]=(0,k.useState)(He);(0,k.useEffect)(()=>Ue(n),[n]),(0,k.useEffect)(()=>{let e=!0;return We().then(n=>e&&t(n)),()=>{e=!1}},[]);let i=Ze(),a=i??Xe,o=(0,k.useMemo)(()=>[...e??[],...a],[e,a]),s=(0,k.useMemo)(()=>Be(o),[o]),c=(0,k.useMemo)(()=>ze(e??[],n),[e,n]),l=(0,k.useMemo)(()=>ze(a,n),[a,n]),u=c.length+l.length,[d,f]=(0,k.useState)(b),p=(0,k.useRef)(null),m=()=>{f(`asking`),te().then(f,()=>f(null)).then(()=>setTimeout(()=>p.current?.focus()))},h=o.length,g=Ne(n),[_,v]=(0,k.useState)(!1),y=_?s:s.filter((e,t)=>t<$e||n.tags.includes(e)),S=(e,t)=>r(n=>({...n,[e]:t}));return i===void 0?(0,F.jsx)(`div`,{className:`loading`,children:`Opening…`}):(0,F.jsxs)(`div`,{className:`library templates`,children:[(0,F.jsxs)(`header`,{className:`screen-head`,children:[(0,F.jsx)(`a`,{className:`icon-btn`,href:`#/`,"aria-label":`All graphs`,children:(0,F.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`M15 5 8 12l7 7`})})}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h1`,{children:`Templates`}),(0,F.jsx)(`p`,{className:`muted`,children:`Start a graph from one, or insert one into a graph you have open.`})]})]}),(0,F.jsxs)(`div`,{className:`browse`,role:`search`,children:[(0,F.jsxs)(`div`,{className:`browse-row`,children:[(0,F.jsx)(`input`,{type:`search`,className:`input browse-q`,placeholder:`Search templates`,"aria-label":`Search templates`,value:n.q,onChange:e=>S(`q`,e.target.value),autoComplete:`off`,enterKeyHint:`search`}),(0,F.jsxs)(`button`,{type:`button`,className:`btn browse-toggle${g>0?` is-on`:``}`,"aria-expanded":n.open,"aria-controls":`browse-filters`,onClick:()=>S(`open`,!n.open),children:[`Filters`,g>0?(0,F.jsx)(`span`,{className:`browse-count`,children:g}):null]})]}),(0,F.jsxs)(`div`,{className:`browse-row browse-meta`,children:[(0,F.jsx)(`span`,{className:`muted browse-shown`,role:`status`,"aria-live":`polite`,children:u===h?`${h} templates`:`${u} of ${h}`}),(0,F.jsxs)(`label`,{className:`browse-sort`,children:[(0,F.jsx)(`span`,{className:`muted`,children:`Sort`}),(0,F.jsx)(`select`,{className:`input`,"aria-label":`Sort by`,value:n.sort,onChange:e=>S(`sort`,e.target.value),children:Object.keys(R).map(e=>(0,F.jsx)(`option`,{value:e,children:R[e]},e))})]}),Pe(n)?null:(0,F.jsx)(`button`,{type:`button`,className:`link browse-clear`,onClick:()=>r({...L,open:n.open}),children:`Clear`})]}),n.open?(0,F.jsxs)(`div`,{className:`browse-filters`,id:`browse-filters`,children:[(0,F.jsx)(H,{label:`Kind`,options:[`graph`,`fragment`],text:e=>e===`graph`?`Whole graph`:`Fragment`,on:n.kind,onToggle:e=>S(`kind`,z(n.kind,e))}),[`cost`,`speed`,`rigor`].map(e=>(0,F.jsx)(H,{label:e[0].toUpperCase()+e.slice(1),options:D[e],text:e=>e[0].toUpperCase()+e.slice(1),title:t=>x[e][t],level:t=>w[e][t],on:n[e],onToggle:t=>S(e,z(n[e],t))},e)),s.length>0?(0,F.jsx)(H,{label:`Tags`,options:y,text:e=>e,on:n.tags,onToggle:e=>S(`tags`,z(n.tags,e)),more:s.length>$e?(0,F.jsx)(`button`,{type:`button`,className:`chip chip-small chip-more`,"aria-expanded":_,onClick:()=>v(e=>!e),children:_?`Fewer tags`:`All ${s.length} tags`}):null}):null]}):null]}),e&&e.length>0&&c.length>0?(0,F.jsxs)(`section`,{"aria-labelledby":`yours-title`,children:[(0,F.jsx)(`h2`,{className:`list-title`,id:`yours-title`,children:`Yours`}),(0,F.jsx)(U,{source:`yours`,docs:c})]}):null,l.length>0?(0,F.jsxs)(`section`,{"aria-labelledby":`builtin-title`,children:[(0,F.jsx)(`h2`,{className:`list-title`,id:`builtin-title`,children:`Built-in`}),(0,F.jsx)(U,{source:`built-in`,docs:l})]}):null,i===null?(0,F.jsx)(`p`,{className:`muted templates-hint`,role:`status`,children:`The built-in templates could not be fetched. They need a connection the first time. Yours are listed.`}):null,u===0?(0,F.jsxs)(`p`,{className:`muted templates-hint browse-none`,role:`status`,children:[`No template matches.`,` `,(0,F.jsx)(`button`,{type:`button`,className:`link`,onClick:()=>r({...L,open:n.open}),children:`Clear the search and filters`})]}):null,(0,F.jsxs)(`section`,{"aria-labelledby":`plans-title`,children:[(0,F.jsx)(`h2`,{className:`list-title`,id:`plans-title`,children:`Plans`}),(0,F.jsx)(`p`,{className:`muted templates-hint`,children:ee}),(0,F.jsx)(`p`,{className:`muted templates-hint`,role:`status`,tabIndex:-1,ref:p,children:d&&d!==`asking`?`${d.length} plans, listed whole: the search and filters above are for the templates.`:(0,F.jsxs)(F.Fragment,{children:[d===null?`The plans could not be fetched. They need a connection the first time. `:null,(0,F.jsx)(`button`,{type:`button`,className:`btn`,disabled:d===`asking`,onClick:m,children:d===null?`Try again`:d===`asking`?`Fetching the plans…`:`Show the plans`})]})}),d&&d!==`asking`?(0,F.jsx)(U,{source:`plan`,docs:d}):null]}),e&&e.length===0?(0,F.jsxs)(`p`,{className:`muted templates-hint`,children:[(0,F.jsx)(`strong`,{children:`Yours`}),` is empty. Save a graph, or some of its nodes, as a template from the Graph panel of the editor, or import a template file from the graph list.`]}):null]})}var $e=8;function H({label:e,options:t,text:n,title:r,level:i,on:a,onToggle:o,more:s}){return(0,F.jsxs)(`div`,{className:`browse-group`,role:`group`,"aria-label":e,children:[(0,F.jsx)(`span`,{className:`browse-group-label`,children:e}),(0,F.jsxs)(`div`,{className:`chips browse-chips`,children:[t.map(e=>(0,F.jsxs)(`button`,{type:`button`,className:`chip chip-small${a.includes(e)?` chip-on`:``}`,"aria-pressed":a.includes(e),"aria-label":r?r(e):void 0,onClick:()=>o(e),children:[i?(0,F.jsxs)(`span`,{className:`meter`,"aria-hidden":`true`,"data-level":i(e),children:[(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{})]}):null,n(e)]},e)),s]})]})}function U({source:e,docs:t}){return(0,F.jsx)(`ul`,{className:`template-list`,"aria-label":e===`yours`?`Your templates`:e===`plan`?`Plan templates`:`Built-in templates`,children:t.map(t=>{let n=t.template;return(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{className:`template-row${je(t)?` has-long-glyph`:``}`,href:V(e,t.id),"data-template":t.id,children:[(0,F.jsx)(I,{doc:t,className:`template-glyph`,decorative:!0}),(0,F.jsxs)(`span`,{className:`template-text`,children:[(0,F.jsxs)(`span`,{className:`template-title`,children:[n.title,n.kind===`fragment`?(0,F.jsx)(`span`,{className:`badge badge-quiet`,children:`fragment`}):null,e===`plan`?(0,F.jsx)(`span`,{className:`badge badge-quiet`,children:`plan`}):null]}),(0,F.jsxs)(`span`,{className:`template-when`,children:[(0,F.jsx)(`span`,{className:`template-label`,children:`Use when`}),` `,n.whenToUse]}),e===`plan`?null:(0,F.jsx)(et,{profile:n.profile})]})]})},t.id)})})}function et({profile:e}){return(0,F.jsx)(`ul`,{className:`template-meters`,"aria-label":`Profile`,children:[`cost`,`speed`,`rigor`].map(t=>(0,F.jsxs)(`li`,{className:`template-meter`,"aria-label":x[t][e[t]],title:x[t][e[t]],children:[(0,F.jsxs)(`span`,{className:`meter`,"aria-hidden":`true`,"data-level":w[t][e[t]],children:[(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{}),(0,F.jsx)(`i`,{})]}),(0,F.jsx)(`span`,{className:`template-meter-word`,"aria-hidden":`true`,children:t})]},t))})}var W=`https://github.com/ryanjosephkamp/grooph`,G=`/grooph/docs/`,K=[{id:`grooph`,label:`Grooph`,dot:`oklch(0.85 0.14 165)`},{id:`meteor`,label:`Meteor`,dot:`oklch(0.9 0.2 124)`}],tt=`groophTheme`,nt=()=>K.find(e=>e.id===document.documentElement.dataset.theme)?.id??K[0].id;function rt(){return(0,F.jsxs)(`svg`,{viewBox:`0 0 32 32`,"aria-hidden":`true`,children:[(0,F.jsx)(`rect`,{width:`32`,height:`32`,rx:`8.5`}),(0,F.jsx)(`path`,{d:`M13.5 12.5 19 21M18.5 12.5 13 21M14 11h4`}),(0,F.jsx)(`circle`,{cx:`10`,cy:`11`,r:`4`}),(0,F.jsx)(`circle`,{cx:`22`,cy:`11`,r:`4`}),(0,F.jsx)(`circle`,{cx:`16`,cy:`23`,r:`4`})]})}var it=()=>(0,F.jsx)(`svg`,{viewBox:`0 0 20 20`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`m4.5 10.5 3.5 3.5 7.5-8`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})});function at(){let[e,t]=(0,k.useState)(!1),[n,r]=(0,k.useState)(nt),i=(0,k.useRef)(null),a=(0,k.useRef)(null),o=()=>{e&&(t(!1),a.current?.focus())};return(0,k.useEffect)(()=>{let e=Array.from(document.querySelectorAll(`meta[name="theme-color"]`)),t=e.map(e=>e.content),n=i.current?getComputedStyle(i.current).backgroundColor:``;if(n)for(let t of e)t.content=n;return()=>e.forEach((e,n)=>e.content=t[n])},[n]),(0,F.jsx)(`header`,{className:`site-header has-menu`,ref:i,onKeyDown:e=>e.key===`Escape`&&o(),children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`a`,{className:`site-logo`,href:`#/`,children:[(0,F.jsx)(rt,{}),(0,F.jsx)(`span`,{children:`grooph`})]}),(0,F.jsxs)(`button`,{className:`site-menu-toggle`,type:`button`,ref:a,"aria-expanded":e,"aria-controls":`site-nav`,onClick:()=>t(!e),children:[(0,F.jsx)(`svg`,{viewBox:`0 0 20 20`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`M3.5 6h13M3.5 10h13M3.5 14h13`,fill:`none`,stroke:`currentColor`,strokeWidth:`1.8`,strokeLinecap:`round`})}),`Menu`]}),(0,F.jsx)(`nav`,{className:`site-nav land-nav${e?` is-open`:``}`,id:`site-nav`,"aria-label":`grooph`,onClick:()=>t(!1),children:(0,F.jsxs)(`ul`,{children:[(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`#/templates`,children:`Templates`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:G,children:`Docs`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}field-guide/`,children:`Field guide`})}),(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{href:W,rel:`noopener`,children:[`Source`,(0,F.jsx)(`svg`,{viewBox:`0 0 20 20`,"aria-hidden":`true`,children:(0,F.jsx)(`path`,{d:`M11.5 3.5h5v5M16.5 3.5l-7 7M14.5 12v3.5a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1H8`,fill:`none`,stroke:`currentColor`,strokeWidth:`1.8`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,F.jsx)(`span`,{className:`sr-only`,children:` (GitHub)`})]})})]})}),(0,F.jsx)(ot,{theme:n,onTheme:r})]})})}function ot({theme:e,onTheme:t}){let[n,r]=(0,k.useState)(!1),i=(0,k.useRef)(null),a=(0,k.useRef)(null),o=(0,k.useRef)([]),s=K.findIndex(t=>t.id===e);(0,k.useEffect)(()=>{if(!n)return;o.current[s]?.focus();let e=e=>{i.current?.contains(e.target)||r(!1)};return document.addEventListener(`pointerdown`,e),()=>document.removeEventListener(`pointerdown`,e)},[n,s]);let c=()=>{r(!1),a.current?.focus()},l=e=>{e===K[0].id?delete document.documentElement.dataset.theme:document.documentElement.dataset.theme=e;try{localStorage.setItem(tt,e)}catch{}let n=new URL(location.href);n.searchParams.has(`theme`)&&(n.searchParams.delete(`theme`),history.replaceState(history.state,``,n)),t(e),c()};return(0,F.jsxs)(`div`,{className:`site-theme`,ref:i,children:[(0,F.jsxs)(`button`,{className:`site-theme-toggle`,type:`button`,ref:a,"aria-label":`Theme: ${K[s].label}`,"aria-haspopup":`menu`,"aria-expanded":n,"aria-controls":`site-theme-list`,onClick:()=>r(!n),onKeyDown:e=>{(e.key===`ArrowDown`||e.key===`ArrowUp`)&&(e.preventDefault(),r(!0))},children:[(0,F.jsx)(`span`,{className:`site-theme-dot`,"aria-hidden":`true`}),(0,F.jsx)(`span`,{className:`site-theme-label`,children:`Theme`})]}),(0,F.jsxs)(`ul`,{className:`site-theme-list`,id:`site-theme-list`,role:`menu`,"aria-label":`Theme`,hidden:!n,onKeyDown:e=>{let t=o.current.indexOf(document.activeElement),n=e.key===`ArrowDown`?(t+1)%q:e.key===`ArrowUp`?(t-1+q)%q:e.key===`Home`?0:e.key===`End`?q-1:-1;n>=0?(e.preventDefault(),o.current[n]?.focus()):e.key===`Escape`?(e.stopPropagation(),c()):e.key===`Tab`&&r(!1)},children:[K.map((t,n)=>(0,F.jsx)(`li`,{role:`none`,children:(0,F.jsxs)(`button`,{type:`button`,role:`menuitemradio`,"aria-checked":t.id===e,tabIndex:-1,ref:e=>void(o.current[n]=e),onClick:()=>l(t.id),children:[(0,F.jsx)(`span`,{className:`site-theme-dot`,style:{"--dot":t.dot},"aria-hidden":`true`}),t.label,(0,F.jsx)(it,{})]})},t.id)),(0,F.jsx)(`li`,{role:`none`,children:(0,F.jsxs)(`button`,{type:`button`,role:`menuitem`,"aria-haspopup":`menu`,tabIndex:-1,"data-pictures":``,ref:e=>void(o.current[K.length]=e),onClick:e=>{e.currentTarget.dataset.pressed=``,r(!1)},children:[(0,F.jsx)(`span`,{className:`site-theme-dot`,style:{"--dot":`#0000`},"aria-hidden":`true`}),`Picture theme`]})})]})]})}var q=K.length+1,st=`/grooph/assets/site-icons.v1.svg`,ct=[{href:`https://ryanjosephkamp.github.io/`,name:`Ryan Kamp’s website`,title:`Website`,icon:`globe`},{href:`https://github.com/ryanjosephkamp/`,name:`Ryan Kamp on GitHub`,title:`GitHub`,icon:`github`},{href:`https://www.linkedin.com/in/rjk1999`,name:`Ryan Kamp on LinkedIn`,title:`LinkedIn`,icon:`linkedin`},{href:`https://x.com/ryanjosephkamp`,name:`Ryan Kamp on X`,title:`X`,icon:`x`},{href:`https://m.youtube.com/@RyanJosephKamp`,name:`Ryan Kamp on YouTube`,title:`YouTube`,icon:`youtube`}];function lt(){return(0,F.jsx)(`footer`,{className:`site-footer land-foot`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`div`,{children:[(0,F.jsxs)(`a`,{className:`site-logo`,href:`#/`,children:[(0,F.jsx)(rt,{}),(0,F.jsx)(`span`,{children:`grooph`})]}),(0,F.jsx)(`p`,{children:`Loop graphs for coding agents. Graphs live in this browser on this device. Nothing is sent anywhere.`})]}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h2`,{children:`Use it`}),(0,F.jsxs)(`ul`,{children:[(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`#/templates`,children:`Templates`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}quickstart/`,children:`Quickstart`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}field-guide/`,children:`Field guide`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:G,children:`Docs`})})]})]}),(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h2`,{children:`Help and contact`}),(0,F.jsxs)(`ul`,{children:[(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${W}/issues`,rel:`noopener`,children:`Report a bug or suggest a feature`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:`${G}community/`,children:`Community loops`})}),(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:W,rel:`noopener`,children:`Source on GitHub`})})]})]}),(0,F.jsxs)(`div`,{className:`site-credit`,children:[(0,F.jsxs)(`p`,{className:`site-made`,children:[`Made by `,(0,F.jsx)(`a`,{href:`https://ryanjosephkamp.github.io/`,children:`Ryan Kamp`})]}),(0,F.jsx)(`ul`,{className:`site-social`,"aria-label":`Ryan Kamp online`,children:ct.map(e=>(0,F.jsx)(`li`,{children:(0,F.jsx)(`a`,{href:e.href,"aria-label":e.name,title:e.title,children:(0,F.jsx)(`svg`,{"aria-hidden":`true`,children:(0,F.jsx)(`use`,{href:`${st}#${e.icon}`})})})},e.href))}),(0,F.jsxs)(`a`,{className:`site-sponsor`,href:`https://github.com/sponsors/ryanjosephkamp`,children:[(0,F.jsx)(`svg`,{"aria-hidden":`true`,children:(0,F.jsx)(`use`,{href:`${st}#heart`})}),`Sponsor on GitHub`]})]}),(0,F.jsxs)(`p`,{className:`site-fine`,children:[`Every feature is free; sponsorship is optional and never unlocks anything. MIT license, © 2026 Ryan Kamp. This site uses no cookies, analytics or third-party requests. Fonts: Atkinson Hyperlegible Next and Mono, SIL Open Font License.`,` `,(0,F.jsx)(`a`,{href:`${W}#license-and-author`,rel:`noopener`,children:`Credits`})]})]})})}function ut({children:e}){let[t,n]=(0,k.useState)(`idle`),[r,i]=(0,k.useState)(null),[a,o]=(0,k.useState)(680),s=(0,k.useRef)(null);return(0,k.useEffect)(()=>{if(r===null)return;let e=e=>{let t=e.data;e.origin===location.origin&&e.source===s.current?.contentWindow&&t?.grooph===`embed-height`&&Number(t.height)>0&&o(Math.min(Number(t.height),4e3))};return addEventListener(`message`,e),()=>removeEventListener(`message`,e)},[r]),r===null?(0,F.jsxs)(F.Fragment,{children:[e,(0,F.jsxs)(`p`,{className:`land-play`,children:[(0,F.jsxs)(`button`,{type:`button`,className:`btn`,disabled:t===`loading`,onClick:async()=>{n(`loading`);try{let e=await fetch(`/grooph/demo/run.txt`);if(!e.ok)throw Error(String(e.status));i((await e.text()).trim()),n(`idle`)}catch{n(`failed`)}},children:[(0,F.jsx)(`span`,{"aria-hidden":`true`,children:`▶`}),` Watch a recorded run`]}),(0,F.jsx)(`span`,{className:`muted`,role:`status`,children:t===`loading`?`Fetching the run…`:t===`failed`?`The run could not be fetched. It needs a network the first time.`:``})]})]}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(`iframe`,{ref:s,className:`land-run-frame`,title:`A recorded run of the heterogeneous critic template, played step by step`,src:`/grooph/#/embed?d=${r}&play=1`,style:{height:a}}),(0,F.jsxs)(`figcaption`,{className:`muted`,children:[`A run Claude Code made on 20 September, replayed from its own notes. The critic fails the first round, the builder goes again, and the run halts at the human gate.`,` `,(0,F.jsx)(`button`,{type:`button`,className:`link-button`,onClick:()=>i(null),children:`Back to the picture`})]})]})}var J=`review-gate`,dt=`/grooph-design a builder and a critic that loop until the checkout tests pass, and ask me before merging`,ft,Y=()=>n(`front`,()=>r(()=>import(`./front-BRl7rl-u.js`),[])).then(e=>ft=e),pt=600;function mt(){let[e,t]=(0,k.useState)(ft),[n,r]=(0,k.useState)(!1);return(0,k.useEffect)(()=>{if(e)return;let n=!0,i=setTimeout(()=>n&&r(!0),pt);return Y().then(e=>n&&t(e),()=>n&&r(!0)),()=>{n=!1,clearTimeout(i)}},[]),e??(n?null:void 0)}var ht=[`No account`,`Built for a phone's screen`,`Opens offline after a first visit`,`Graphs stay on your device`],X=`${G}field-guide/poster.svg`;function gt({device:e}){let[t,n]=(0,k.useState)(!0),r=mt();return r===void 0?(0,F.jsx)(`div`,{className:`loading`,children:`Opening…`}):(0,F.jsxs)(`div`,{className:`land`,children:[(0,F.jsx)(at,{}),(0,F.jsxs)(`main`,{children:[(0,F.jsx)(`section`,{className:`land-hero`,"aria-label":`What grooph is`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`div`,{className:`land-hero-title`,children:[(0,F.jsx)(`p`,{className:`land-chip`,children:`Free and open source`}),(0,F.jsxs)(`h1`,{className:`land-headline`,children:[`Loop graphs `,(0,F.jsx)(`span`,{children:`for coding agents.`})]})]}),(0,F.jsxs)(`div`,{className:`land-hero-text`,children:[(0,F.jsx)(`p`,{className:`land-lede`,children:`Draw who builds, who checks, where a person decides and when the work stops. grooph checks that every loop names a stop, then compiles the graph into a package a Claude Code session runs. Your harness runs it; grooph never does.`}),(0,F.jsxs)(`div`,{className:`land-cta`,children:[(0,F.jsx)(`a`,{className:`btn btn-primary`,href:V(`built-in`,J),children:`Open the template`}),(0,F.jsx)(`a`,{className:`btn`,href:`#/templates`,children:`See all twenty`})]}),(0,F.jsx)(`ul`,{className:`land-promise`,"aria-label":`About the app`,children:ht.map(e=>(0,F.jsxs)(`li`,{children:[(0,F.jsx)(it,{}),e]},e))})]}),r?(0,F.jsx)(`figure`,{className:`land-figure`,children:(0,F.jsxs)(ut,{children:[(0,F.jsx)(`div`,{className:`land-picture`,role:`img`,"aria-label":`The review gate template as a graph: a builder, a critic, a human merge approval and a stop, in one loop of at most four rounds`,dangerouslySetInnerHTML:{__html:r.HERO_SVG}}),(0,F.jsxs)(`figcaption`,{className:`muted`,children:[`The `,(0,F.jsx)(`a`,{href:V(`built-in`,J),children:`review gate`}),` template, drawn by grooph.`]})]})}):null]})}),(0,F.jsx)(`section`,{className:`land-section`,children:(0,F.jsx)(`div`,{className:`site-wrap`,children:(0,F.jsxs)(`ul`,{className:`land-claims`,"aria-label":`What grooph does`,children:[(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`strong`,{children:`Every loop names its stop.`}),` The validator refuses a loop without one, and warns when a loop has no budget and either no cap or a cap above five rounds. Where a graph asks for it, it refuses a critic that shares the builder’s context, and it refuses a step marked irreversible with no human gate before it.`]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`strong`,{children:`The graph is the contract.`}),` The package tells the session to run it as drawn: named subagents, stops in order, a halt at every human gate. grooph does not enforce it while it runs; eighteen of the twenty runs counted pass the checks of it, and two say why they do not.`]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`strong`,{children:`Every run is asked for a record.`}),` Notes, rounds and why it stopped, in a folder a monitor reads. To go on, a halted run is resumed in the same session with the person’s answer and its run id.`]})]})})}),(0,F.jsx)(`section`,{className:`land-section land-alt land-start`,"aria-labelledby":`land-start-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsx)(`h2`,{id:`land-start-title`,className:`land-h2`,children:`Two ways to start`}),(0,F.jsxs)(`div`,{className:`land-ways`,children:[(0,F.jsxs)(`div`,{className:`land-way`,children:[(0,F.jsx)(`h3`,{children:`Ask your agent`}),(0,F.jsxs)(`p`,{children:[`In Claude Code, with grooph `,(0,F.jsx)(`a`,{href:`${G}quickstart/`,children:`installed`}),`, describe the work. The session proposes one to three graphs, sends a link to compare them on your phone, and places the package you pick.`]}),(0,F.jsx)(vt,{text:dt})]}),(0,F.jsxs)(`div`,{className:`land-way`,children:[(0,F.jsx)(`h3`,{children:`Open a template`}),(0,F.jsx)(`p`,{children:`Twenty templates, each with a recorded run of its own. Open one, fill in its blanks, and export the package or the graph.`}),(0,F.jsxs)(`div`,{className:`land-way-actions`,children:[(0,F.jsx)(`a`,{className:`btn btn-primary`,href:V(`built-in`,J),children:`Open the review gate`}),(0,F.jsx)(`a`,{className:`btn`,href:`#/templates`,children:`Browse all`})]})]})]}),(0,F.jsx)(`div`,{className:`land-device`,children:e??(0,F.jsx)(_t,{})})]})}),(0,F.jsx)(`section`,{className:`land-section land-strip`,"aria-labelledby":`land-strip-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsx)(`h2`,{id:`land-strip-title`,className:`land-h2`,children:`Loop shapes`}),r?(0,F.jsx)(`ul`,{className:`land-strip-list`,"aria-label":`Templates`,children:r.TILES.map(e=>(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{className:`land-tile`,href:V(`built-in`,e.id),children:[(0,F.jsx)(Me,{svg:e.glyph,long:e.long,className:`land-tile-glyph${e.long?` is-wide`:``}`,decorative:!0}),(0,F.jsx)(`span`,{className:`land-tile-title`,children:e.title})]})},e.id))}):null,(0,F.jsxs)(`div`,{className:`land-poster`,children:[t?(0,F.jsx)(`a`,{href:X,"aria-label":`Open the poster of the twenty loop shapes`,children:(0,F.jsx)(`img`,{src:X,width:`1200`,height:`800`,loading:`lazy`,decoding:`async`,alt:`The poster: twenty loop shapes, each drawn with its name and when to reach for it`,onError:()=>n(!1)})}):null,(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h3`,{children:`Twenty shapes on one page`}),(0,F.jsxs)(`p`,{className:`land-guide-line`,children:[`All twenty, with what each one’s recorded run showed: `,(0,F.jsx)(`a`,{href:`${G}field-guide/`,children:`the field guide`}),`, and`,` `,(0,F.jsx)(`a`,{href:X,children:`a poster of the shapes`}),`.`]})]})]})]})}),(0,F.jsx)(`section`,{className:`land-section land-alt land-more`,"aria-labelledby":`land-more-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsx)(`h2`,{id:`land-more-title`,className:`land-h2`,children:`More than a drawing`}),(0,F.jsxs)(`ul`,{className:`land-more-list`,children:[(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`h3`,{children:`Put a graph on any page`}),(0,F.jsxs)(`p`,{children:[`One line of HTML shows a live graph a reader can pan, zoom and tap, or a recorded run that plays. `,(0,F.jsx)(`a`,{href:`${G}exports/`,children:`How to embed`}),`.`]})]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`h3`,{children:`See what is running`}),(0,F.jsxs)(`p`,{children:[`A hook records when each session and subagent starts and stops, and nothing they say. A screen shows it live.`,` `,(0,F.jsx)(`a`,{href:`${G}subagents/`,children:`How it works`}),`.`]})]}),(0,F.jsxs)(`li`,{children:[(0,F.jsx)(`h3`,{children:`Map work across sessions`}),(0,F.jsxs)(`p`,{children:[`Sessions, the people they work with, and what carries work between them, drawn and checked.`,` `,(0,F.jsx)(`a`,{href:`${G}operation-map/`,children:`Operation maps`}),`.`]})]})]})]})}),(0,F.jsx)(`section`,{className:`land-section land-honest`,"aria-labelledby":`land-honest-title`,children:(0,F.jsxs)(`div`,{className:`site-wrap`,children:[(0,F.jsxs)(`h2`,{id:`land-honest-title`,className:`land-h2`,children:[`What is shown, `,(0,F.jsx)(`mark`,{children:`and what is not`})]}),(0,F.jsxs)(`p`,{children:[`The latest kept run of each of the twenty templates is counted: in those a session stopped where its graph said, at a passed bar or a human gate, and left a record; eighteen of the twenty pass the project’s checks. No round cap or budget is on record as firing. In a paired comparison on four small tasks the package showed no quality advantage over a prompt derived from it. grooph runs no agent, calls no model and needs no hosted service.`,` `,(0,F.jsx)(`a`,{href:`${G}claims/`,children:`Every claim and its evidence`}),`.`]})]})})]}),(0,F.jsx)(lt,{})]})}function _t(){return(0,F.jsx)(`p`,{className:`land-device-line`,children:(0,F.jsx)(`a`,{className:`btn`,href:`#/`,children:`Your graphs`})})}function vt({text:e}){let[t,n]=(0,k.useState)(null);return(0,F.jsxs)(`div`,{className:`copy-line`,children:[(0,F.jsx)(`code`,{className:`copy-line-text`,children:e}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-small`,"aria-label":`Copy the line for Claude Code`,onClick:async()=>n(await De(e)?`Copied. Paste it into Claude Code.`:`Could not copy. Select the line and copy it.`),children:`Copy`}),(0,F.jsx)(`span`,{className:`copy-line-said muted`,role:`status`,children:t})]})}function yt({className:e=``}){let t=ve();if(!t)return null;let n=t.result===`granted`;return(0,F.jsxs)(`div`,{className:`persist-notice ${n?`is-granted`:`is-denied`} ${e}`,role:`status`,children:[(0,F.jsx)(`p`,{children:n?(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(`strong`,{children:`Storage kept.`}),` This browser agreed not to clear grooph’s data to free space.`]}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(`strong`,{children:`Storage not guaranteed.`}),` This browser may clear grooph’s data when space runs low. Keep backups: Export, then Download graph.`]})}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:ge,children:`Got it`})]})}function bt({toast:e,onDone:t}){return(0,k.useEffect)(()=>{if(!e)return;let n=window.setTimeout(t,6e3);return()=>window.clearTimeout(n)},[e,t]),e?(0,F.jsxs)(`div`,{className:`toast`,role:`status`,children:[(0,F.jsx)(`span`,{children:e.text}),e.undo?(0,F.jsx)(`button`,{type:`button`,className:`toast-action`,onClick:()=>{e.undo(),t()},children:`Undo`}):null]},e.id):null}var xt=e=>{let t=Date.now()-e;return t<6e4?`just now`:t<36e5?`${Math.floor(t/6e4)} min ago`:t<864e5?`${Math.floor(t/36e5)} h ago`:new Date(e).toLocaleDateString()},St=()=>n(`Import`,()=>r(()=>import(`./Import-ByMI7Uz9.js`),__vite__mapDeps([3,4,1,5,6]))),Ct=e=>e?.scrollIntoView({block:`nearest`});function wt({runs:e}){return(0,F.jsx)(`ul`,{className:`run-rows`,"aria-label":`Runs`,children:e.map(e=>{let t=c(e.bundle.notes,e.bundle.working);return(0,F.jsx)(`li`,{children:(0,F.jsxs)(`a`,{className:`run-row`,href:re(e.key),children:[(0,F.jsxs)(`span`,{className:`run-row-name`,children:[`Run `,(0,F.jsx)(`span`,{className:`mono`,children:e.run})]}),(0,F.jsx)(`span`,{className:`run-row-meta`,children:s(t)})]})},e.key)})})}function Tt({open:e}){let[t,n]=(0,k.useState)(null),[r,i]=(0,k.useState)([]),[a,o]=(0,k.useState)(!0),[s,c]=(0,k.useState)(null),[l,u]=(0,k.useState)(null),[d,f]=(0,k.useState)(null),[m,g]=(0,k.useState)(null),[_,v]=(0,k.useState)(null),y=(0,k.useRef)(null),[b,x]=(0,k.useState)(null),S=(0,k.useCallback)(async()=>{n(await ae()),i(await ce()),o((await O()).persistent)},[]);(0,k.useEffect)(()=>void S(),[S]);let C={open:e,route:h,problem:c,offer:v,close:()=>x(null)},w=(e,t)=>void St().then(t,()=>c({name:e,issues:[],what:`The part of grooph that opens it could not be fetched. It needs a connection the first time: try again when you have one.`})),T=e=>{e&&w(e.name,async t=>t.importText(await e.text(),e,C))};(0,k.useEffect)(()=>{let e=e=>{let t=e.clipboardData?.getData(`text/plain`);t&&e.target instanceof Element&&!e.target.closest(`input, textarea, select`)&&St().then(e=>e.openPasted(t,C,!0),()=>void 0)};return window.addEventListener(`paste`,e),()=>window.removeEventListener(`paste`,e)});let E=async(e,t)=>{let n=await Ke(e,{replace:t});if(`exists`in n){v(e=>e&&{...e,exists:n.exists});return}v(null),location.hash=V(`yours`,n.saved.id)},D=(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`div`,{className:`library-actions`,children:[(0,F.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-large`,onClick:async()=>{e((await le()).key,!0)},children:`New graph`}),(0,F.jsx)(`a`,{className:`btn btn-large`,href:`#/templates`,children:`Templates`}),(0,F.jsxs)(`label`,{className:`btn btn-large file-btn`,children:[`Import .grooph.json`,(0,F.jsx)(`input`,{ref:y,type:`file`,accept:`.json,application/json`,onChange:e=>{T(e.target.files?.[0]),e.target.value=``}})]}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-large`,onClick:()=>w(`what you paste`,e=>x(t=>t?null:e.PasteBox)),children:`Paste a document`})]}),b?(0,F.jsx)(b,{host:C}):null,a?null:(0,F.jsx)(`p`,{className:`notice`,role:`status`,children:`This browser is not letting grooph store anything, so graphs last until the tab closes. Download them from Export to keep them.`}),(0,F.jsx)(yt,{}),_?(0,F.jsxs)(`div`,{className:`offer`,role:`alert`,ref:Ct,children:[(0,F.jsxs)(`p`,{children:[(0,F.jsxs)(`strong`,{children:[_.name,` is a template:`]}),` `,_.doc.template.title,_.doc.template.kind===`fragment`?` (a fragment)`:``,`.`,` `,_.refusal?`It carries errors, so it cannot go into Yours; grooph template add refuses it too. Open it as a graph to fix it.`:`Add it to Yours to use it from Templates.`]}),_.refusal?(0,F.jsx)(`pre`,{className:`issue-lines`,children:_.refusal.issues.map(p).join(`
|
|
4
4
|
`)}):null,_.exists?(0,F.jsxs)(`p`,{className:`field-hint`,children:[`Yours already has a template with the id `,(0,F.jsx)(`span`,{className:`mono`,children:_.doc.id}),` (version `,_.exists.version,`). Replacing it makes version `,Math.max(_.exists.version,_.doc.version)+1,`.`]}):null,(0,F.jsxs)(`div`,{className:`offer-actions`,children:[_.refusal?null:_.exists?(0,F.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>void E(_.doc,!0),children:`Replace yours`}):(0,F.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>void E(_.doc,!1),children:`Add to Yours`}),(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:async()=>{let t=await ue(_.doc);v(null),e(t.key)},children:`Open it as a graph`}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-quiet`,onClick:()=>v(null),children:`Cancel`})]})]}):null,s?(0,F.jsxs)(`div`,{className:`refusal`,role:`alert`,ref:Ct,children:[(0,F.jsxs)(`p`,{children:[(0,F.jsxs)(`strong`,{children:[`Could not import `,s.name,`.`]}),` `,s.what??`It is not a graph document grooph can open.`]}),(0,F.jsx)(`pre`,{className:`issue-lines`,children:s.issues.map(p).join(`
|
|
5
|
-
`)}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>c(null),children:`Dismiss`})]}):null]});return t===null?null:t.length===0&&r.length===0?(0,F.jsx)(gt,{device:(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`div`,{className:`library-empty land-empty`,children:[(0,F.jsx)(`p`,{children:`No graphs on this device yet.`}),(0,F.jsxs)(`p`,{className:`muted`,children:[`Start one here, or import a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph.json`}),` graph, a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-proposals.json`}),` set, a`,` `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-run.json`}),` run or a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-map.json`}),` operation map.`]})]}),D]})}):(0,F.jsxs)(`div`,{className:`library`,children:[(0,F.jsxs)(`header`,{className:`library-head`,children:[(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h1`,{className:`wordmark`,children:`grooph`}),(0,F.jsx)(`p`,{className:`muted`,children:`Loop graphs for coding agents. Draw, validate, export.`})]}),(0,F.jsx)(`a`,{className:`library-about`,href:`#/about`,children:`What is grooph?`})]}),D,t.length===0?(0,F.jsxs)(`div`,{className:`library-empty`,children:[(0,F.jsx)(`p`,{children:`No graphs on this device yet.`}),(0,F.jsxs)(`p`,{className:`muted`,children:[`Start a new one, or import a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph.json`}),` graph, a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-proposals.json`}),` set, a`,` `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-run.json`}),` run or a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-map.json`}),` operation map.`]})]}):(0,F.jsx)(`ul`,{className:`graph-list`,"aria-label":`Graphs on this device`,children:t.map(t=>(0,F.jsxs)(`li`,{className:`graph-row`,children:[d?.key===t.key?(0,F.jsx)(Et,{record:t,name:d.name,onName:e=>f({key:t.key,name:e}),onCancel:()=>f(null),onSave:async e=>{await se(t.key,d.name,{keepId:e}),f(null),await S()}}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`button`,{type:`button`,className:`graph-open${je(t.doc)?` has-long-glyph`:``}`,onClick:()=>e(t.key),children:[(0,F.jsx)(I,{doc:t.doc,className:`graph-glyph`,decorative:!0}),(0,F.jsxs)(`span`,{className:`graph-text`,children:[(0,F.jsx)(`span`,{className:`graph-name`,children:t.doc.name||`Untitled`}),(0,F.jsxs)(`span`,{className:`graph-meta`,children:[(0,F.jsx)(`span`,{className:`mono`,children:t.doc.id}),` · `,t.doc.nodes.length,` node`,t.doc.nodes.length===1?``:`s`,` ·`,` `,t.doc.loops.length,` loop`,t.doc.loops.length===1?``:`s`,` · `,xt(t.updatedAt)]})]})]}),(0,F.jsx)(`button`,{type:`button`,className:`icon-btn`,"aria-label":`Actions for ${t.doc.name}`,"aria-expanded":l===t.key,onClick:()=>{u(l===t.key?null:t.key),g(null)},children:(0,F.jsxs)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:[(0,F.jsx)(`circle`,{cx:`5`,cy:`12`,r:`1.6`}),(0,F.jsx)(`circle`,{cx:`12`,cy:`12`,r:`1.6`}),(0,F.jsx)(`circle`,{cx:`19`,cy:`12`,r:`1.6`})]})})]}),r.some(e=>e.graphId===t.doc.id)?(0,F.jsx)(wt,{runs:r.filter(e=>e.graphId===t.doc.id)}):null,l===t.key&&d?.key!==t.key?(0,F.jsxs)(`div`,{className:`row-actions`,children:[(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:()=>{f({key:t.key,name:t.doc.name}),u(null)},children:`Rename`}),(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:async()=>{await oe(t.key),u(null),await S()},children:`Duplicate`}),m===t.key?(0,F.jsx)(`button`,{type:`button`,className:`btn btn-danger`,onClick:async()=>{await ie(t.key),u(null),g(null),await S()},children:`Delete for good`}):(0,F.jsx)(`button`,{type:`button`,className:`btn btn-danger-text`,onClick:()=>g(t.key),children:`Delete`})]}):null]},t.key))}),r.some(e=>!t.some(t=>t.doc.id===e.graphId))?(0,F.jsxs)(`section`,{className:`orphan-runs`,"aria-label":`Runs of graphs not on this device`,children:[(0,F.jsx)(`h2`,{className:`list-title`,children:`Runs of graphs not on this device`}),(0,F.jsx)(wt,{runs:r.filter(e=>!t.some(t=>t.doc.id===e.graphId))})]}):null,(0,F.jsxs)(`footer`,{className:`library-foot muted`,children:[`Graphs live in this browser on this device. Nothing is sent anywhere.`,` `,(0,F.jsx)(`a`,{href:`https://github.com/ryanjosephkamp/grooph`,rel:`noopener`,children:`Source`})]})]})}function Et(e){let{record:t}=e,n=u(t.doc,e.name).id,r=t.exported?.id,i=r!==void 0&&n!==r&&l(n,e.name);return(0,F.jsxs)(`form`,{className:`rename`,onSubmit:t=>{t.preventDefault(),e.onSave()},children:[(0,F.jsxs)(`div`,{className:`rename-row`,children:[(0,F.jsx)(`input`,{className:`input`,"aria-label":`Graph name`,value:e.name,autoFocus:!0,onChange:t=>e.onName(t.target.value)}),(0,F.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,children:`Save`}),(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:e.onCancel,children:`Cancel`})]}),i?(0,F.jsx)(Dt,{exportedAs:r,nextId:n,onKeep:()=>e.onSave(r)}):null]})}function Dt({exportedAs:e,nextId:t,onKeep:n}){return(0,F.jsxs)(`div`,{className:`rename-warning`,role:`alert`,children:[(0,F.jsxs)(`p`,{children:[`This graph was exported from this device as `,(0,F.jsxs)(`span`,{className:`mono`,children:[`.grooph/`,e,`/`]}),`. With this name its id becomes`,` `,(0,F.jsx)(`span`,{className:`mono`,children:t}),`, so the next export writes a new package folder, `,(0,F.jsxs)(`span`,{className:`mono`,children:[`.grooph/`,t,`/`]}),`, beside the old one.`]}),(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:n,children:`Keep the old id`})]})}var Ot=i({App:()=>Lt,loadScreens:()=>Q,ready:()=>Pt}),kt=(0,k.lazy)(()=>n(`EmbedApp`,()=>r(()=>import(`./EmbedApp-
|
|
5
|
+
`)}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-small`,onClick:()=>c(null),children:`Dismiss`})]}):null]});return t===null?null:t.length===0&&r.length===0?(0,F.jsx)(gt,{device:(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`div`,{className:`library-empty land-empty`,children:[(0,F.jsx)(`p`,{children:`No graphs on this device yet.`}),(0,F.jsxs)(`p`,{className:`muted`,children:[`Start one here, or import a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph.json`}),` graph, a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-proposals.json`}),` set, a`,` `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-run.json`}),` run or a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-map.json`}),` operation map.`]})]}),D]})}):(0,F.jsxs)(`div`,{className:`library`,children:[(0,F.jsxs)(`header`,{className:`library-head`,children:[(0,F.jsxs)(`div`,{children:[(0,F.jsx)(`h1`,{className:`wordmark`,children:`grooph`}),(0,F.jsx)(`p`,{className:`muted`,children:`Loop graphs for coding agents. Draw, validate, export.`})]}),(0,F.jsx)(`a`,{className:`library-about`,href:`#/about`,children:`What is grooph?`})]}),D,t.length===0?(0,F.jsxs)(`div`,{className:`library-empty`,children:[(0,F.jsx)(`p`,{children:`No graphs on this device yet.`}),(0,F.jsxs)(`p`,{className:`muted`,children:[`Start a new one, or import a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph.json`}),` graph, a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-proposals.json`}),` set, a`,` `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-run.json`}),` run or a `,(0,F.jsx)(`span`,{className:`mono`,children:`.grooph-map.json`}),` operation map.`]})]}):(0,F.jsx)(`ul`,{className:`graph-list`,"aria-label":`Graphs on this device`,children:t.map(t=>(0,F.jsxs)(`li`,{className:`graph-row`,children:[d?.key===t.key?(0,F.jsx)(Et,{record:t,name:d.name,onName:e=>f({key:t.key,name:e}),onCancel:()=>f(null),onSave:async e=>{await se(t.key,d.name,{keepId:e}),f(null),await S()}}):(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`button`,{type:`button`,className:`graph-open${je(t.doc)?` has-long-glyph`:``}`,onClick:()=>e(t.key),children:[(0,F.jsx)(I,{doc:t.doc,className:`graph-glyph`,decorative:!0}),(0,F.jsxs)(`span`,{className:`graph-text`,children:[(0,F.jsx)(`span`,{className:`graph-name`,children:t.doc.name||`Untitled`}),(0,F.jsxs)(`span`,{className:`graph-meta`,children:[(0,F.jsx)(`span`,{className:`mono`,children:t.doc.id}),` · `,t.doc.nodes.length,` node`,t.doc.nodes.length===1?``:`s`,` ·`,` `,t.doc.loops.length,` loop`,t.doc.loops.length===1?``:`s`,` · `,xt(t.updatedAt)]})]})]}),(0,F.jsx)(`button`,{type:`button`,className:`icon-btn`,"aria-label":`Actions for ${t.doc.name}`,"aria-expanded":l===t.key,onClick:()=>{u(l===t.key?null:t.key),g(null)},children:(0,F.jsxs)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:[(0,F.jsx)(`circle`,{cx:`5`,cy:`12`,r:`1.6`}),(0,F.jsx)(`circle`,{cx:`12`,cy:`12`,r:`1.6`}),(0,F.jsx)(`circle`,{cx:`19`,cy:`12`,r:`1.6`})]})})]}),r.some(e=>e.graphId===t.doc.id)?(0,F.jsx)(wt,{runs:r.filter(e=>e.graphId===t.doc.id)}):null,l===t.key&&d?.key!==t.key?(0,F.jsxs)(`div`,{className:`row-actions`,children:[(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:()=>{f({key:t.key,name:t.doc.name}),u(null)},children:`Rename`}),(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:async()=>{await oe(t.key),u(null),await S()},children:`Duplicate`}),m===t.key?(0,F.jsx)(`button`,{type:`button`,className:`btn btn-danger`,onClick:async()=>{await ie(t.key),u(null),g(null),await S()},children:`Delete for good`}):(0,F.jsx)(`button`,{type:`button`,className:`btn btn-danger-text`,onClick:()=>g(t.key),children:`Delete`})]}):null]},t.key))}),r.some(e=>!t.some(t=>t.doc.id===e.graphId))?(0,F.jsxs)(`section`,{className:`orphan-runs`,"aria-label":`Runs of graphs not on this device`,children:[(0,F.jsx)(`h2`,{className:`list-title`,children:`Runs of graphs not on this device`}),(0,F.jsx)(wt,{runs:r.filter(e=>!t.some(t=>t.doc.id===e.graphId))})]}):null,(0,F.jsxs)(`footer`,{className:`library-foot muted`,children:[`Graphs live in this browser on this device. Nothing is sent anywhere.`,` `,(0,F.jsx)(`a`,{href:`https://github.com/ryanjosephkamp/grooph`,rel:`noopener`,children:`Source`})]})]})}function Et(e){let{record:t}=e,n=u(t.doc,e.name).id,r=t.exported?.id,i=r!==void 0&&n!==r&&l(n,e.name);return(0,F.jsxs)(`form`,{className:`rename`,onSubmit:t=>{t.preventDefault(),e.onSave()},children:[(0,F.jsxs)(`div`,{className:`rename-row`,children:[(0,F.jsx)(`input`,{className:`input`,"aria-label":`Graph name`,value:e.name,autoFocus:!0,onChange:t=>e.onName(t.target.value)}),(0,F.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,children:`Save`}),(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:e.onCancel,children:`Cancel`})]}),i?(0,F.jsx)(Dt,{exportedAs:r,nextId:n,onKeep:()=>e.onSave(r)}):null]})}function Dt({exportedAs:e,nextId:t,onKeep:n}){return(0,F.jsxs)(`div`,{className:`rename-warning`,role:`alert`,children:[(0,F.jsxs)(`p`,{children:[`This graph was exported from this device as `,(0,F.jsxs)(`span`,{className:`mono`,children:[`.grooph/`,e,`/`]}),`. With this name its id becomes`,` `,(0,F.jsx)(`span`,{className:`mono`,children:t}),`, so the next export writes a new package folder, `,(0,F.jsxs)(`span`,{className:`mono`,children:[`.grooph/`,t,`/`]}),`, beside the old one.`]}),(0,F.jsx)(`button`,{type:`button`,className:`btn`,onClick:n,children:`Keep the old id`})]})}var Ot=i({App:()=>Lt,loadScreens:()=>Q,ready:()=>Pt}),kt=(0,k.lazy)(()=>n(`EmbedApp`,()=>r(()=>import(`./EmbedApp-390Z2d4x.js`),__vite__mapDeps([7,4,1,8]))).then(e=>({default:e.EmbedApp}))),Z;function Q(){return n(`screens`,()=>r(()=>import(`./screens-aIjMSzZg.js`),__vite__mapDeps([9,4,1,5,6,10]))).then(e=>Z=e)}function At(e){return!jt.has(Ft(e).name)}var jt=new Set([`library`,`about`,`templates`,`embed`]),Mt=e=>e.name===`template`&&e.source===`built-in`,Nt=300;function Pt(e){let t=[];return At(e)&&t.push(Q()),new RegExp(fe).test(e)&&t.push(S()),new RegExp(de).test(e)&&t.push(Promise.race([Y(),new Promise(e=>setTimeout(e,Nt))])),Promise.all(t.map(e=>e.catch(()=>void 0)))}function $(e){try{return decodeURIComponent(e)}catch{return e}}function Ft(e){if(e===`#/run?live`)return{name:`live-run`};if(e===`#/live`)return{name:`live`};let t=/^#\/run\/([^?]+)$/.exec(e);if(t)return{name:`run`,key:$(t[1])};if(e===`#/about`)return{name:`about`};if(e===`#/templates`)return{name:`templates`};if(e===`#/embed`||e.startsWith(`#/embed?`))return{name:`embed`};let n=/^#\/templates\/(built-in|yours|plan)\/([^/?]+)(\/use)?$/.exec(e);if(n)return{name:`template`,source:n[1],id:$(n[2]),use:n[3]!==void 0};let r=/^#\/g\/([^/?]+)(\?new)?$/.exec(e);if(r)return{name:`graph`,key:$(r[1]),fresh:r[2]!==void 0};if(e.startsWith(`#/open?`)){let t=/[?&]c=([^&]*)/.exec(e)?.[1];return{name:`open`,payload:o(e)??``,...t?{candidate:$(t)}:{}}}return{name:`library`}}function It(e,t,n){let[r,i]=(0,k.useState)(()=>e()?`yes`:`no`),[a,o]=(0,k.useState)(null),s=(0,k.useRef)(n);return s.current=n,(0,k.useEffect)(()=>{if(r!==`no`)return;let e=!1;return t().then(()=>!e&&i(`yes`),()=>{e||(o(s.current),i(`failed`))}),()=>{e=!0}},[r]),(0,k.useEffect)(()=>{r===`failed`&&a!==n&&i(`no`)},[n]),r===`failed`&&a!==n?`no`:r}function Lt(){let[e,t]=(0,k.useState)(()=>Ft(location.hash));(0,k.useEffect)(()=>{let e=()=>{t(Ft(location.hash)),window.scrollTo(0,0)};return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]);let n=It(()=>Z!==void 0,Q,e),r=It(()=>T()!==void 0,S,e);(0,k.useEffect)(()=>void Y().catch(()=>void 0),[]);let i=e=>e===`failed`?(0,F.jsxs)(`div`,{className:`notfound`,children:[(0,F.jsx)(`p`,{children:`This screen could not be fetched. It needs a connection the first time.`}),(0,F.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>location.reload(),children:`Load the page again`}),(0,F.jsx)(`a`,{className:`btn`,href:`#/`,children:`Back to the library`})]}):(0,F.jsx)(`div`,{className:`loading`,children:`Opening…`});if(e.name===`about`)return(0,F.jsx)(gt,{});if(Mt(e)&&r!==`yes`)return i(r);if(e.name===`templates`)return(0,F.jsx)(Qe,{});if(e.name===`library`)return(0,F.jsx)(Tt,{open:(e,t)=>{location.hash=`#/g/${encodeURIComponent(e)}${t?`?new`:``}`}});if(e.name===`embed`)return(0,F.jsx)(k.Suspense,{fallback:null,children:(0,F.jsx)(kt,{})});if(!Z)return i(n);let{EditorScreen:a,LiveRun:o,LiveSessions:s,OpenScreen:c,StoredRun:l,TemplateView:u,UseTemplate:d}=Z;if(e.name===`graph`)return(0,F.jsx)(a,{graphKey:e.key,fresh:e.fresh},e.key);if(e.name===`open`)return(0,F.jsx)(c,{payload:e.payload,candidate:e.candidate});if(e.name===`live-run`)return(0,F.jsx)(o,{});if(e.name===`live`)return(0,F.jsx)(s,{});if(e.name===`run`)return(0,F.jsx)(l,{runKey:e.key},e.key);let f=`${e.source}/${e.id}`;return e.use?(0,F.jsx)(d,{source:e.source,id:e.id},f):(0,F.jsx)(u,{source:e.source,id:e.id},f)}export{Lt as App,Se as S,Ee as _,V as a,ye as b,Ge as c,Je as d,Ye as f,De as g,be as h,bt as i,We as l,Q as loadScreens,xe as m,Dt as n,Ze as o,I as p,yt as r,Pt as ready,qe as s,Ot as t,Ke as u,we as v,Te as x,Ce as y};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,n,r,t as i}from"./index-BoSi6XYh.js";import{B as a,Ht as o,L as s,Qt as c,T as l,V as u,c as d,on as f,t as p,u as m,w as h,z as g}from"./share-BzIzB4EY.js";var _=t(e(),1),v=i(),y={agent:`Agent`,"human-gate":`Human gate`,check:`Check`,merge:`Merge`,stop:`Stop`};function b({rows:e}){let t=e.filter(([,e])=>e!=null&&e!==``&&!(Array.isArray(e)&&e.length===0));return t.length===0?null:(0,v.jsx)(`dl`,{className:`gx-rows`,children:t.map(([e,t])=>(0,v.jsxs)(`div`,{children:[(0,v.jsx)(`dt`,{children:e}),(0,v.jsx)(`dd`,{children:t})]},e))})}var x=e=>e&&e.length>0?(0,v.jsx)(`ul`,{children:e.map((e,t)=>(0,v.jsx)(`li`,{children:e},t))}):void 0;function S({doc:e,node:t,run:n}){let r=e.loops.filter(e=>e.members.includes(t.id)).map(e=>e.name||e.id),i=[];switch(t.kind){case`agent`:{let e=typeof t.role==`string`?t.role:t.role.custom,n=t.by!==`person`;i.push([`Role`,n?[e,t.model?.tier,t.effort].filter(Boolean).join(` · `):e],[`Brief`,(0,v.jsx)(`p`,{className:`gx-prose`,children:t.brief})],[`Reads`,x(t.inputs)],[`Leaves`,x(t.outputs)],[`May`,n?t.allow?.join(`, `):void 0],[`May not`,n?t.deny?.join(`, `):void 0],[`Irreversible`,t.irreversible?.join(`, `)]);break}case`human-gate`:i.push([`Asks`,(0,v.jsx)(`p`,{className:`gx-prose`,children:t.prompt})],[`Answers`,t.options?.join(` / `)]);break;case`check`:i.push([`Kind`,t.check.kind],[`Runs`,t.check.run?(0,v.jsx)(`code`,{children:t.check.run}):void 0],[`Passes when`,(0,v.jsx)(`p`,{className:`gx-prose`,children:t.check.pass})]);break;case`merge`:i.push([`Merges`,t.merges.join(`, `)],[`How`,t.strategy]);break;case`stop`:i.push([`Ends the run`,t.outcome??`yes`])}return i.push([`About`,t.description?(0,v.jsx)(`p`,{className:`gx-prose`,children:t.description}):void 0],[`In loop`,r.join(`, `)]),(0,v.jsxs)(v.Fragment,{children:[n?(0,v.jsx)(C,{run:n}):null,(0,v.jsx)(b,{rows:i})]})}function C({run:e}){let t=[e.state,e.round===void 0?``:`round ${e.round}`,e.runs>1?`${e.runs} dispatches`:``].filter(Boolean).join(` · `);return(0,v.jsxs)(`div`,{className:`gx-runline`,"data-state":e.state,children:[(0,v.jsxs)(`strong`,{children:[`At this step: `,t]}),e.note?.text?(0,v.jsx)(`p`,{children:e.note.text}):null]})}function w({doc:e,loop:t,round:n}){return(0,v.jsxs)(v.Fragment,{children:[n?(0,v.jsx)(`div`,{className:`gx-runline`,children:(0,v.jsxs)(`strong`,{children:[`At this step: `,n]})}):null,(0,v.jsx)(b,{rows:[[`Kind`,`${c(f(e),t)} loop`],[`Members`,t.members.map(t=>e.nodes.find(e=>e.id===t)?.name||t).join(`, `)],[`Bar`,t.bar?(0,v.jsx)(`p`,{className:`gx-prose`,children:`${t.bar.name}. ${t.bar.acceptance}`}):void 0],[`Stops, in order`,x(t.stops.map(o))]]})]})}function T({map:e,picked:t}){if(t.kind===`session`){let n=e.sessions.find(e=>e.id===t.id);if(!n)return null;let{out:r,in:i}=u(e,n.id);return(0,v.jsx)(b,{rows:[[`Does`,n.role],[`Runs in`,[n.harness,n.model,n.lifetime,n.count&&n.count>1?`${n.count} like it`:``].filter(Boolean).join(` · `)],[`Lane`,e.lanes.find(e=>e.id===n.lane)?.name??n.lane],[`Repository`,n.repo],[`Graph`,n.graph],[`About`,n.description?(0,v.jsx)(`p`,{className:`gx-prose`,children:n.description}):void 0],[`Hands to`,x(r.map(t=>`${g(e,t.to)}${t.what?`: ${t.what}`:``}`))],[`Takes from`,x(i.map(t=>`${g(e,t.from)}${t.what?`: ${t.what}`:``}`))]]})}if(t.kind===`person`){let n=(e.people??[]).find(e=>e.id===t.id);return n?(0,v.jsx)(b,{rows:[[`Does`,n.role],[`About`,n.description?(0,v.jsx)(`p`,{className:`gx-prose`,children:n.description}):void 0]]}):null}let n=e.handoffs.find(e=>e.id===t.id);return n?(0,v.jsx)(b,{rows:[[`From`,g(e,n.from)],[`To`,g(e,n.to)],[`What`,n.what],[`Carried by`,n.carrier?`${s[n.carrier.kind]}: ${a(e,n)}`:`not named`]]}):null}function E(e,t){if(`grooph`in e){if(t.kind===`node`){let n=e.nodes.find(e=>e.id===t.id);return n?{kind:n.kind===`agent`&&n.by===`person`?`Person`:y[n.kind],name:n.name||n.id}:void 0}if(t.kind===`loop`){let n=e.loops.find(e=>e.id===t.id);return n?{kind:`Loop`,name:n.name||n.id}:void 0}return}if(t.kind===`session`)return{kind:`Session`,name:g(e,t.id)};if(t.kind===`person`)return{kind:`Person`,name:g(e,t.id)};if(t.kind===`handoff`){let n=e.handoffs.findIndex(e=>e.id===t.id),r=e.handoffs[n];return r?{kind:`Handoff ${n+1}`,name:`${g(e,r.from)} → ${g(e,r.to)}`}:void 0}}function D({doc:e,picked:t,run:n,loopRound:r,onClose:i}){let a=E(e,t),o=(0,_.useRef)(null),s=(0,_.useRef)(i);s.current=i;let c=(0,_.useRef)(t);if(c.current=t,(0,_.useEffect)(()=>{o.current?.focus({preventScroll:!0})},[t.kind,t.id]),(0,_.useEffect)(()=>{let e=document.activeElement,t=e=>{e.key===`Escape`&&s.current()};return document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`keydown`,t);let{kind:n,id:r}=c.current,i=document.querySelector(n===`handoff`?`[data-handoff-row="${CSS.escape(r)}"]`:`[data-${n}="${CSS.escape(r)}"]`)??e;(i instanceof HTMLElement||i instanceof SVGElement)&&i.focus({preventScroll:!0})}},[]),!a)return null;let l=null;if(`grooph`in e){if(t.kind===`node`){let r=e.nodes.find(e=>e.id===t.id);l=(0,v.jsx)(S,{doc:e,node:r,...n?{run:n}:{}})}else t.kind===`loop`&&(l=(0,v.jsx)(w,{doc:e,loop:e.loops.find(e=>e.id===t.id),...r?{round:r}:{}}))}else l=(0,v.jsx)(T,{map:e,picked:t});return(0,v.jsxs)(`aside`,{className:`gx-brief`,role:`dialog`,"aria-modal":`false`,"aria-labelledby":`gx-brief-title`,children:[(0,v.jsxs)(`header`,{children:[(0,v.jsxs)(`div`,{children:[(0,v.jsx)(`span`,{className:`gx-brief-kind`,children:a.kind}),(0,v.jsx)(`h2`,{id:`gx-brief-title`,children:a.name})]}),(0,v.jsx)(`button`,{ref:o,type:`button`,className:`gx-btn gx-icon`,"aria-label":`Close brief`,onClick:i,children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`M6 6l12 12M18 6 6 18`})})})]}),(0,v.jsx)(`div`,{className:`gx-brief-body`,children:l})]})}var O=`http://www.w3.org/2000/svg`,k={agent:`Agent`,"human-gate":`Human gate`,check:`Check`,merge:`Merge`,stop:`Stop`},A=`gx-inj`;function j(e,t){e.setAttribute(`tabindex`,`0`),e.setAttribute(`role`,`button`),e.setAttribute(`aria-label`,t)}var M=(e,t)=>Number(e?.getAttribute(t)??0);function N(e,t,n,r,i){let a=document.createElementNS(O,`g`);a.setAttribute(`class`,`${A} gx-pill`),a.setAttribute(`data-state`,i),a.setAttribute(`aria-hidden`,`true`);let o=document.createElementNS(O,`rect`),s=document.createElementNS(O,`text`);s.setAttribute(`font-size`,`9.5`),s.setAttribute(`font-weight`,`700`),s.setAttribute(`text-anchor`,`end`),s.setAttribute(`x`,String(t-6)),s.setAttribute(`y`,String(n)),s.textContent=r,a.append(o,s),e.append(a);let c=(s.getComputedTextLength?.()||r.length*5.6)+12;o.setAttribute(`x`,String(t-c)),o.setAttribute(`y`,String(n-10)),o.setAttribute(`width`,String(c)),o.setAttribute(`height`,`13.5`),o.setAttribute(`rx`,`6.75`)}var P={running:`running`,passed:`passed`,failed:`failed`,halted:`halted`};function F(e,t,n){for(let t of e.querySelectorAll(`.${A}`))t.remove();let r=n?.step.summary,i=n?.step.focus;for(let n of e.querySelectorAll(`g[data-node]`)){let e=n.dataset.node,a=t.nodes.find(t=>t.id===e),o=r?.nodes[e];if(j(n,`${a?a.kind===`agent`&&a.by===`person`?`Person`:k[a.kind]??a.kind:`Node`} ${a?.name||e}${o&&o.state!==`pending`?`, ${o.state}`:o?`, not reached yet`:``}`),!o){delete n.dataset.state,delete n.dataset.focus;continue}n.dataset.state=o.state,i&&i.kind===`node`&&i.id===e?n.dataset.focus=``:delete n.dataset.focus;let s=P[o.state];if(!s)continue;let c=n.querySelector(`rect[data-card]`);if(!c)continue;let l=t.loops.filter(t=>t.members.includes(e)).length;N(n,M(c,`x`)+M(c,`width`)-10-l*10-(l>0?4:0),M(c,`y`)+18,`${s}${o.runs>1?` ×${o.runs}`:``}`,o.state)}let a=e.viewBox.baseVal?.width||400;for(let n of e.querySelectorAll(`g[data-loop]`)){let e=n.dataset.loop,o=t.loops.find(t=>t.id===e),s=r?.loops[e];if(j(n,`Loop ${o?.name||e}${s?`, ${I(s)}`:``}`),i&&i.kind===`loop`&&i.id===e?n.dataset.focus=``:delete n.dataset.focus,!s||s.round===null)continue;let c=n.querySelector(`text`),l=s.lastStop?.fired;N(n,a-12,M(c,`y`),I(s),l?`stopped`:`round`)}for(let t of e.querySelectorAll(`g[data-edge]`))i&&i.kind===`edge`&&i.id===t.dataset.edge?t.dataset.focus=``:delete t.dataset.focus}function I(e){return e.round===null?`not entered`:`round ${e.round}${e.lastStop?.fired?` · ${h[e.lastStop.fired]}`:``}`}function L(e,t){let n=e=>t.handoffs.findIndex(t=>t.id===e)+1;for(let n of e.querySelectorAll(`[data-session]`))j(n,`Session ${g(t,n.dataset.session)}`);for(let n of e.querySelectorAll(`[data-person]`))j(n,`Person ${g(t,n.dataset.person)}`);for(let r of e.querySelectorAll(`[data-handoff-row]`)){let e=r.dataset.handoffRow,i=t.handoffs.find(t=>t.id===e);j(r,i?`Handoff ${n(e)}: ${g(t,i.from)} to ${g(t,i.to)}`:`Handoff ${e}`)}}var ee=e=>{try{return decodeURIComponent(e)}catch{return e}};function te(e){let t=e.includes(`?`)?e.slice(e.indexOf(`?`)+1):``,n=new Map;for(let e of t.split(`&`)){if(e===``)continue;let t=e.indexOf(`=`),r=t<0?e:e.slice(0,t);n.has(r)||n.set(r,t<0?``:e.slice(t+1))}let r=/(?:^|-)(light|dark)$/.exec(n.get(`theme`)??``)?.[1],i=/^([a-z]+?)(?:-(?:light|dark|auto))?$/.exec(n.get(`theme`)??``)?.[1],a=n.get(`c`);return{payload:n.get(`d`)??n.get(`run`)??``,...r===`light`||r===`dark`?{theme:r}:{},frame:n.get(`frame`)===`1`,play:n.get(`play`)===`1`,...a?{candidate:ee(a)}:{},...i&&![`light`,`dark`,`auto`].includes(i)?{look:i}:{}}}var R=e=>e===`#/embed`||e.startsWith(`#/embed?`);function z(e,t=location.href){return`${t.split(`#`)[0]}#/open?d=${e.payload}${e.candidate?`&c=${encodeURIComponent(e.candidate)}`:``}${e.look?`&theme=${e.look}`:``}`}var B=e=>e===void 0||e.round===null?`not entered`:`round ${e.round}${e.lastStop?.fired?` · ${h[e.lastStop.fired]}`:``}`,V=()=>typeof matchMedia==`function`&&matchMedia(`(prefers-reduced-motion: reduce)`).matches;function H({replay:e,doc:t,step:n,setStep:r,autoplay:i}){let a=e.steps.length-1,[o,s]=(0,_.useState)(()=>i&&!V()&&a>0),c=e.steps[n],l=n===a,u=(0,_.useRef)(null);(0,_.useEffect)(()=>{if(!o)return;if(n>=a){s(!1);return}let e=setTimeout(()=>r(e=>Math.min(e+1,a)),900);return()=>clearTimeout(e)},[o,n,a,r]);let d=()=>{if(o)return s(!1);l&&r(0),s(!0)},f=e=>{s(!1),r(t=>Math.min(Math.max(t+e,0),a))},p=l&&n>0?e.end.line:c.caption;return(0,v.jsxs)(`section`,{className:`gx-replay`,"aria-label":`Replay of the run`,children:[(0,v.jsxs)(`div`,{className:`gx-replay-row`,children:[(0,v.jsx)(`button`,{ref:u,type:`button`,className:`gx-btn gx-play`,"aria-label":o?`Pause`:l?`Play the run from the start`:`Play`,onClick:d,disabled:a===0,children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:o?(0,v.jsx)(`path`,{d:`M8 5v14M16 5v14`}):l?(0,v.jsx)(`path`,{d:`M4 12a8 8 0 1 0 2.4-5.7M4 4v4.5h4.5`}):(0,v.jsx)(`path`,{d:`M7 5v14l12-7z`,className:`gx-fill`})})}),(0,v.jsx)(`button`,{type:`button`,className:`gx-btn gx-icon`,"aria-label":`Previous step`,onClick:()=>f(-1),disabled:n===0,children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`M17 6 9 12l8 6zM7 6v12`,className:`gx-fill`})})}),(0,v.jsx)(`button`,{type:`button`,className:`gx-btn gx-icon`,"aria-label":`Next step`,onClick:()=>f(1),disabled:l,children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`m7 6 8 6-8 6zM17 6v12`,className:`gx-fill`})})}),(0,v.jsx)(`input`,{className:`gx-scrub`,type:`range`,min:0,max:a,step:1,value:n,"aria-label":`Replay position`,"aria-valuetext":`Step ${n} of ${a}: ${c.caption}`,onChange:e=>{s(!1),r(Number(e.target.value))}}),(0,v.jsxs)(`span`,{className:`gx-count`,"aria-hidden":`true`,children:[n,`/`,a]})]}),(0,v.jsx)(`p`,{className:`gx-caption${l&&n>0?` is-end`:``}`,"aria-live":`polite`,"data-testid":`replay-caption`,children:p}),t.loops.length>0?(0,v.jsx)(`ul`,{className:`gx-loops`,"aria-label":`Loops`,children:t.loops.map((e,t)=>{let n=c.summary.loops[e.id];return(0,v.jsxs)(`li`,{className:`gx-loop-chip${n?.lastStop?.fired?` is-stopped`:``}`,"data-loop-chip":e.id,children:[(0,v.jsx)(`span`,{className:`gx-dot gx-loop-${t%4}`,"aria-hidden":`true`}),e.name||e.id,` · `,(0,v.jsx)(`span`,{className:`gx-round`,children:B(n)})]},e.id)})}):null]})}var U=6,W=.35,G=4;function K({ref:e,svg:t,width:n,height:r,baseScale:i,label:a,onTap:o,decorate:s,onMoved:c}){let l=(0,_.useRef)(null),u=(0,_.useRef)(null),d=(0,_.useRef)({x:0,y:0,s:i}),f=(0,_.useRef)({x:0,y:0,s:i}),p=(0,_.useRef)(!1),m=(0,_.useRef)(c);m.current=c;let h=(0,_.useRef)(o);h.current=o;let g=()=>({w:l.current?.clientWidth??0,h:l.current?.clientHeight??0}),y=(0,_.useCallback)(e=>{let{w:t,h:i}=g(),a=n*e.s,o=r*e.s;return{x:Math.min(Math.max(e.x,Math.min(0,t-a)-24),Math.max(0,t-a)+24),y:Math.min(Math.max(e.y,Math.min(0,i-o)-24),Math.max(0,i-o)+24),s:e.s}},[n,r]),b=(0,_.useCallback)((e,t)=>{d.current=e;let i=u.current,a=l.current;if(!i||!a)return;i.style.transform=`translate(${e.x}px, ${e.y}px)`;let o=i.querySelector(`svg`);o&&(o.setAttribute(`width`,String(n*e.s)),o.setAttribute(`height`,String(r*e.s)));let{w:s,h:c}=g();a.dataset.overflow=n*e.s>s+1||r*e.s>c+1?`1`:`0`,t!==p.current&&(p.current=t,m.current?.(t))},[n,r]),x=(0,_.useCallback)(()=>{let{w:e,h:t}=g(),a=i;t>0&&r*a>t&&(a=Math.max(t/r,i*.55));let o={x:(e-n*a)/2,y:r*a<=t?(t-r*a)/2:0,s:a};f.current=o,b(o,!1)},[b,i,n,r]),S=(0,_.useCallback)((e,t,n)=>{let r=d.current,a=Math.min(Math.max(r.s*e,i*W),i*G),o=a/r.s;b(y({x:t-(t-r.x)*o,y:n-(n-r.y)*o,s:a}),!0)},[b,y,i]),C=(0,_.useCallback)(e=>{if(!(e instanceof SVGGraphicsElement))return;let t=e.getBBox();if(t.width===0)return;let n=d.current,{w:r,h:i}=g(),a=n.x+t.x*n.s,o=n.y+t.y*n.s,s=a+t.width*n.s,c=o+t.height*n.s,{x:l,y:u}=n;a<8?l+=8-a:s>r-8&&(l-=Math.min(s-(r-8),a-8)),o<8?u+=8-o:c>i-8&&(u-=Math.min(c-(i-8),o-8)),(l!==n.x||u!==n.y)&&b(y({x:l,y:u,s:n.s}),!0)},[b,y]);return(0,_.useImperativeHandle)(e,()=>({zoom:e=>{let{w:t,h:n}=g();S(e,t/2,n/2)},fit:x,reveal:C}),[x,C,S]),(0,_.useLayoutEffect)(()=>{p.current=!1,x()},[t,x]),(0,_.useEffect)(()=>{let e=l.current;if(!e)return;let t=new ResizeObserver(()=>p.current?b(y(d.current),!0):x());return t.observe(e),()=>t.disconnect()},[b,y,x]),(0,_.useLayoutEffect)(()=>{let e=u.current?.querySelector(`svg`);e&&s&&s(e)},[t,s]),(0,_.useEffect)(()=>{let e=l.current;if(!e)return;let t=new Map,n=null,r=null,a=t=>{let n=e.getBoundingClientRect();return{x:t.clientX-n.left,y:t.clientY-n.top}},o=()=>{let[e,n]=[...t.values()];return{d:Math.hypot(e.x-n.x,e.y-n.y),mx:(e.x+n.x)/2,my:(e.y+n.y)/2}},s=e=>{(e.button===0||e.pointerType!==`mouse`)&&(e.target instanceof Element&&e.target.closest(`a, button, input`)||(t.set(e.pointerId,a(e)),t.size===1?(n={...a(e),target:e.target instanceof Element?e.target:null,moved:!1,from:d.current},r=null):t.size===2&&(n=null,r={...o(),from:d.current})))},c=s=>{if(!t.has(s.pointerId))return;if(t.set(s.pointerId,a(s)),r&&t.size>=2){let e=o(),t=Math.min(Math.max(r.from.s*e.d/Math.max(r.d,1),i*W),i*G),n=t/r.from.s;b(y({x:e.mx-(r.mx-r.from.x)*n,y:e.my-(r.my-r.from.y)*n,s:t}),!0);return}if(!n)return;let c=a(s),l=c.x-n.x,u=c.y-n.y;!n.moved&&Math.hypot(l,u)<U||(n.moved||(n={...n,x:c.x,y:c.y,from:d.current,moved:!0},e.setPointerCapture(s.pointerId),e.dataset.dragging=`1`),b(y({x:n.from.x+(c.x-n.x),y:n.from.y+(c.y-n.y),s:n.from.s}),!0))},u=i=>{t.delete(i.pointerId)&&(n&&!n.moved&&i.type===`pointerup`&&n.target&&h.current(n.target),t.size<2&&(r=null),n=null,delete e.dataset.dragging)},f=t=>{let n=a(t);if(t.ctrlKey||t.metaKey){t.preventDefault(),S(Math.exp(-t.deltaY*.01),n.x,n.y);return}let r=d.current,i=y({x:r.x-t.deltaX,y:r.y-t.deltaY,s:r.s});Math.abs(i.x-r.x)<.5&&Math.abs(i.y-r.y)<.5||e.dataset.overflow===`1`&&(t.preventDefault(),b(i,!0))};return e.addEventListener(`pointerdown`,s),e.addEventListener(`pointermove`,c),e.addEventListener(`pointerup`,u),e.addEventListener(`pointercancel`,u),e.addEventListener(`wheel`,f,{passive:!1}),()=>{e.removeEventListener(`pointerdown`,s),e.removeEventListener(`pointermove`,c),e.removeEventListener(`pointerup`,u),e.removeEventListener(`pointercancel`,u),e.removeEventListener(`wheel`,f)}},[b,y,S,i]),(0,v.jsx)(`div`,{ref:l,className:`gx-stage`,onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&e.target instanceof Element&&e.target!==l.current&&o(e.target)&&e.preventDefault()},onFocus:e=>C(e.target),children:(0,v.jsx)(`div`,{ref:u,className:`gx-canvas`,"aria-label":a,role:`group`,dangerouslySetInnerHTML:{__html:t}})})}var q=e=>Math.round(Math.min(Math.max(e,300),600)),J=(e,t)=>Math.min(e/t,1.25),Y=e=>{let t=/viewBox="0 0 ([\d.]+) ([\d.]+)"/.exec(e);return{w:Number(t?.[1]??400),h:Number(t?.[2]??400)}};function X(e){let t=p(e.payload);if(!t.ok)return{kind:`problem`,message:t.message};let{envelope:n}=t;if(n.kind===`graph`)return{kind:`graph`,doc:n.doc};if(n.kind===`map`)return{kind:`map`,doc:n.doc};if(n.kind===`run`)return{kind:`run`,doc:n.doc.working,bundle:n.doc};let r=n.doc,i=r.candidates.find(t=>t.id===e.candidate)??r.candidates.find(e=>e.id===r.recommendation?.candidate)??r.candidates[0];return i&&`grooph`in i.graph?{kind:`graph`,doc:i.graph}:{kind:`problem`,message:`This comparison has no graph that can be drawn here. Open it in grooph to see the candidates.`}}function Z(e){window.parent!==window&&window.parent.postMessage({grooph:`embed-height`,height:e},`*`)}function ne({link:e}){let t=(0,_.useMemo)(()=>X(e),[e]),n=(0,_.useRef)(null),[r,i]=(0,_.useState)(()=>document.documentElement.clientWidth||400);(0,_.useLayoutEffect)(()=>{let e=n.current;if(!e)return;let t=new ResizeObserver(()=>i(e.clientWidth));return t.observe(e),i(e.clientWidth),()=>t.disconnect()},[]);let a={ref:n,className:`gx`,...e.theme?{"data-theme":e.theme}:{},...e.frame?{"data-frame":``}:{}};return t.kind===`problem`?(0,v.jsx)(`div`,{...a,children:(0,v.jsxs)(`div`,{className:`gx-problem`,role:`alert`,children:[(0,v.jsx)(`strong`,{children:`This embed could not be drawn.`}),(0,v.jsx)(`p`,{children:t.message})]})}):(0,v.jsx)(`div`,{...a,...t.kind===`run`?{"data-replay":``}:{},children:(0,v.jsx)(re,{shown:t,link:e,frameWidth:r,root:n})})}function re({shown:e,link:t,frameWidth:n,root:r}){let i=q(n),a=J(n,i),o=(0,_.useMemo)(()=>e.kind===`map`?m(e.doc,{width:i}):d(e.doc,{width:i}),[e,i]),s=(0,_.useMemo)(()=>Y(o),[o]),c=e.doc.name||e.doc.id,u=(0,_.useRef)(null),f=(0,_.useRef)(null),[p,h]=(0,_.useState)(null),[g,y]=(0,_.useState)(!1),b=(0,_.useMemo)(()=>e.kind===`run`?l(e.bundle.notes,e.doc):void 0,[e]),[x,S]=(0,_.useState)(()=>b&&(!t.play||V())?b.steps.length-1:0),C=b?.steps[x],w=(0,_.useCallback)(n=>{t.theme&&n.setAttribute(`data-theme`,t.theme),n.removeAttribute(`role`),n.setAttribute(`aria-hidden`,`false`),e.kind===`map`?L(n,e.doc):F(n,e.doc,C?{step:C,last:x===b.steps.length-1}:void 0);for(let e of n.querySelectorAll(`.is-picked`))e.classList.remove(`is-picked`);if(p){let e=p.kind===`handoff`?`[data-handoff-row="${CSS.escape(p.id)}"], [data-handoff="${CSS.escape(p.id)}"]`:`[data-${p.kind}="${CSS.escape(p.id)}"]`;for(let t of n.querySelectorAll(e))t.classList.add(`is-picked`)}},[e,t.theme,C,x,b,p]),T=(0,_.useCallback)(e=>{let t=e.closest(`[data-node], [data-loop], [data-session], [data-person], [data-handoff], [data-handoff-row], [data-plate], [data-number]`);if(!(t instanceof SVGElement))return!1;let n=t.dataset,r=n.node?{kind:`node`,id:n.node}:n.loop?{kind:`loop`,id:n.loop}:n.session?{kind:`session`,id:n.session}:n.person?{kind:`person`,id:n.person}:{kind:`handoff`,id:n.handoff??n.handoffRow??n.plate??n.number};return h(e=>e&&e.kind===r.kind&&e.id===r.id?null:r),!0},[]);(0,_.useEffect)(()=>{let e=r.current,t=f.current;if(!e||!t)return;let n=()=>Z(Math.ceil(s.h*a+t.offsetHeight+(e.offsetHeight-e.clientHeight)));n();let i=new ResizeObserver(n);i.observe(t);let o=[1e3,3e3].map(e=>setTimeout(n,e));return window.addEventListener(`load`,n),()=>{i.disconnect(),o.forEach(clearTimeout),window.removeEventListener(`load`,n)}},[s.h,a,r]);let E=(0,_.useMemo)(()=>{if(!b||!C||p?.kind!==`node`)return;let e=C.summary.nodes[p.id];if(!e)return;let t=[...b.steps.slice(1,x+1)].reverse().find(e=>e.note?.at===`node:${p.id}`)?.note;return{state:e.state,runs:e.runs,...e.round===void 0?{}:{round:e.round},...t?{note:t}:{}}},[b,C,p,x]),O=b&&C&&p?.kind===`loop`?B(C.summary.loops[p.id]):void 0;return(0,v.jsxs)(v.Fragment,{children:[(0,v.jsxs)(`div`,{className:`gx-main`,children:[(0,v.jsx)(K,{ref:u,svg:o,width:s.w,height:s.h,baseScale:a,label:`${c}. Drag to move, pinch or ctrl and scroll to zoom, tap ${e.kind===`map`?`a session or a handoff`:`a node`} to read about it.`,onTap:T,decorate:w,onMoved:y}),p?(0,v.jsx)(D,{doc:e.doc,picked:p,...E?{run:E}:{},...O?{loopRound:O}:{},onClose:()=>h(null)}):null]}),(0,v.jsxs)(`div`,{ref:f,className:`gx-bars`,children:[b?(0,v.jsx)(H,{replay:b,doc:e.doc,step:x,setStep:S,autoplay:t.play}):null,(0,v.jsxs)(`div`,{className:`gx-bar`,role:`toolbar`,"aria-label":`Picture`,children:[(0,v.jsx)(`button`,{type:`button`,className:`gx-btn gx-icon`,"aria-label":`Zoom out`,onClick:()=>u.current?.zoom(1/1.25),children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`M6 12h12`})})}),(0,v.jsx)(`button`,{type:`button`,className:`gx-btn gx-icon`,"aria-label":`Zoom in`,onClick:()=>u.current?.zoom(1.25),children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`M6 12h12M12 6v12`})})}),(0,v.jsx)(`button`,{type:`button`,className:`gx-btn`,"aria-label":`Fit the picture`,disabled:!g,onClick:()=>u.current?.fit(),children:`Fit`}),(0,v.jsx)(`span`,{className:`gx-spacer`}),(0,v.jsxs)(`a`,{className:`gx-btn gx-open`,href:z(t),target:`_blank`,rel:`noopener noreferrer`,children:[`Open in grooph`,(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`M14 5h5v5M19 5l-8 8M17 14v5H5V7h5`})})]})]})]})]})}var ie=/^#\/embed\?(?:[^&]*&)*?theme=(?:blueprint|ink|phosphor|transit|chalk)(?:-(?:light|dark|auto))?(?:&|$)/,Q=()=>ie.test(location.hash)?n(`themes`,()=>r(()=>import(`./themes-DtOBrLk0.js`),[])).catch(()=>void 0):void 0;addEventListener(`hashchange`,()=>void Q());var $=Q();if($){let e=document.createElement(`style`);e.textContent=`.gx{visibility:hidden}`,document.head.append(e);let t=()=>e.remove();$.then(t),setTimeout(t,800)}function ae(){let[e,t]=(0,_.useState)(()=>location.hash);(0,_.useEffect)(()=>{let e=()=>{!R(location.hash)&&document.documentElement.classList.contains(`gx-page-only`)?location.reload():t(location.hash)};return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]),(0,_.useLayoutEffect)(()=>{let e=document.documentElement;return e.classList.add(`gx-page`),()=>e.classList.remove(`gx-page`)},[]);let n=(0,_.useMemo)(()=>te(e),[e]);return(0,v.jsx)(ne,{link:n},n.payload)}export{ae as EmbedApp};
|
|
1
|
+
import{a as e,c as t,n,r,t as i}from"./index-CeaKwKuU.js";import{B as a,Ht as o,L as s,Qt as c,T as l,V as u,c as d,on as f,t as p,u as m,w as h,z as g}from"./share-BzIzB4EY.js";var _=t(e(),1),v=i(),y={agent:`Agent`,"human-gate":`Human gate`,check:`Check`,merge:`Merge`,stop:`Stop`};function b({rows:e}){let t=e.filter(([,e])=>e!=null&&e!==``&&!(Array.isArray(e)&&e.length===0));return t.length===0?null:(0,v.jsx)(`dl`,{className:`gx-rows`,children:t.map(([e,t])=>(0,v.jsxs)(`div`,{children:[(0,v.jsx)(`dt`,{children:e}),(0,v.jsx)(`dd`,{children:t})]},e))})}var x=e=>e&&e.length>0?(0,v.jsx)(`ul`,{children:e.map((e,t)=>(0,v.jsx)(`li`,{children:e},t))}):void 0;function S({doc:e,node:t,run:n}){let r=e.loops.filter(e=>e.members.includes(t.id)).map(e=>e.name||e.id),i=[];switch(t.kind){case`agent`:{let e=typeof t.role==`string`?t.role:t.role.custom,n=t.by!==`person`;i.push([`Role`,n?[e,t.model?.tier,t.effort].filter(Boolean).join(` · `):e],[`Brief`,(0,v.jsx)(`p`,{className:`gx-prose`,children:t.brief})],[`Reads`,x(t.inputs)],[`Leaves`,x(t.outputs)],[`May`,n?t.allow?.join(`, `):void 0],[`May not`,n?t.deny?.join(`, `):void 0],[`Irreversible`,t.irreversible?.join(`, `)]);break}case`human-gate`:i.push([`Asks`,(0,v.jsx)(`p`,{className:`gx-prose`,children:t.prompt})],[`Answers`,t.options?.join(` / `)]);break;case`check`:i.push([`Kind`,t.check.kind],[`Runs`,t.check.run?(0,v.jsx)(`code`,{children:t.check.run}):void 0],[`Passes when`,(0,v.jsx)(`p`,{className:`gx-prose`,children:t.check.pass})]);break;case`merge`:i.push([`Merges`,t.merges.join(`, `)],[`How`,t.strategy]);break;case`stop`:i.push([`Ends the run`,t.outcome??`yes`])}return i.push([`About`,t.description?(0,v.jsx)(`p`,{className:`gx-prose`,children:t.description}):void 0],[`In loop`,r.join(`, `)]),(0,v.jsxs)(v.Fragment,{children:[n?(0,v.jsx)(C,{run:n}):null,(0,v.jsx)(b,{rows:i})]})}function C({run:e}){let t=[e.state,e.round===void 0?``:`round ${e.round}`,e.runs>1?`${e.runs} dispatches`:``].filter(Boolean).join(` · `);return(0,v.jsxs)(`div`,{className:`gx-runline`,"data-state":e.state,children:[(0,v.jsxs)(`strong`,{children:[`At this step: `,t]}),e.note?.text?(0,v.jsx)(`p`,{children:e.note.text}):null]})}function w({doc:e,loop:t,round:n}){return(0,v.jsxs)(v.Fragment,{children:[n?(0,v.jsx)(`div`,{className:`gx-runline`,children:(0,v.jsxs)(`strong`,{children:[`At this step: `,n]})}):null,(0,v.jsx)(b,{rows:[[`Kind`,`${c(f(e),t)} loop`],[`Members`,t.members.map(t=>e.nodes.find(e=>e.id===t)?.name||t).join(`, `)],[`Bar`,t.bar?(0,v.jsx)(`p`,{className:`gx-prose`,children:`${t.bar.name}. ${t.bar.acceptance}`}):void 0],[`Stops, in order`,x(t.stops.map(o))]]})]})}function T({map:e,picked:t}){if(t.kind===`session`){let n=e.sessions.find(e=>e.id===t.id);if(!n)return null;let{out:r,in:i}=u(e,n.id);return(0,v.jsx)(b,{rows:[[`Does`,n.role],[`Runs in`,[n.harness,n.model,n.lifetime,n.count&&n.count>1?`${n.count} like it`:``].filter(Boolean).join(` · `)],[`Lane`,e.lanes.find(e=>e.id===n.lane)?.name??n.lane],[`Repository`,n.repo],[`Graph`,n.graph],[`About`,n.description?(0,v.jsx)(`p`,{className:`gx-prose`,children:n.description}):void 0],[`Hands to`,x(r.map(t=>`${g(e,t.to)}${t.what?`: ${t.what}`:``}`))],[`Takes from`,x(i.map(t=>`${g(e,t.from)}${t.what?`: ${t.what}`:``}`))]]})}if(t.kind===`person`){let n=(e.people??[]).find(e=>e.id===t.id);return n?(0,v.jsx)(b,{rows:[[`Does`,n.role],[`About`,n.description?(0,v.jsx)(`p`,{className:`gx-prose`,children:n.description}):void 0]]}):null}let n=e.handoffs.find(e=>e.id===t.id);return n?(0,v.jsx)(b,{rows:[[`From`,g(e,n.from)],[`To`,g(e,n.to)],[`What`,n.what],[`Carried by`,n.carrier?`${s[n.carrier.kind]}: ${a(e,n)}`:`not named`]]}):null}function E(e,t){if(`grooph`in e){if(t.kind===`node`){let n=e.nodes.find(e=>e.id===t.id);return n?{kind:n.kind===`agent`&&n.by===`person`?`Person`:y[n.kind],name:n.name||n.id}:void 0}if(t.kind===`loop`){let n=e.loops.find(e=>e.id===t.id);return n?{kind:`Loop`,name:n.name||n.id}:void 0}return}if(t.kind===`session`)return{kind:`Session`,name:g(e,t.id)};if(t.kind===`person`)return{kind:`Person`,name:g(e,t.id)};if(t.kind===`handoff`){let n=e.handoffs.findIndex(e=>e.id===t.id),r=e.handoffs[n];return r?{kind:`Handoff ${n+1}`,name:`${g(e,r.from)} → ${g(e,r.to)}`}:void 0}}function D({doc:e,picked:t,run:n,loopRound:r,onClose:i}){let a=E(e,t),o=(0,_.useRef)(null),s=(0,_.useRef)(i);s.current=i;let c=(0,_.useRef)(t);if(c.current=t,(0,_.useEffect)(()=>{o.current?.focus({preventScroll:!0})},[t.kind,t.id]),(0,_.useEffect)(()=>{let e=document.activeElement,t=e=>{e.key===`Escape`&&s.current()};return document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`keydown`,t);let{kind:n,id:r}=c.current,i=document.querySelector(n===`handoff`?`[data-handoff-row="${CSS.escape(r)}"]`:`[data-${n}="${CSS.escape(r)}"]`)??e;(i instanceof HTMLElement||i instanceof SVGElement)&&i.focus({preventScroll:!0})}},[]),!a)return null;let l=null;if(`grooph`in e){if(t.kind===`node`){let r=e.nodes.find(e=>e.id===t.id);l=(0,v.jsx)(S,{doc:e,node:r,...n?{run:n}:{}})}else t.kind===`loop`&&(l=(0,v.jsx)(w,{doc:e,loop:e.loops.find(e=>e.id===t.id),...r?{round:r}:{}}))}else l=(0,v.jsx)(T,{map:e,picked:t});return(0,v.jsxs)(`aside`,{className:`gx-brief`,role:`dialog`,"aria-modal":`false`,"aria-labelledby":`gx-brief-title`,children:[(0,v.jsxs)(`header`,{children:[(0,v.jsxs)(`div`,{children:[(0,v.jsx)(`span`,{className:`gx-brief-kind`,children:a.kind}),(0,v.jsx)(`h2`,{id:`gx-brief-title`,children:a.name})]}),(0,v.jsx)(`button`,{ref:o,type:`button`,className:`gx-btn gx-icon`,"aria-label":`Close brief`,onClick:i,children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`M6 6l12 12M18 6 6 18`})})})]}),(0,v.jsx)(`div`,{className:`gx-brief-body`,children:l})]})}var O=`http://www.w3.org/2000/svg`,k={agent:`Agent`,"human-gate":`Human gate`,check:`Check`,merge:`Merge`,stop:`Stop`},A=`gx-inj`;function j(e,t){e.setAttribute(`tabindex`,`0`),e.setAttribute(`role`,`button`),e.setAttribute(`aria-label`,t)}var M=(e,t)=>Number(e?.getAttribute(t)??0);function N(e,t,n,r,i){let a=document.createElementNS(O,`g`);a.setAttribute(`class`,`${A} gx-pill`),a.setAttribute(`data-state`,i),a.setAttribute(`aria-hidden`,`true`);let o=document.createElementNS(O,`rect`),s=document.createElementNS(O,`text`);s.setAttribute(`font-size`,`9.5`),s.setAttribute(`font-weight`,`700`),s.setAttribute(`text-anchor`,`end`),s.setAttribute(`x`,String(t-6)),s.setAttribute(`y`,String(n)),s.textContent=r,a.append(o,s),e.append(a);let c=(s.getComputedTextLength?.()||r.length*5.6)+12;o.setAttribute(`x`,String(t-c)),o.setAttribute(`y`,String(n-10)),o.setAttribute(`width`,String(c)),o.setAttribute(`height`,`13.5`),o.setAttribute(`rx`,`6.75`)}var P={running:`running`,passed:`passed`,failed:`failed`,halted:`halted`};function F(e,t,n){for(let t of e.querySelectorAll(`.${A}`))t.remove();let r=n?.step.summary,i=n?.step.focus;for(let n of e.querySelectorAll(`g[data-node]`)){let e=n.dataset.node,a=t.nodes.find(t=>t.id===e),o=r?.nodes[e];if(j(n,`${a?a.kind===`agent`&&a.by===`person`?`Person`:k[a.kind]??a.kind:`Node`} ${a?.name||e}${o&&o.state!==`pending`?`, ${o.state}`:o?`, not reached yet`:``}`),!o){delete n.dataset.state,delete n.dataset.focus;continue}n.dataset.state=o.state,i&&i.kind===`node`&&i.id===e?n.dataset.focus=``:delete n.dataset.focus;let s=P[o.state];if(!s)continue;let c=n.querySelector(`rect[data-card]`);if(!c)continue;let l=t.loops.filter(t=>t.members.includes(e)).length;N(n,M(c,`x`)+M(c,`width`)-10-l*10-(l>0?4:0),M(c,`y`)+18,`${s}${o.runs>1?` ×${o.runs}`:``}`,o.state)}let a=e.viewBox.baseVal?.width||400;for(let n of e.querySelectorAll(`g[data-loop]`)){let e=n.dataset.loop,o=t.loops.find(t=>t.id===e),s=r?.loops[e];if(j(n,`Loop ${o?.name||e}${s?`, ${I(s)}`:``}`),i&&i.kind===`loop`&&i.id===e?n.dataset.focus=``:delete n.dataset.focus,!s||s.round===null)continue;let c=n.querySelector(`text`),l=s.lastStop?.fired;N(n,a-12,M(c,`y`),I(s),l?`stopped`:`round`)}for(let t of e.querySelectorAll(`g[data-edge]`))i&&i.kind===`edge`&&i.id===t.dataset.edge?t.dataset.focus=``:delete t.dataset.focus}function I(e){return e.round===null?`not entered`:`round ${e.round}${e.lastStop?.fired?` · ${h[e.lastStop.fired]}`:``}`}function L(e,t){let n=e=>t.handoffs.findIndex(t=>t.id===e)+1;for(let n of e.querySelectorAll(`[data-session]`))j(n,`Session ${g(t,n.dataset.session)}`);for(let n of e.querySelectorAll(`[data-person]`))j(n,`Person ${g(t,n.dataset.person)}`);for(let r of e.querySelectorAll(`[data-handoff-row]`)){let e=r.dataset.handoffRow,i=t.handoffs.find(t=>t.id===e);j(r,i?`Handoff ${n(e)}: ${g(t,i.from)} to ${g(t,i.to)}`:`Handoff ${e}`)}}var ee=e=>{try{return decodeURIComponent(e)}catch{return e}};function te(e){let t=e.includes(`?`)?e.slice(e.indexOf(`?`)+1):``,n=new Map;for(let e of t.split(`&`)){if(e===``)continue;let t=e.indexOf(`=`),r=t<0?e:e.slice(0,t);n.has(r)||n.set(r,t<0?``:e.slice(t+1))}let r=/(?:^|-)(light|dark)$/.exec(n.get(`theme`)??``)?.[1],i=/^([a-z]+?)(?:-(?:light|dark|auto))?$/.exec(n.get(`theme`)??``)?.[1],a=n.get(`c`);return{payload:n.get(`d`)??n.get(`run`)??``,...r===`light`||r===`dark`?{theme:r}:{},frame:n.get(`frame`)===`1`,play:n.get(`play`)===`1`,...a?{candidate:ee(a)}:{},...i&&![`light`,`dark`,`auto`].includes(i)?{look:i}:{}}}var R=e=>e===`#/embed`||e.startsWith(`#/embed?`);function z(e,t=location.href){return`${t.split(`#`)[0]}#/open?d=${e.payload}${e.candidate?`&c=${encodeURIComponent(e.candidate)}`:``}${e.look?`&theme=${e.look}`:``}`}var B=e=>e===void 0||e.round===null?`not entered`:`round ${e.round}${e.lastStop?.fired?` · ${h[e.lastStop.fired]}`:``}`,V=()=>typeof matchMedia==`function`&&matchMedia(`(prefers-reduced-motion: reduce)`).matches;function H({replay:e,doc:t,step:n,setStep:r,autoplay:i}){let a=e.steps.length-1,[o,s]=(0,_.useState)(()=>i&&!V()&&a>0),c=e.steps[n],l=n===a,u=(0,_.useRef)(null);(0,_.useEffect)(()=>{if(!o)return;if(n>=a){s(!1);return}let e=setTimeout(()=>r(e=>Math.min(e+1,a)),900);return()=>clearTimeout(e)},[o,n,a,r]);let d=()=>{if(o)return s(!1);l&&r(0),s(!0)},f=e=>{s(!1),r(t=>Math.min(Math.max(t+e,0),a))},p=l&&n>0?e.end.line:c.caption;return(0,v.jsxs)(`section`,{className:`gx-replay`,"aria-label":`Replay of the run`,children:[(0,v.jsxs)(`div`,{className:`gx-replay-row`,children:[(0,v.jsx)(`button`,{ref:u,type:`button`,className:`gx-btn gx-play`,"aria-label":o?`Pause`:l?`Play the run from the start`:`Play`,onClick:d,disabled:a===0,children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:o?(0,v.jsx)(`path`,{d:`M8 5v14M16 5v14`}):l?(0,v.jsx)(`path`,{d:`M4 12a8 8 0 1 0 2.4-5.7M4 4v4.5h4.5`}):(0,v.jsx)(`path`,{d:`M7 5v14l12-7z`,className:`gx-fill`})})}),(0,v.jsx)(`button`,{type:`button`,className:`gx-btn gx-icon`,"aria-label":`Previous step`,onClick:()=>f(-1),disabled:n===0,children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`M17 6 9 12l8 6zM7 6v12`,className:`gx-fill`})})}),(0,v.jsx)(`button`,{type:`button`,className:`gx-btn gx-icon`,"aria-label":`Next step`,onClick:()=>f(1),disabled:l,children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`m7 6 8 6-8 6zM17 6v12`,className:`gx-fill`})})}),(0,v.jsx)(`input`,{className:`gx-scrub`,type:`range`,min:0,max:a,step:1,value:n,"aria-label":`Replay position`,"aria-valuetext":`Step ${n} of ${a}: ${c.caption}`,onChange:e=>{s(!1),r(Number(e.target.value))}}),(0,v.jsxs)(`span`,{className:`gx-count`,"aria-hidden":`true`,children:[n,`/`,a]})]}),(0,v.jsx)(`p`,{className:`gx-caption${l&&n>0?` is-end`:``}`,"aria-live":`polite`,"data-testid":`replay-caption`,children:p}),t.loops.length>0?(0,v.jsx)(`ul`,{className:`gx-loops`,"aria-label":`Loops`,children:t.loops.map((e,t)=>{let n=c.summary.loops[e.id];return(0,v.jsxs)(`li`,{className:`gx-loop-chip${n?.lastStop?.fired?` is-stopped`:``}`,"data-loop-chip":e.id,children:[(0,v.jsx)(`span`,{className:`gx-dot gx-loop-${t%4}`,"aria-hidden":`true`}),e.name||e.id,` · `,(0,v.jsx)(`span`,{className:`gx-round`,children:B(n)})]},e.id)})}):null]})}var U=6,W=.35,G=4;function K({ref:e,svg:t,width:n,height:r,baseScale:i,label:a,onTap:o,decorate:s,onMoved:c}){let l=(0,_.useRef)(null),u=(0,_.useRef)(null),d=(0,_.useRef)({x:0,y:0,s:i}),f=(0,_.useRef)({x:0,y:0,s:i}),p=(0,_.useRef)(!1),m=(0,_.useRef)(c);m.current=c;let h=(0,_.useRef)(o);h.current=o;let g=()=>({w:l.current?.clientWidth??0,h:l.current?.clientHeight??0}),y=(0,_.useCallback)(e=>{let{w:t,h:i}=g(),a=n*e.s,o=r*e.s;return{x:Math.min(Math.max(e.x,Math.min(0,t-a)-24),Math.max(0,t-a)+24),y:Math.min(Math.max(e.y,Math.min(0,i-o)-24),Math.max(0,i-o)+24),s:e.s}},[n,r]),b=(0,_.useCallback)((e,t)=>{d.current=e;let i=u.current,a=l.current;if(!i||!a)return;i.style.transform=`translate(${e.x}px, ${e.y}px)`;let o=i.querySelector(`svg`);o&&(o.setAttribute(`width`,String(n*e.s)),o.setAttribute(`height`,String(r*e.s)));let{w:s,h:c}=g();a.dataset.overflow=n*e.s>s+1||r*e.s>c+1?`1`:`0`,t!==p.current&&(p.current=t,m.current?.(t))},[n,r]),x=(0,_.useCallback)(()=>{let{w:e,h:t}=g(),a=i;t>0&&r*a>t&&(a=Math.max(t/r,i*.55));let o={x:(e-n*a)/2,y:r*a<=t?(t-r*a)/2:0,s:a};f.current=o,b(o,!1)},[b,i,n,r]),S=(0,_.useCallback)((e,t,n)=>{let r=d.current,a=Math.min(Math.max(r.s*e,i*W),i*G),o=a/r.s;b(y({x:t-(t-r.x)*o,y:n-(n-r.y)*o,s:a}),!0)},[b,y,i]),C=(0,_.useCallback)(e=>{if(!(e instanceof SVGGraphicsElement))return;let t=e.getBBox();if(t.width===0)return;let n=d.current,{w:r,h:i}=g(),a=n.x+t.x*n.s,o=n.y+t.y*n.s,s=a+t.width*n.s,c=o+t.height*n.s,{x:l,y:u}=n;a<8?l+=8-a:s>r-8&&(l-=Math.min(s-(r-8),a-8)),o<8?u+=8-o:c>i-8&&(u-=Math.min(c-(i-8),o-8)),(l!==n.x||u!==n.y)&&b(y({x:l,y:u,s:n.s}),!0)},[b,y]);return(0,_.useImperativeHandle)(e,()=>({zoom:e=>{let{w:t,h:n}=g();S(e,t/2,n/2)},fit:x,reveal:C}),[x,C,S]),(0,_.useLayoutEffect)(()=>{p.current=!1,x()},[t,x]),(0,_.useEffect)(()=>{let e=l.current;if(!e)return;let t=new ResizeObserver(()=>p.current?b(y(d.current),!0):x());return t.observe(e),()=>t.disconnect()},[b,y,x]),(0,_.useLayoutEffect)(()=>{let e=u.current?.querySelector(`svg`);e&&s&&s(e)},[t,s]),(0,_.useEffect)(()=>{let e=l.current;if(!e)return;let t=new Map,n=null,r=null,a=t=>{let n=e.getBoundingClientRect();return{x:t.clientX-n.left,y:t.clientY-n.top}},o=()=>{let[e,n]=[...t.values()];return{d:Math.hypot(e.x-n.x,e.y-n.y),mx:(e.x+n.x)/2,my:(e.y+n.y)/2}},s=e=>{(e.button===0||e.pointerType!==`mouse`)&&(e.target instanceof Element&&e.target.closest(`a, button, input`)||(t.set(e.pointerId,a(e)),t.size===1?(n={...a(e),target:e.target instanceof Element?e.target:null,moved:!1,from:d.current},r=null):t.size===2&&(n=null,r={...o(),from:d.current})))},c=s=>{if(!t.has(s.pointerId))return;if(t.set(s.pointerId,a(s)),r&&t.size>=2){let e=o(),t=Math.min(Math.max(r.from.s*e.d/Math.max(r.d,1),i*W),i*G),n=t/r.from.s;b(y({x:e.mx-(r.mx-r.from.x)*n,y:e.my-(r.my-r.from.y)*n,s:t}),!0);return}if(!n)return;let c=a(s),l=c.x-n.x,u=c.y-n.y;!n.moved&&Math.hypot(l,u)<U||(n.moved||(n={...n,x:c.x,y:c.y,from:d.current,moved:!0},e.setPointerCapture(s.pointerId),e.dataset.dragging=`1`),b(y({x:n.from.x+(c.x-n.x),y:n.from.y+(c.y-n.y),s:n.from.s}),!0))},u=i=>{t.delete(i.pointerId)&&(n&&!n.moved&&i.type===`pointerup`&&n.target&&h.current(n.target),t.size<2&&(r=null),n=null,delete e.dataset.dragging)},f=t=>{let n=a(t);if(t.ctrlKey||t.metaKey){t.preventDefault(),S(Math.exp(-t.deltaY*.01),n.x,n.y);return}let r=d.current,i=y({x:r.x-t.deltaX,y:r.y-t.deltaY,s:r.s});Math.abs(i.x-r.x)<.5&&Math.abs(i.y-r.y)<.5||e.dataset.overflow===`1`&&(t.preventDefault(),b(i,!0))};return e.addEventListener(`pointerdown`,s),e.addEventListener(`pointermove`,c),e.addEventListener(`pointerup`,u),e.addEventListener(`pointercancel`,u),e.addEventListener(`wheel`,f,{passive:!1}),()=>{e.removeEventListener(`pointerdown`,s),e.removeEventListener(`pointermove`,c),e.removeEventListener(`pointerup`,u),e.removeEventListener(`pointercancel`,u),e.removeEventListener(`wheel`,f)}},[b,y,S,i]),(0,v.jsx)(`div`,{ref:l,className:`gx-stage`,onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&e.target instanceof Element&&e.target!==l.current&&o(e.target)&&e.preventDefault()},onFocus:e=>C(e.target),children:(0,v.jsx)(`div`,{ref:u,className:`gx-canvas`,"aria-label":a,role:`group`,dangerouslySetInnerHTML:{__html:t}})})}var q=e=>Math.round(Math.min(Math.max(e,300),600)),J=(e,t)=>Math.min(e/t,1.25),Y=e=>{let t=/viewBox="0 0 ([\d.]+) ([\d.]+)"/.exec(e);return{w:Number(t?.[1]??400),h:Number(t?.[2]??400)}};function X(e){let t=p(e.payload);if(!t.ok)return{kind:`problem`,message:t.message};let{envelope:n}=t;if(n.kind===`graph`)return{kind:`graph`,doc:n.doc};if(n.kind===`map`)return{kind:`map`,doc:n.doc};if(n.kind===`run`)return{kind:`run`,doc:n.doc.working,bundle:n.doc};let r=n.doc,i=r.candidates.find(t=>t.id===e.candidate)??r.candidates.find(e=>e.id===r.recommendation?.candidate)??r.candidates[0];return i&&`grooph`in i.graph?{kind:`graph`,doc:i.graph}:{kind:`problem`,message:`This comparison has no graph that can be drawn here. Open it in grooph to see the candidates.`}}function Z(e){window.parent!==window&&window.parent.postMessage({grooph:`embed-height`,height:e},`*`)}function ne({link:e}){let t=(0,_.useMemo)(()=>X(e),[e]),n=(0,_.useRef)(null),[r,i]=(0,_.useState)(()=>document.documentElement.clientWidth||400);(0,_.useLayoutEffect)(()=>{let e=n.current;if(!e)return;let t=new ResizeObserver(()=>i(e.clientWidth));return t.observe(e),i(e.clientWidth),()=>t.disconnect()},[]);let a={ref:n,className:`gx`,...e.theme?{"data-theme":e.theme}:{},...e.frame?{"data-frame":``}:{}};return t.kind===`problem`?(0,v.jsx)(`div`,{...a,children:(0,v.jsxs)(`div`,{className:`gx-problem`,role:`alert`,children:[(0,v.jsx)(`strong`,{children:`This embed could not be drawn.`}),(0,v.jsx)(`p`,{children:t.message})]})}):(0,v.jsx)(`div`,{...a,...t.kind===`run`?{"data-replay":``}:{},children:(0,v.jsx)(re,{shown:t,link:e,frameWidth:r,root:n})})}function re({shown:e,link:t,frameWidth:n,root:r}){let i=q(n),a=J(n,i),o=(0,_.useMemo)(()=>e.kind===`map`?m(e.doc,{width:i}):d(e.doc,{width:i}),[e,i]),s=(0,_.useMemo)(()=>Y(o),[o]),c=e.doc.name||e.doc.id,u=(0,_.useRef)(null),f=(0,_.useRef)(null),[p,h]=(0,_.useState)(null),[g,y]=(0,_.useState)(!1),b=(0,_.useMemo)(()=>e.kind===`run`?l(e.bundle.notes,e.doc):void 0,[e]),[x,S]=(0,_.useState)(()=>b&&(!t.play||V())?b.steps.length-1:0),C=b?.steps[x],w=(0,_.useCallback)(n=>{t.theme&&n.setAttribute(`data-theme`,t.theme),n.removeAttribute(`role`),n.setAttribute(`aria-hidden`,`false`),e.kind===`map`?L(n,e.doc):F(n,e.doc,C?{step:C,last:x===b.steps.length-1}:void 0);for(let e of n.querySelectorAll(`.is-picked`))e.classList.remove(`is-picked`);if(p){let e=p.kind===`handoff`?`[data-handoff-row="${CSS.escape(p.id)}"], [data-handoff="${CSS.escape(p.id)}"]`:`[data-${p.kind}="${CSS.escape(p.id)}"]`;for(let t of n.querySelectorAll(e))t.classList.add(`is-picked`)}},[e,t.theme,C,x,b,p]),T=(0,_.useCallback)(e=>{let t=e.closest(`[data-node], [data-loop], [data-session], [data-person], [data-handoff], [data-handoff-row], [data-plate], [data-number]`);if(!(t instanceof SVGElement))return!1;let n=t.dataset,r=n.node?{kind:`node`,id:n.node}:n.loop?{kind:`loop`,id:n.loop}:n.session?{kind:`session`,id:n.session}:n.person?{kind:`person`,id:n.person}:{kind:`handoff`,id:n.handoff??n.handoffRow??n.plate??n.number};return h(e=>e&&e.kind===r.kind&&e.id===r.id?null:r),!0},[]);(0,_.useEffect)(()=>{let e=r.current,t=f.current;if(!e||!t)return;let n=()=>Z(Math.ceil(s.h*a+t.offsetHeight+(e.offsetHeight-e.clientHeight)));n();let i=new ResizeObserver(n);i.observe(t);let o=[1e3,3e3].map(e=>setTimeout(n,e));return window.addEventListener(`load`,n),()=>{i.disconnect(),o.forEach(clearTimeout),window.removeEventListener(`load`,n)}},[s.h,a,r]);let E=(0,_.useMemo)(()=>{if(!b||!C||p?.kind!==`node`)return;let e=C.summary.nodes[p.id];if(!e)return;let t=[...b.steps.slice(1,x+1)].reverse().find(e=>e.note?.at===`node:${p.id}`)?.note;return{state:e.state,runs:e.runs,...e.round===void 0?{}:{round:e.round},...t?{note:t}:{}}},[b,C,p,x]),O=b&&C&&p?.kind===`loop`?B(C.summary.loops[p.id]):void 0;return(0,v.jsxs)(v.Fragment,{children:[(0,v.jsxs)(`div`,{className:`gx-main`,children:[(0,v.jsx)(K,{ref:u,svg:o,width:s.w,height:s.h,baseScale:a,label:`${c}. Drag to move, pinch or ctrl and scroll to zoom, tap ${e.kind===`map`?`a session or a handoff`:`a node`} to read about it.`,onTap:T,decorate:w,onMoved:y}),p?(0,v.jsx)(D,{doc:e.doc,picked:p,...E?{run:E}:{},...O?{loopRound:O}:{},onClose:()=>h(null)}):null]}),(0,v.jsxs)(`div`,{ref:f,className:`gx-bars`,children:[b?(0,v.jsx)(H,{replay:b,doc:e.doc,step:x,setStep:S,autoplay:t.play}):null,(0,v.jsxs)(`div`,{className:`gx-bar`,role:`toolbar`,"aria-label":`Picture`,children:[(0,v.jsx)(`button`,{type:`button`,className:`gx-btn gx-icon`,"aria-label":`Zoom out`,onClick:()=>u.current?.zoom(1/1.25),children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`M6 12h12`})})}),(0,v.jsx)(`button`,{type:`button`,className:`gx-btn gx-icon`,"aria-label":`Zoom in`,onClick:()=>u.current?.zoom(1.25),children:(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`M6 12h12M12 6v12`})})}),(0,v.jsx)(`button`,{type:`button`,className:`gx-btn`,"aria-label":`Fit the picture`,disabled:!g,onClick:()=>u.current?.fit(),children:`Fit`}),(0,v.jsx)(`span`,{className:`gx-spacer`}),(0,v.jsxs)(`a`,{className:`gx-btn gx-open`,href:z(t),target:`_blank`,rel:`noopener noreferrer`,children:[`Open in grooph`,(0,v.jsx)(`svg`,{viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,v.jsx)(`path`,{d:`M14 5h5v5M19 5l-8 8M17 14v5H5V7h5`})})]})]})]})]})}var ie=/^#\/embed\?(?:[^&]*&)*?theme=(?:blueprint|ink|phosphor|transit|chalk)(?:-(?:light|dark|auto))?(?:&|$)/,Q=()=>ie.test(location.hash)?n(`themes`,()=>r(()=>import(`./themes-DtOBrLk0.js`),[])).catch(()=>void 0):void 0;addEventListener(`hashchange`,()=>void Q());var $=Q();if($){let e=document.createElement(`style`);e.textContent=`.gx{visibility:hidden}`,document.head.append(e);let t=()=>e.remove();$.then(t),setTimeout(t,800)}function ae(){let[e,t]=(0,_.useState)(()=>location.hash);(0,_.useEffect)(()=>{let e=()=>{!R(location.hash)&&document.documentElement.classList.contains(`gx-page-only`)?location.reload():t(location.hash)};return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]),(0,_.useLayoutEffect)(()=>{let e=document.documentElement;return e.classList.add(`gx-page`),()=>e.classList.remove(`gx-page`)},[]);let n=(0,_.useMemo)(()=>te(e),[e]);return(0,v.jsx)(ne,{link:n},n.payload)}export{ae as EmbedApp};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as e,c as t,t as n}from"./index-
|
|
1
|
+
import{a as e,c as t,t as n}from"./index-CeaKwKuU.js";import{an as r,c as i,fn as a,o,s,sn as c,tt as l}from"./share-BzIzB4EY.js";import{S as u,_ as d,b as f,g as p,h as m,m as h,v as g,x as _,y as v}from"./App-48y1Ec5B.js";var y=t(e(),1),b=e=>e.replace(/[\s\u0000-\u001f\u007f-\u009f\u200b-\u200d\u2028\u2029\u2060]+/g,` `).trim(),x=e=>b(e).replace(/[\\`*_[\]<>&|~#]/g,`\\$&`),S=e=>x(e)||` `,C=e=>b(e)===e&&!/[`|<>\\]/.test(e)?`runs \`${e}\``:`runs a command, given in full below`,w=e=>typeof e.role==`string`?e.role:e.role.custom;function T(e){return e.nodes.map(e=>{let t={id:e.id,name:b(e.name??``)||e.id};switch(e.kind){case`agent`:return e.by===`person`?{...t,whose:`a person`,does:b(w(e)),leaves:b(e.outputs.join(`; `))}:{...t,whose:w(e)===`lead`?`the lead`:`an agent`,does:b([w(e),e.model?.tier,e.effort?`${e.effort} effort`:void 0].filter(Boolean).join(`, `)),leaves:b(e.outputs.join(`; `))};case`human-gate`:{let n=(e.options??[]).map(b).filter(Boolean);return{...t,whose:`a person`,does:n.length>0?`decides: ${n.join(` / `)}`:b(e.prompt)?`is asked: ${b(e.prompt)}`:`is asked`,leaves:`their answer`}}case`check`:{let n=b(e.check.pass)?`pass or fail (${b(e.check.pass)})`:`pass or fail`;return e.check.run&&b(e.check.run)?{...t,whose:`a command`,does:`runs a command`,leaves:n,command:e.check.run}:{...t,whose:`the lead`,does:`judges a check of kind ${e.check.kind}`,leaves:n}}case`merge`:return{...t,whose:`the lead`,does:e.merges.length>0?b(`merges ${e.merges.join(`, `)}`):`merges what it is handed`,leaves:b(e.merges.join(`; `))};case`stop`:return{...t,whose:`nobody`,does:`the run ends here${e.outcome===`halt`?`, halted`:e.outcome===`success`?`, in success`:``}`,leaves:``}}})}var E=(e,t,n)=>`${e} ${e===1?t:n}`,D=(e,t)=>e([{...t,title:`x`}]).replace(/^# x\n*/,``).trimEnd();function O(e,t,n,r,i){let[,a,o,s]=e,c=x(t.name??``)||t.id,l=n.filter(e=>e.severity===`error`),u=n.filter(e=>e.severity!==`error`),d=s(t).filter(e=>e.severity===`error`).length,f=T(t),p=new Map(f.map(e=>[e.id,e.name])),m=e=>f.filter(t=>t.whose===e).length,h=[...t.edges.filter(e=>e.approval===!0).map(e=>`- to approve the work going from ${x(p.get(e.from)??e.from)} to ${x(p.get(e.to)??e.to)}, each time`),...t.loops.flatMap(e=>e.stops.filter(e=>e.kind===`human`).map(t=>`- in the loop ${x(e.name??``)||e.id}, ${t.kind===`human`&&t.every!==void 0?t.every===1?`every round`:`every ${t.every} rounds`:`when it stops for them`}`))],g=e=>`- \`${e.code}\` ${x(e.message)}${e.at.length>0?` (at: ${e.at.map(x).join(`, `)})`:``}`,_=t.notes?.length??0,[v,...y]=a(t);return`${[`# ${c}`,``,`A plan, kept by grooph: the picture, who does what, and every step in full. grooph runs nothing: a plan is for people to read and follow. The document it is drawn from is \`${i}\`, and that is the one to edit.${_>0?` It carries ${E(_,`note`,`notes`)} from runs, which ${_===1?`is`:`are`} in that file and not shown here.`:``}`,``,`${d>0?`As a plan this is not whole yet: it breaks ${d===1?`a rule a graph itself is held to`:`the rules a graph itself is held to in ${d} places`}, and until ${d===1?`that is`:`those are`} fixed, parts of what follows may be missing or drawn wrong.`:f.length===0?`This plan has no steps yet.`:`As a plan for people to read and follow, this is whole.`} ${l.length===0?`A coding harness could run it as it is: nothing in it is in error.${t.target?.harness?` \`grooph export\` writes its package for ${x(t.target.harness)}.`:``}`:`**To run it in a coding harness, ${E(l.length,`thing is`,`things are`)} to be fixed first**${d>0&&d<l.length?` (${d===1?`that one`:`those ${d}`} among them)`:``}, listed under "To fix before a harness can run this".`}`,``,...b(t.goal??``)?[`**Goal:** ${x(t.goal)}`,``]:[],``,``,`## Who does what`,``,...f.length===0?[`No steps yet.`]:[`| Step | Whose | What it does or asks | Leaves behind |`,`|---|---|---|---|`,...f.map(e=>`| ${S(e.name)} | ${e.whose===`nobody`?` `:e.whose} | ${e.command===void 0?S(e.does):C(e.command)} | ${S(e.leaves)} |`),``,`Of ${E(f.length,`step`,`steps`)}: ${m(`an agent`)} by an agent, ${m(`a person`)} by a person, ${m(`a command`)} by a command${m(`the lead`)>0?`, ${m(`the lead`)} by the lead`:``}${m(`nobody`)>0?`; ${m(`nobody`)} ${m(`nobody`)===1?`ends`:`end`} the run`:``}.`],...h.length>0?[``,`A person is also asked, apart from the steps above:`,``,...h]:[],``,`## To fix before a harness can run this`,``,...l.length>0?[`Each of these stops a package from being written. The code names the rule, and grooph's rule reference has each rule in full.`,``,...l.map(g)]:[`Nothing.`],...u.length>0?[``,l.length>0?`And these are warnings: a package is written with them, and carries them in its lead's brief.`:`These are warnings: a package is written with them, and carries them in its lead's brief.`,``,...u.map(g)]:[],``,`## In full`,``,...v?[D(o,v),``]:[],...y.flatMap(e=>[`### ${e.kind}: ${x(e.title)||e.id}`,``,`\`${e.id}\``,``,D(o,e),``])].join(`
|
|
2
2
|
`).replace(/\n{3,}/g,`
|
|
3
3
|
|
|
4
4
|
`).trimEnd()}\n`}function k(e,t){let[n,,,r,i]=e,a=r(t,{forExport:!0}),o=`${t.id}.svg`,s=`${t.id}.grooph.json`;return{files:{"PLAN.md":O(e,t,a,o,s),[o]:i(t),[s]:n(t)},toFix:a}}var A=e=>k([c,o,s,l,e=>i(e)],e),j=e=>`${e.id||`graph`}-plan.zip`,M=(e,t)=>Object.fromEntries(Object.entries(t.files).map(([t,n])=>[`${e.id||`graph`}-plan/${t}`,n])),N=e=>e.endsWith(`.svg`)?`image/svg+xml`:e.endsWith(`.json`)?`application/json`:`text/markdown`,P=n();function F({doc:e,own:t,needs:n,keep:r,open:i,exported:o}){let[s,c]=(0,y.useState)(m()?`here`:`coming`);(0,y.useEffect)(()=>{if(s!==`coming`)return;let e=!1;return f().then(()=>!e&&c(`here`),()=>!e&&c(`failed`)),()=>{e=!0}},[s]);let l=(0,y.useMemo)(()=>h(e),[e,s]),u=!t.some(e=>e.code===`E_SCHEMA`),p=(0,y.useMemo)(()=>u?A(e):void 0,[e,u]),_=(0,P.jsx)(`button`,{type:`button`,className:`btn`,onClick:()=>d(g(e),v(e),`application/json`),children:`Download graph (.grooph.json)`});return u?(0,P.jsxs)(`div`,{className:`inspector`,children:[p?(0,P.jsx)(I,{doc:e,plan:p,graph:_}):null,r,(0,P.jsx)(L,{doc:e,attempt:l,compiler:s,own:t,needs:n,open:i,exported:o})]}):(0,P.jsxs)(`div`,{className:`inspector`,children:[(0,P.jsxs)(`div`,{className:`refusal`,role:`alert`,children:[(0,P.jsx)(`p`,{children:(0,P.jsx)(`strong`,{children:`This does not read as a graph yet: fix these first.`})}),(0,P.jsx)(`p`,{className:`field-hint`,children:`The document does not match the graph schema yet, so it has no plan and no package. The file itself can be kept.`}),(0,P.jsx)(`pre`,{className:`issue-lines`,children:t.map(a).join(`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,t as n}from"./index-
|
|
1
|
+
import{a as e,c as t,t as n}from"./index-CeaKwKuU.js";import{E as r,G as i,H as a,J as o,M as s,N as c,Y as l}from"./share-BzIzB4EY.js";import{m as u}from"./templates-CoNTzuuz.js";import{S as d,a as f,p,u as m}from"./runs-DcjRi7S6.js";var h=t(e(),1),g=n(),_=e=>{try{return JSON.parse(e)}catch{return}},v=`It could not be read: it is nested far deeper than a grooph document ever is.`;async function y(e,t,n){try{return await b(e,t,n)}catch(e){if(!(e instanceof RangeError))throw e;return n.problem({name:t.name,issues:[],what:v}),!1}}async function b(e,t,n){let h=_(e);if(s(h)){let e=c(h);if(!e.bundle)return n.problem({name:t.name,issues:e.issues.map(e=>({code:`E_SCHEMA`,severity:`error`,message:e,at:[]})),what:`It is a run bundle grooph cannot read. Make it again with grooph runs bundle <run dir> --out <file>.`}),!1;let{record:r}=await f(e.bundle);return location.hash=d(r.key),!0}if(a(h)){let e=i(h);return e.map?(location.hash=n.route(e.map),!0):(n.problem({name:t.name,issues:e.issues,what:`It is an operation map grooph cannot read.`}),!1)}if(o(h)){let i=l(JSON.parse(e));try{if(!i.set)throw new r(`not a proposal set`,i.issues);return location.hash=n.route(i.set),!0}catch(e){if(!(e instanceof r))throw e;return n.problem({name:t.name,issues:e.issues,what:`It is a proposal set grooph cannot show. Make a self-contained copy with grooph share --out, which carries every graph.`}),!1}}let g=p(e);if(!g.doc)return n.problem({name:t.name,issues:g.issues}),!1;if(n.problem(null),g.doc.template)return n.offer({name:t.name,doc:g.doc,refusal:u(g.doc)}),!0;let v=await m(g.doc);return n.open(v.key),!0}var x=e=>{try{let t=JSON.parse(e);return typeof t==`object`&&t&&!Array.isArray(t)?t:void 0}catch{return}},S=e=>`grooph`in e||o(e)||a(e)||s(e);function C(e){if(S(e))return e;let t=e.graph;return typeof t==`object`&&t&&!Array.isArray(t)&&S(t)?t:void 0}function w(e,t){let n=0,r=!1;for(let i=t;i<e.length;i+=1){let a=e[i];if(r)a===`\\`?i+=1:a===`"`&&(r=!1);else if(a===`"`)r=!0;else if(a===`{`)n+=1;else if(a===`}`&&(--n,n===0))return e.slice(t,i+1)}}var T=1e6;function E(e){if(e.length>1e6)return{kind:`nothing`};let t=e.trim();if(t===``)return{kind:`nothing`};let n=[],r=x(t);if(r)n.push({text:t,json:r,inside:!1,at:0});else{for(let e of t.matchAll(/```[A-Za-z0-9-]*[ \t]*\r?\n([\s\S]*?)```/g)){let t=e[1].trim(),r=x(t);r&&n.push({text:t,json:r,inside:!1,at:e.index+e[0].indexOf(t)})}let e=0,r=t.indexOf(`{`);for(let i=0;r!==-1&&i<64&&e<8;i+=1){let i=w(t,r);if(i===void 0){e+=1,r=t.indexOf(`{`,r+1);continue}let a=x(i);a&&!n.some(e=>e.at===r)&&n.push({text:i,json:a,inside:e>0,at:r}),r=t.indexOf(`{`,r+i.length)}n.sort((e,t)=>e.at-t.at)}for(let e of n){let t=C(e.json);if(t)return{kind:`document`,text:t===e.json?e.text:JSON.stringify(t,null,2)}}let i=/#\/(?:open|embed)\?((?:[^#\s]*&)?d=([A-Za-z0-9_-]+)[^#\s]*)/.exec(t);if(i){let e=/(?:^|&)c=([A-Za-z0-9_%.~-]+)(?:&|$)/.exec(i[1])?.[1],t=/(?:^|&)theme=([a-z]+(?:-[a-z]+)?)(?:&|$)/.exec(i[1])?.[1],n=`${e?`&c=${e}`:``}${t?`&theme=${t}`:``}`;return{kind:`link`,payload:i[2],...n?{rest:n}:{}}}let a=n.find(e=>!e.inside);return a?{kind:`document`,text:a.text}:{kind:`nothing`}}async function D(e,t,n=!1){let r=`what you pasted`;if(e.length>1e6)return n||t.problem({name:r,issues:[],what:`It is over a megabyte, and a grooph document is a few kilobytes. Paste the document alone.`}),!1;try{let i=E(e);if(i.kind===`link`)return t.close(),location.hash=`#/open?d=${i.payload}${i.rest??``}`,!0;if(i.kind===`nothing`)return n||t.problem({name:r,issues:[{code:`E_SCHEMA`,severity:`error`,message:`no JSON document and no grooph link was found in the text`,at:[]}],what:`Paste the whole document, from its first { to its last }, or a link that ends in #/open?d=…`}),!1;let a=await y(i.text,{name:r},t);return a&&t.close(),a}catch(e){if(!(e instanceof RangeError))throw e;return n||t.problem({name:r,issues:[],what:v}),!1}}var O=e=>e?.scrollIntoView({block:`nearest`});function k({host:e}){let[t,n]=(0,h.useState)(``);return(0,h.useEffect)(()=>e.problem(null),[]),(0,g.jsxs)(`form`,{className:`offer`,style:{flexDirection:`column`,alignItems:`stretch`},ref:O,onSubmit:n=>{n.preventDefault(),D(t,e)},children:[(0,g.jsx)(`label`,{className:`field-label`,htmlFor:`paste-document`,style:{marginBottom:0},children:`A graph's JSON, as a chat or an agent gave it to you, or a grooph link`}),(0,g.jsx)(`textarea`,{id:`paste-document`,className:`input textarea mono`,rows:6,autoFocus:!0,spellCheck:!1,autoCapitalize:`off`,autoCorrect:`off`,placeholder:`{ "grooph": 0, "id": "…", "nodes": [ … ] }`,value:t,onChange:e=>n(e.target.value)}),(0,g.jsx)(`div`,{className:`field-hint`,style:{margin:0},children:`The code fence and the sentences around it can stay. Nothing leaves this device; the document is checked here, with the same rules as a file.`}),(0,g.jsxs)(`div`,{className:`offer-actions`,children:[(0,g.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:t.trim()===``,children:`Open it`}),(0,g.jsx)(`button`,{type:`button`,className:`btn btn-quiet`,onClick:e.close,children:`Cancel`})]})]})}export{T as PASTE_LIMIT,k as PasteBox,y as importText,D as openPasted,E as readPasted};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./index-CeaKwKuU.js";import{Kt as t,Ut as n,Yt as r}from"./share-BzIzB4EY.js";var i=e=>typeof e.when==`object`?e.when.verdict:e.when??`always`;function a(e){let t=new Map(e.nodes.map(e=>[e.id,e.kind])),n=new Set(e.nodes.filter(e=>e.kind===`stop`&&e.outcome===`halt`).map(e=>e.id)),a=new Set(e.nodes.filter(r).map(e=>e.id)),o=e.edges.map(e=>({from:e.from,to:e.to,person:e.approval===!0||t.get(e.from)===`human-gate`,edge:e.id,when:i(e)}));for(let t of e.loops)for(let e of t.stops){if(e.then===void 0)continue;let r=e.kind===`max-iterations`||e.kind===`budget`||e.kind===`human`,i=r&&n.has(e.then),s=e.kind===`bar-passed`?t.members.filter(e=>a.has(e)):[];for(let n of t.members)o.push({from:n,to:e.then,person:e.kind===`human`,loop:t.id,...r?{fires:r}:{},...i?{escalates:i}:{},...s.length>0?{verdictOf:s}:{}})}return o}var o=e=>`${e.loop}\n${e.to}`;function s(e,t){if(t===`every`)return e.person;if(`approval`in t)return e.edge===t.approval;if(`critic`in t&&(e.escalates||e.fires&&t.stops?.has(o(e)))||`critic`in t&&e.verdictOf?.includes(t.critic)&&(t.when===void 0||t.when===`pass`))return!0;let n=`gate`in t?t.gate:t.critic;return e.edge!==void 0&&e.from===n&&(t.when===void 0||e.when===t.when)}function c(e){let t=new Set(e.loops.flatMap(e=>e.back));return e.nodes.filter(n=>!e.edges.some(e=>e.to===n.id&&!t.has(e.id))).map(e=>e.id)}function l(e,t,n){let r=new Set(e.nodes.map(e=>e.id)),i=new Map;for(let t of a(e))n!==void 0&&s(t,n)||!r.has(t.from)||!r.has(t.to)||(i.get(t.from)??i.set(t.from,[]).get(t.from)).push(t.to);let o=new Set(t),c=[...o];for(let e=c.pop();e!==void 0;e=c.pop())for(let t of i.get(e)??[])o.has(t)||(o.add(t),c.push(t));return o}var u=(e,t)=>l(e,c(e),t);function d(e,t){let n=new Map(t.nodes.map(e=>[e.id,e])),s=new Set(t.edges.filter(e=>e.approval===!0).map(e=>e.id)),c=t=>[...new Set(e.edges.filter(e=>e.from===t).map(i))],l=[`every`],u=new Set(a(e).filter(e=>e.fires).map(o));for(let t of e.nodes)t.kind===`human-gate`&&n.get(t.id)?.kind===`human-gate`&&l.push({gate:t.id},...c(t.id).map(e=>({gate:t.id,when:e})));for(let t of e.edges)t.approval===!0&&s.has(t.id)&&l.push({approval:t.id});for(let t of e.nodes){let e=n.get(t.id);if(r(t)&&e&&r(e)&&l.push({critic:t.id},...c(t.id).map(e=>({critic:t.id,when:e}))),t.kind===`check`&&e?.kind===`check`)for(let e of[{check:!0},{check:!0,stops:u}])l.push({critic:t.id,...e},...c(t.id).map(n=>({critic:t.id,when:n,...e})))}return l}function f(e){if(e===`every`)return`a person`;if(`approval`in e)return`the approval on "${e.approval}"`;if(`gate`in e)return e.when===void 0?`the human gate "${e.gate}"`:`"${e.when}" at the human gate "${e.gate}"`;let t=e.check?`check`:`critic`;return e.when===void 0?`the ${t} "${e.critic}"`:`"${e.when}" from the ${t} "${e.critic}"`}var p=(e,t)=>JSON.stringify(e)===JSON.stringify(t),m=(e,t)=>e!==void 0&&(e===t||e.startsWith(`${t}; `)||e.endsWith(`; ${t}`)||e.includes(`; ${t}; `)),h=e=>e.map(e=>`"${e}"`).join(`, `),g=e=>e?.kind===`agent`?e.irreversible??[]:[],_=e=>e.kind===`max-iterations`||e.kind===`budget`||e.kind===`human`,v={dispatches:`dispatch`,minutes:`minute`,turns:`turn`,tokens:`token`,rounds:`round`},y=(e,t)=>`${e} ${e===1?v[t]??t:t}`,b=(e,t)=>t===``?`${e}`:y(e,t);function x(e){let t=new Map(e.nodes.map(e=>[e.id,e]));return e=>{if(e.then===void 0)return!0;let n=t.get(e.then);return n?.kind===`human-gate`||n?.kind===`stop`&&n.outcome===`halt`}}function S(e,t){let n=x(e),r=new Map,i=(e,t)=>e===void 0?t:Math.min(e,t);for(let e of t)for(let t of e.stops){let[e,a,o,s]=t.kind===`max-iterations`?[`cap`,`the round cap`,``,t.n]:t.kind===`budget`?[`budget ${t.measure}`,`the budget`,t.measure,t.limit]:t.kind===`human`?[`human`,`the stop where a person is asked`,``,t.every??1]:[void 0,``,``,0];if(e===void 0)continue;let c=r.get(e)??r.set(e,{name:a,unit:o,leads:new Set}).get(e);c.any=i(c.any,s),n(t)?c.halt=i(c.halt,s):(c.lead=i(c.lead,s),c.leads.add(t.then))}return r}function C(e,t){let n=[],r=e=>e.lead!==void 0&&(e.halt===void 0||e.lead<=e.halt);for(let[i,a]of e){let e=t.get(i),o=i===`human`;if(e?.any===void 0)n.push(o?`removes the stop where a person is asked`:`removes ${a.name} (${b(a.any,a.unit)})`);else if(e.any>a.any)n.push(o?`a person would be asked every ${e.any} rounds, not every ${a.any}`:`raises ${a.name} from ${a.any} to ${b(e.any,a.unit)}`);else if(a.halt!==void 0&&e.halt===void 0)n.push(`${a.name} (${b(a.halt,a.unit)}) would no longer halt the run`);else if(a.halt!==void 0&&e.halt>a.halt)n.push(`${a.name} that halts the run would rise from ${a.halt} to ${b(e.halt,a.unit)}`);else if(a.halt!==void 0&&!r(a)&&r(e))n.push(`${o?`a stop that asks a person`:a.name} of ${b(e.lead,a.unit)} that leads on to ${h([...e.leads])} would fire ${e.lead<e.halt?`before`:`as soon as`} the one of ${b(e.halt,a.unit)} that halts the run`);else if(r(e)){let t=[...e.leads].filter(e=>!a.leads.has(e));t.length>0&&n.push(`${a.name} would lead on to ${h(t)}${a.leads.size>0?`, not to ${h([...a.leads])}`:``}`)}}return n}function w(e){switch(e.kind){case`max-iterations`:return`the round cap of ${e.n}`;case`budget`:return`the budget of ${y(e.limit,e.measure)}`;case`human`:return(e.every??1)===1?`the stop where a person is asked`:`the stop where a person is asked every ${y(e.every,`rounds`)}`;case`diminishing-returns`:return`the stop on diminishing returns over ${y(e.rounds,`rounds`)}`;case`evidence-invalid`:return`the stop on evidence invalid for ${y(e.rounds,`rounds`)}`;default:return`the stop on "bar passed"`}}var T=e=>e.kind===`max-iterations`?e.n:e.kind===`budget`?e.limit:e.kind===`human`?e.every??1:e.kind===`bar-passed`?void 0:e.rounds,E=e=>e.kind===`budget`?`budget ${e.measure}`:e.kind===`diminishing-returns`?`${e.kind} ${JSON.stringify([e.metric??null,e.threshold??null])}`:e.kind,D=(e,t)=>n=>n.kind===`human`?!1:n.kind===`bar-passed`?!t&&(n.then===void 0||!e(n)):n.then!==void 0&&!e(n);function O(e){let t=e=>Number.isFinite(e)?Math.max(1,Math.ceil(e)):1;switch(e.kind){case`max-iterations`:return{sort:`cap`,from:t(e.n)};case`human`:return{sort:`person`,every:t(e.every??1)};case`budget`:return{sort:`counted`,key:`budget ${e.measure}`,size:e.limit,from:1,lasting:!0};case`diminishing-returns`:return{sort:`counted`,key:`no progress ${JSON.stringify([e.metric??null,e.threshold??null])}`,size:e.rounds,from:t(e.rounds),lasting:!1};case`evidence-invalid`:return{sort:`counted`,key:`invalid evidence`,size:e.rounds,from:t(e.rounds),lasting:!1};default:return{sort:`counted`,key:`bar passed`,size:0,from:1,lasting:!1}}}function k(e){let t=e.map(O),n=[],r=[],i=new Map,[a,o,s,c]=[!1,1/0,1/0,1/0];t.forEach((e,t)=>{n.push(a),r.push(o),e.sort===`person`?(i.has(e.every)||i.set(e.every,t),a||=e.every===1,s=Math.min(s,e.every)):e.sort===`cap`&&(o=Math.min(o,e.from),s>e.from&&(c=Math.min(c,e.from)))});let l=new Map,u=e=>{let n=l.get(e);if(!n){let r=1/0;n=t.map(t=>{let n=r;return t.sort===`counted`&&t.key===e&&(r=Math.min(r,t.size)),n}),l.set(e,n)}return n},d=new Map;return{timing:t,always:n,capAhead:r,over:c,person:i,divides:e=>{let t=d.get(e);if(t===void 0){t=1/0;for(let[n,r]of i)e%n===0&&(t=Math.min(t,r));d.set(e,t)}return t},least:u}}function A(e,t,n,r){let[i,a]=[k(e),k(n)],o=i.timing.flatMap((e,t)=>e.sort===`cap`?[{from:e.from,at:t}]:[]).sort((e,t)=>e.from-t.from),s=[];return n.forEach((n,c)=>{let l=a.timing[c];if(l.sort===`person`||!r(n)||a.always[c])return;let[u,d]=[l.from,Math.min(a.over,a.capAhead[c]-1)];if(u>d||l.sort===`counted`&&!(a.least(l.key)[c]>l.size))return;let f=[],p=1/0;for(let e of i.timing)f.push(p),e.sort===`person`&&!(a.divides(e.every)<c)&&(p=Math.min(p,e.every));let m=u;if(l.sort===`counted`){let e=i.timing.findIndex(e=>e.sort===`counted`&&e.key===l.key&&e.size<=l.size);e>=0&&(m=Math.max(m,f[e]))}for(let e of o)e.from<=m&&m<f[e.at]&&(m=f[e.at]);let h;for(let[r,o]of e.entries()){let e=i.timing[r];if(!t(o)||i.always[r]||e.sort===`person`&&i.divides(e.every)<r)continue;let[f,p]=[e.sort===`person`?e.every:e.from,Math.min(i.over,i.capAhead[r]-1)];if(f>p||e.sort===`counted`&&!(i.least(e.key)[r]>e.size)||l.sort===`counted`&&l.lasting&&!(i.least(l.key)[r]>l.size))continue;let g=(t,n)=>t<=n&&(e.sort!==`person`||Math.ceil(t/e.every)*e.every<=n),_=g(Math.max(u,f),Math.min(d,p))&&!(e.sort===`person`&&a.divides(e.every)<c)&&!(l.sort===`counted`&&!(i.least(l.key)[r]>l.size))&&!(e.sort===`counted`&&!(a.least(e.key)[c]>e.size));if(Number.isFinite(m)&&m<=d&&g(Math.max(f,m+1),p)){e.sort===`person`&&_?s.push({at:c,from:r,lead:n,halt:o,before:!1}):s.push({at:c,from:r,lead:n,halt:o,before:!0,...e.sort===`person`?{again:m>=e.every}:{}});return}_&&(h??=r)}h!==void 0&&s.push({at:c,from:h,lead:n,halt:e[h],before:!1})}),s}var j=e=>e.edge??`${e.loop} → ${e.to}`;function M(e,t,n){let r=new Set(t.back),i=new Set(e.nodes.filter(e=>e.kind===`human-gate`).map(e=>e.id)),o=a(e).filter(e=>e.from!==e.to&&(e.edge===void 0||!r.has(e.edge))&&(!e.person||n.has(j(e)))),s=n=>n.edge===void 0?[j(n)]:e.loops.filter(e=>e.id!==t.id&&e.back.includes(n.edge)).map(e=>e.id),c=(e,t)=>{let n=new Set(e),r=[...n];for(let e=r.pop();e!==void 0;e=r.pop())for(let i of t(e))n.has(i)||r.push((n.add(i),i));return n},l=o.filter(e=>e.loop===t.id&&t.members.includes(e.to)&&!i.has(e.to)),u=new Map(l.map(e=>[j(e),e])),d=new Map;for(let e of t.members){let t=c([e],e=>o.filter(t=>t.from===e).map(e=>e.to)),n=c([e],e=>o.filter(t=>t.to===e).map(e=>e.from)),r=new Set(l.map(j));for(let e of o)if(t.has(e.from)&&n.has(e.to)){u.set(j(e),e);for(let t of s(e))r.add(t)}d.set(e,r)}return{ways:u,closers:d}}function N(e,t){let n=[],i=[],o=new Set(t.nodes.map(e=>e.id)),s=new Set(e.nodes.map(e=>e.id)),c=a(e),u=a(t),d=new Set(t.nodes.filter(e=>[...l(t,u.filter(t=>t.from===e.id&&t.to!==e.id).map(e=>e.to))].includes(e.id)||u.some(t=>t.edge!==void 0&&t.from===e.id&&t.to===e.id)).map(e=>e.id)),f=new Map(t.edges.map(e=>[e.id,e])),m=new Map(t.loops.map(e=>[e.id,e])),g=new Map(e.loops.map(e=>[e.id,e])),v=new Map(e.edges.map(e=>[e.id,e])),y=new Set(e.nodes.filter(e=>r(e)&&t.nodes.some(t=>t.id===e.id&&r(t))).map(e=>e.id));for(let r of e.loops){if(!(r.stops.some(_)||r.bar!==void 0))continue;let a=m.get(r.id);a||n.push({why:`removes a loop with its stops and its bar`,at:[`loop:${r.id}`]});let l=[...new Set(r.stops.flatMap(e=>e.then===void 0?[]:[`node:${e.then}.kind`,`node:${e.then}.outcome`,`node:${e.then}`]))],b=S(e,[r]);if(a){for(let e of C(b,S(t,[a])))n.push({why:e,at:[`loop:${r.id}.stops`,...l]});let[o,s]=[x(e),x(t)],c=e=>e.kind===`human`||_(e)&&o(e),u=(e,t)=>e.members.some(e=>(t?.members.includes(e)??!1)&&y.has(e)),d=e=>e.kind===`human`?w(e):`${w(e)} that halts the run`,f=e=>JSON.stringify(e),[p,m]=[new Map,new Map];r.stops.forEach((e,t)=>void(p.has(f(e))||p.set(f(e),t))),a.stops.forEach((e,t)=>void m.set(f(e),t));let h=new Map;for(let e of r.stops)m.has(f(e))||(h.get(E(e))??h.set(E(e),[]).get(E(e))).push(e);let v=a.stops.filter(e=>e.kind===`human`&&!p.has(f(e))),O=[...new Set(a.stops.flatMap(e=>e.kind===`human`?[e.every??1]:[]))],k=[`loop:${r.id}.stops`,...l];for(let{at:e,from:t,lead:n,halt:l,before:g,again:_}of A(r.stops,c,a.stops,D(s,u(a,r)))){let r=w(n),a=n.then===void 0?`${r}, which follows the loop's pass edges,`:`${r} that leads on to "${n.then}"`,s=g?l.kind===`human`?_?`between two askings of ${w(l)}, after the person has said go on`:`before ${w(l)} first asks`:`before ${d(l)}`:`on the same pass as ${d(l)}, where it would be the one obeyed`,c=p.get(f(n)),u=h.get(E(n))??[],y=u.find(e=>e.then===n.then&&T(e)!==T(n)),b=n.then===void 0?void 0:u.find(e=>T(e)===T(n)&&e.then!==n.then),x=l.kind===`human`?l.every??1:1,S=c!==void 0&&l.kind===`human`&&!m.has(f(l))&&!O.some(e=>x%e===0)?v.find(e=>e.then===l.then):void 0,C=c===void 0?y?`${a} would go from ${T(y)} to ${T(n)}, and could fire ${s}`:b?`${r} would lead on to "${n.then}"${b.then===void 0?``:`, not to "${b.then}"`}${o(b)?`, where it halted the run`:``}${b===l?``:`, and could fire ${s}`}`:`${a} would come into the loop, and could fire ${s}`:S?`a person would be asked every ${S.every??1} rounds where it was every ${x}: on pass ${x} nobody would be asked, and ${a} could fire on a pass where a person was asked`:!g&&c>t&&(m.get(f(l))??-1)>e?`${a} would be moved ahead of ${d(l)}, and could fire on the same pass`:`${a} could fire ${s}, as it could not before`;i.push({why:C,at:k})}let j=r.stops.find(c);for(let e of j?t.loops:[]){let t=e=>e?.back.some(e=>r.back.includes(e)||a.back.includes(e))??!1;if(e.id===r.id||!t(e))continue;let n=g.get(e.id),o=new Set(t(n)?n.stops.map(f):[]),c=t=>D(s,u(e,t.then===void 0?n??r:n))(t);for(let t of e.stops){if(!c(t)||o.has(f(t)))continue;let a=`${w(t)} among its stops, which ${t.then===void 0?`follows that loop's pass edges`:`leads on to "${t.then}"`},`;i.push({why:`the loop "${e.id}" would count rounds that "${r.id}" counts, and ${a} could fire before ${d(j)}`,at:n?[`loop:${e.id}.stops`,`loop:${e.id}.back`]:[`loop:${e.id}`]})}}r.bar&&a.bar?.acceptance!==r.bar.acceptance&&n.push({why:a.bar?`changes the bar's acceptance`:`removes the loop's bar`,at:[`loop:${r.id}.bar`]})}for(let e of r.back){let i=v.get(e);if(!i)continue;let o=f.has(e)?[f.get(e)]:t.edges.filter(e=>e.from===i.from&&e.to===i.to);for(let e of o){if(a?.back.includes(e.id))continue;let i=t.loops.filter(t=>t.back.includes(e.id));n.push({why:i.length===0?`the rounds that "${e.id}" starts would no longer be counted by any loop`:`the rounds that "${e.id}" starts would be counted by ${h(i.map(e=>e.id))}, not against the stops of "${r.id}"`,at:[`loop:${r.id}.back`,`loop:${r.id}`,...i.flatMap(e=>[`loop:${e.id}`,`loop:${e.id}.back`])]})}}let O=new Set(r.members);for(let i of t.loops){if(i.id===r.id)continue;let t=new Set(e.loops.find(e=>e.id===i.id)?.back??[]);for(let e of i.back){let o=f.get(e),s=v.get(e);!o||t.has(e)&&s?.from===o.from&&s.to===o.to||a?.back.includes(e)||!O.has(o.from)||!O.has(o.to)||n.push({why:`a round between "${o.from}" and "${o.to}", which the loop "${r.id}" bounds, would be counted by "${i.id}" and not against its stops`,at:[`loop:${i.id}`,`loop:${i.id}.back`,`edge:${e}`,`edge:${e}.from`,`edge:${e}.to`]})}}let k=a?r.members.filter(e=>o.has(e)&&!a.members.includes(e)):[];a&&r.members.length>0&&!r.members.some(e=>a.members.includes(e))?n.push({why:`the loop "${r.id}" would keep its stops and bound none of the nodes it did`,at:[`loop:${r.id}.members`,`loop:${r.id}.back`]}):k.length>0&&n.push({why:`the loop "${r.id}" would no longer bound ${h(k)}, which ${k.length===1?`is`:`are`} still in the graph`,at:[`loop:${r.id}.members`]});let N=a?r.members.filter(e=>!o.has(e)):[],P=N.length>0?t.nodes.filter(e=>!s.has(e.id)&&!a.members.includes(e.id)&&e.kind!==`stop`&&d.has(e.id)).map(e=>e.id):[];if(P.length>0&&n.push({why:`removes ${h(N)}, which the loop "${r.id}" bounded, while ${h(P)} would come in on a round it does not count: it may be the same step under another name`,at:[...N.map(e=>`node:${e}`),`loop:${r.id}.members`]}),a&&a.stops.some(e=>e.kind===`budget`&&e.measure===`dispatches`)){let e=new Set(t.loops.filter(e=>e.id!==r.id).flatMap(e=>e.back)),i=u.filter(t=>t.edge!==void 0&&!e.has(t.edge)),o=e=>t=>i.filter(n=>e(n)[0]===t).map(t=>e(t)[1]),c=(e,t)=>{let n=new Set(e),r=[...n];for(let e=r.pop();e!==void 0;e=r.pop())for(let i of t(e))n.has(i)||r.push((n.add(i),i));return n},l=c(a.members,o(e=>[e.from,e.to])),d=c(a.members,o(e=>[e.to,e.from])),f=t.nodes.filter(e=>!s.has(e.id)&&(e.kind===`agent`||e.kind===`check`)&&!a.members.includes(e.id)&&l.has(e.id)&&d.has(e.id)).map(e=>e.id);f.length>0&&n.push({why:`${h(f)} would work on the rounds of the loop "${r.id}" and not be among its members: its budget of dispatches would not count ${f.length===1?`it`:`them`}`,at:[...f.map(e=>`node:${e}`),`loop:${r.id}.members`]})}if(a){let i=new Set(c.filter(e=>e.person).map(j)),s=M(e,r,i),l=[...new Set([...r.members.filter(e=>o.has(e)),...a.members])],u=0,d=M(t,{id:r.id,members:l,back:a.back},i),g=r.members.some(e=>[...d.closers.get(e)??[]].some(t=>!s.closers.get(e)?.has(t))),_=e=>e.edge!==void 0&&v.has(e.edge)&&(v.get(e.edge).from!==e.from||v.get(e.edge).to!==e.to),y=g?[...d.ways].filter(([e,t])=>!s.ways.has(e)||_(t)):[];for(let[,i]of y){let a=i.edge===void 0?void 0:v.get(i.edge),o=i.edge===void 0?[]:t.loops.filter(e=>e.back.includes(i.edge)),s=i.edge===void 0?e.loops.find(e=>e.id===i.loop)?.stops:void 0,c=i.edge===void 0?p(s,m.get(i.loop)?.stops)?[]:[`loop:${i.loop}.stops`,`loop:${i.loop}`]:a===void 0?[`edge:${i.edge}`]:[`from`,`to`,`when`].filter(e=>!p(a[e],f.get(i.edge)[e])).map(e=>`edge:${i.edge}.${e}`);c.length!==0&&(u+=1,n.push({why:i.edge===void 0?`a stop of the loop "${i.loop}" would lead back to "${i.to}": a way round the nodes of "${r.id}" that its stops do not count`:`"${i.edge}" (${i.from} → ${i.to}) would make a way round the nodes of "${r.id}" that its stops do not count${o.length>0?`: ${h(o.map(e=>e.id))} would count it, and each time round "${r.id}" starts afresh`:``}`,at:[...c,...o.flatMap(e=>[`loop:${e.id}`,`loop:${e.id}.back`])]}))}g&&u===0&&n.push({why:`there would be a way round the nodes of "${r.id}" that its stops do not count`,at:[`loop:${r.id}.members`,`loop:${r.id}.back`]})}}return{losses:n,fired:i}}function P(e,t){let a=[],o=new Map(t.nodes.map(e=>[e.id,e])),s=new Map(t.edges.map(e=>[e.id,e])),c=new Map(e.edges.map(e=>[e.id,e])),l=new Map(e.nodes.map(e=>[e.id,e]));for(let i of e.nodes){let c=o.get(i.id);if(i.kind===`human-gate`){if(!c)a.push({why:`removes a human gate`,at:[`node:${i.id}`]});else if(c.kind!==`human-gate`)a.push({why:`a human gate becomes another kind of node`,at:[`node:${i.id}.kind`]});else{let e=(i.options??[]).filter(e=>!(c.options??[]).includes(e));e.length>0&&a.push({why:`the gate would no longer offer ${h(e)}`,at:[`node:${i.id}.options`],gain:!0})}}if(g(i).length>0){let e=g(i).filter(e=>!g(c).includes(e));c?e.length>0&&a.push({why:`removes the irreversible marker ${h(e)}`,at:[`node:${i.id}.irreversible`,`node:${i.id}.kind`]}):a.push({why:`removes a node marked irreversible (${g(i).join(`, `)}): what takes its place carries no such mark unless it is given one`,at:[`node:${i.id}`],gain:!0})}if(i.kind===`stop`&&i.outcome===`halt`&&c?.kind===`stop`&&F(c)&&a.push({why:`the stop "${i.id}" would end in success where it halted: what led there to stop the run would now end it well`,at:[`node:${i.id}.outcome`]}),i.kind===`check`){let e=t.nodes.filter(e=>e.kind===`check`&&l.get(e.id)?.kind!==`check`),n=e.map(e=>`"${e.id}": ${e.check.run===void 0?`of kind "${e.check.kind}"`:`runs ${JSON.stringify(e.check.run)}`}, passes on ${JSON.stringify(e.check.pass)}${e.check.threshold===void 0?``:`, threshold ${e.check.threshold}`}`).join(`, and `),r=`while ${e.length===1?`a check`:`checks`} the graph has not ${e.length===1?`comes`:`come`} in (${n}): if that is this check under another id, allowing this`;if(!c&&e.length>0)a.push({why:`removes a check, ${r} name allows every change made to it and every way round it`,at:[`node:${i.id}`],swap:`removes a check`});else if(!c)a.push({why:`removes a check`,at:[`node:${i.id}`]});else if(c.kind!==`check`&&e.length>0)a.push({why:`a check becomes another kind of node, ${r} change allows every change made to it and every way round it`,at:[`node:${i.id}.kind`,`node:${i.id}.check`],swap:`a check becomes another kind of node`});else if(c.kind!==`check`)a.push({why:`a check becomes another kind of node`,at:[`node:${i.id}.kind`,`node:${i.id}.check`]});else{let[e,t]=[i.check,c.check],n=[...new Set([...Object.keys(e),...Object.keys(t)])].filter(n=>!p(e[n],t[n]));n.length>0&&a.push({why:`changes the check's definition (${n.join(`, `)}): what it runs and what counts as a pass may be tightened and not loosened, and a program cannot tell which this is`,at:[`node:${i.id}.check`]})}}if(r(i)){c?r(c)||a.push({why:c.kind===`agent`?`a critic is given another role`:`a critic becomes another kind of node`,at:[`node:${i.id}.role`,`node:${i.id}.kind`]}):a.push({why:`removes a critic`,at:[`node:${i.id}`]});let u=e=>e.edges.filter(e=>e.to===i.id),d=new Set(e.edges.map(e=>e.id));for(let n of c?u(e):[]){let e=s.get(n.id),r=new Set(t.edges.filter(e=>e.from===n.from&&!l.has(e.to)).map(e=>e.to)),c=e&&e.from===n.from&&e.to===i.id?[e]:u(t).filter(e=>!d.has(e.id)&&(!o.has(n.from)||e.from===n.from||r.has(e.from))),f=new Set(c.flatMap(e=>e.evidence??[])),p=(n.evidence??[]).filter(e=>!f.has(e));p.length>0&&a.push({why:`the critic would no longer be handed ${h(p)} by "${n.from}"`,at:[`edge:${n.id}.evidence`,`edge:${n.id}.to`,`edge:${n.id}.from`,`edge:${n.id}`,`node:${n.from}`]})}for(let r of u(t)){let t=e.edges.find(e=>e.id===r.id);n(r)===`shared`&&!(t&&t.to===i.id&&n(t)===`shared`)&&a.push({why:`the critic would share its builder's context`,at:[`edge:${r.id}.isolation`,`edge:${r.id}.to`,`edge:${r.id}`]})}}}for(let n of e.edges){let e=s.get(n.id);if(n.approval===!0){e?e.approval!==!0&&a.push({why:`removes a person's approval from the edge`,at:[`edge:${n.id}.approval`]}):a.push({why:`removes an edge that needs a person's approval`,at:[`edge:${n.id}`,`node:${n.from}`,`node:${n.to}`]});for(let r of e?t.edges:[]){if(r.id===n.id||r.from!==e.from||r.to!==e.to||r.approval===!0)continue;let t=c.get(r.id),i=t===void 0?[`edge:${r.id}`]:[`from`,`to`,`approval`].filter(e=>!p(t[e],r[e])).map(e=>`edge:${r.id}.${e}`);i.length>0&&a.push({why:`"${r.id}" would lead from "${r.from}" to "${r.to}" beside "${n.id}", which needs a person's approval, and need none`,at:i})}}let u=l.get(n.from);u?.kind===`human-gate`&&o.get(n.from)?.kind===`human-gate`&&!t.edges.some(e=>e.from===n.from&&i(e)===i(n))&&a.push({why:`"${i(n)}" at the human gate "${n.from}" would lead nowhere`,at:[`edge:${n.id}`,`edge:${n.id}.from`,`edge:${n.id}.when`,`node:${n.to}`],gain:!0}),e&&i(e)!==i(n)&&(n.approval===!0||u?.kind===`human-gate`?a.push({why:`changes what a person's answer leads to`,at:[`edge:${n.id}.when`]}):u&&r(u)&&a.push({why:`changes what the critic's verdict leads to`,at:[`edge:${n.id}.when`]}))}let u=new Map((t.policies??[]).map(e=>[e.id,e]));for(let t of e.policies??[]){let e=t.kind===`critic-isolation`?`removes critic isolation`:t.kind===`no-self-grading`?`lets a node grade its own work`:t.kind===`no-live-graph-rewrite`?`lets a run rewrite the graph where it could only propose`:void 0,n=u.get(t.id),r=n?[`kind`,`scope`,`params`].filter(e=>!p(n[e],t[e])):[];e===void 0||n&&r.length===0||a.push({why:e,at:n?r.map(e=>`policy:${t.id}.${e}`):[`policy:${t.id}`]})}return a}var F=e=>e.kind===`stop`&&(e.outcome??`success`)===`success`;function I(e,t,n){let r=new Map;for(let e of t)s(e,n)||(r.get(e.to)??r.set(e.to,[]).get(e.to)).push(e.from);let i=new Set(e.nodes.filter(F).map(e=>e.id)),a=[...i];for(let e=a.pop();e!==void 0;e=a.pop())for(let t of r.get(e)??[])i.has(t)||(i.add(t),a.push(t));return i}function L(e,t){let n=[],r=new Set(e.nodes.map(e=>e.id)),o=new Set(t.nodes.map(e=>e.id)),m=u(t,`every`);for(let e of t.nodes)!r.has(e.id)&&g(e).length>0&&m.has(e.id)&&n.push({why:`adds an irreversible step that a run reaches without a person`,at:[`node:${e.id}`]});let _=new Map(e.edges.map(e=>[e.id,e])),v=new Map(t.edges.map(e=>[e.id,e])),y=new Map(e.loops.map(e=>[e.id,e])),b=new Map(t.loops.map(e=>[e.id,e])),x=new Set(c(t)),S=new Set(e.loops.flatMap(e=>e.back)),C=a(t),w=a(e),T=new Set,E=new Set,D=new Map,O=t=>D.get(t)??D.set(t,l(e,[t])).get(t),k=[],A=(e,t,r)=>{let i=`${e!==`every`&&`critic`in e?e.critic:``}\n${t}\n${r.at.join(` `)}`;E.has(i)||(E.add(i),n.push(r))};for(let a of d(e,t)){let c=u(e,a),d=u(t,a),m=`that does not pass ${f(a)}`,g=`${a!==`every`&&`critic`in a?a.critic:``}\n`,D=e.nodes.filter(e=>!o.has(e.id)&&!c.has(e.id)&&!T.has(g+e.id)),j=t.nodes.filter(e=>!r.has(e.id)&&d.has(e.id));if(j.length>0)for(let e of D)T.add(g+e.id),n.push({why:`removes "${e.id}", which a run reached only by passing ${f(a)}, while ${h(j.map(e=>e.id))} would come in with no such need: it may be the same step under another name`,at:[`node:${e.id}`]});let M=0,N=e=>{if(e.edge!==void 0){let t=_.get(e.edge);if(!t)return[`edge:${e.edge}`];let n=[`from`,`to`,`approval`,`when`].filter(n=>!p(t[n],v.get(e.edge)[n]));return n.length>0?n.map(t=>`edge:${e.edge}.${t}`):w.some(t=>t.edge===e.edge&&s(t,a))?[`node:${e.from}.kind`,`node:${e.from}.role`]:void 0}let t=y.get(e.loop);if(!t)return[`loop:${e.loop}`];let n=[`stops`,`members`].filter(n=>!p(t[n],b.get(e.loop)[n]));return n.length>0?n.map(t=>`loop:${e.loop}.${t}`):void 0},P=(e,t)=>{M+=1,A(a,e,t)},L=new Set(t.nodes.filter(e=>r.has(e.id)&&!c.has(e.id)&&d.has(e.id)).map(e=>e.id));for(let e of L.size>0?C:[]){if(s(e,a)||!d.has(e.from)||!L.has(e.to))continue;let t=N(e);t&&(e.edge===void 0?P(e.to,{why:`a stop of the loop would lead on to "${e.to}", a way ${m}`,at:t}):P(e.to,{why:`${_.has(e.edge)?`opens`:`adds`} a way into "${e.to}" ${m}`,at:t}))}let R=a===`every`||!(`when`in a)||a.when===void 0,z=a===`every`?void 0:`gate`in a?a.gate:`critic`in a?a.critic:void 0;for(let n of R?t.nodes:[]){if(!r.has(n.id)||n.id===z)continue;let i=l(e,[n.id],a),o=l(t,[n.id],a),c=new Set([...o].filter(e=>r.has(e)&&!i.has(e)&&O(n.id).has(e)));for(let e of c.size>0?C:[]){if(e.from===e.to||s(e,a)||!o.has(e.from)||!c.has(e.to))continue;let t=N(e);if(!t)continue;let n=e.edge===void 0?`a stop of the loop would lead on from "${e.from}" to "${e.to}", a way ${m}`:`${_.has(e.edge)?`opens`:`adds`} a way from "${e.from}" to "${e.to}" ${m}`;k.push([a,e.to,{why:n,at:t}])}}for(let n of L){if(!x.has(n))continue;let r=`nothing would lead to "${n}", so a run would start there, where every way to it passed ${f(a)}`;for(let i of e.edges){if(i.to!==n||S.has(i.id))continue;let e=v.get(i.id);e&&e.to!==n?P(`start ${n}`,{why:r,at:[`edge:${i.id}.to`]}):e?P(`start ${n}`,{why:r,at:t.loops.filter(e=>e.back.includes(i.id)).flatMap(e=>[`loop:${e.id}.back`,`loop:${e.id}`])}):P(`start ${n}`,{why:r,at:[o.has(i.from)?`edge:${i.id}`:`node:${i.from}`]})}}let B=typeof a==`object`&&`critic`in a&&a.when!==void 0?new Set(e.edges.filter(e=>e.from===a.critic).map(i)):new Set,V=B.size>1&&!B.has(`pass`),H=R||V||typeof a==`object`&&`critic`in a&&a.when===`pass`,U=H?I(e,w,a):new Set,W=H?I(t,C,a):new Set,G=new Set(t.nodes.filter(e=>e.kind!==`stop`&&r.has(e.id)&&!U.has(e.id)&&W.has(e.id)).map(e=>e.id));for(let e of G.size>0?C:[]){if(s(e,a)||!G.has(e.from)||!W.has(e.to))continue;let t=N(e),n=`${a!==`every`&&`critic`in a?a.critic:``}\n`;t&&![...E].some(e=>e.startsWith(n)&&e.endsWith(`\n${t.join(` `)}`))?P(`ends ${e.to}`,{why:`adds a way from "${e.from}" to end in success ${m}`,at:t}):t&&(M+=1)}let K=new Set(e.nodes.filter(F).map(e=>e.id));for(let e of G.size>0?t.nodes:[])F(e)&&r.has(e.id)&&!K.has(e.id)&&W.has(e.id)&&P(`ends ${e.id}`,{why:`a run could end in success at "${e.id}", a way ${m}`,at:[`node:${e.id}.outcome`,`node:${e.id}.kind`]});M===0&&(L.size>0||G.size>0)&&n.push({why:L.size>0?`a run would reach ${h([...L])} by a way ${m}`:`a run could end in success from ${h([...G])} by a way ${m}`,at:[]})}return{losses:n,later:k.map(([,,e])=>e)}}function R(e,t){let n=[],r=new Set(a(e).filter(e=>e.person).map(j)),i=new Set(a(t).filter(e=>e.person).map(j)),o=new Set(t.nodes.map(e=>e.id)),s=new Set(t.nodes.filter(e=>e.kind===`human-gate`).map(e=>e.id));for(let a of e.loops){let c=t.loops.find(e=>e.id===a.id);if(!c||!(a.stops.some(_)||a.bar!==void 0))continue;let l={id:a.id,members:[...new Set([...a.members.filter(e=>o.has(e)),...c.members])],back:c.back},u=M(e,a,r),d=[...M(t,l,i).ways].filter(([e,t])=>t.person&&!r.has(e)&&!u.ways.has(e));if(d.length===0)continue;let f=[...new Set(d.map(([,e])=>e.edge===void 0?`the stop where a person is asked, which continues at "${e.to}"`:s.has(e.from)?`"${e.when}" at the human gate "${e.from}" (${e.edge})`:`the approval asked on "${e.edge}"`))],p=[...S(t,[c])].filter(([e])=>e!==`human`).map(([,e])=>`${e.name} (${b(e.halt??e.any,e.unit)})`);n.push(`the loop "${a.id}": ${p.length>0?p.join(` and `):`its stops`} would count the rounds between two of a person's decisions, and no longer the whole run. A way round its nodes that they do not count is opened each time by ${f.join(`, and by `)}`)}return n}function z(e,t){let n=[],r=`a program cannot tell which way this goes, so it is held either way, and an honest change (a gate put behind the check's pass, more evidence handed to a builder) costs one --allow too, the price of a rule a program can apply`,a=new Set(e.nodes.filter(e=>e.kind===`check`&&t.nodes.some(t=>t.id===e.id&&t.kind===`check`)).map(e=>e.id)),o=new Set(t.nodes.map(e=>e.id)),s=new Map(e.edges.map(e=>[e.id,e])),c=new Map(t.edges.map(e=>[e.id,e]));for(let t of e.edges){if(!a.has(t.from))continue;let e=c.get(t.id);if(!e){n.push({why:`removes "${t.id}", an edge that leaves the check "${t.from}": ${r}`,at:[o.has(t.to)?`edge:${t.id}`:`node:${t.to}`],either:!0});continue}for(let a of new Set([...Object.keys(t),...Object.keys(e)])){let o=a===`when`?i(t)!==i(e):!p(t[a],e[a]);a!==`id`&&o&&n.push({why:`changes "${t.id}", an edge that leaves the check "${t.from}" (${a}): ${r}`,at:[`edge:${t.id}.${a}`],either:!0})}}for(let e of t.edges){if(!a.has(e.from))continue;let t=s.get(e.id);t?t.from!==e.from&&n.push({why:`moves "${e.id}" to leave the check "${e.from}": ${r}`,at:[`edge:${e.id}.from`],either:!0}):n.push({why:`adds "${e.id}", an edge that leaves the check "${e.from}": ${r}`,at:[`edge:${e.id}`],either:!0})}return n}function B(e,t){let n=[],i=new Map(e.nodes.map(e=>[e.id,e])),a=new Map(e.loops.map(e=>[e.id,e])),o=e=>e?.stops.some(e=>e.kind===`bar-passed`)??!1;for(let e of t.loops){let s=a.get(e.id),c=e=>i.get(e),l=e.members.filter(e=>c(e)?.kind===`check`&&t.nodes.some(t=>t.id===e&&t.kind===`check`)),u=s?.members.some(e=>c(e)!==void 0&&r(c(e))&&t.nodes.some(t=>t.id===e&&r(t)))??!1;if(l.length===0||u)continue;let d=s?`the loop "${e.id}", which the check ${h(l)} judges with no critic`:`the new loop "${e.id}", around the check ${h(l)}`;e.bar!==void 0&&s?.bar===void 0&&n.push({why:`gives ${d}, a bar of its own: the lead would stop on the bar's words, a way out that does not pass the check`,at:s?[`loop:${e.id}.bar`]:[`loop:${e.id}`]}),o(e)&&!o(s)&&n.push({why:`adds a stop on "bar passed" to ${d}: a way out that does not pass the check`,at:s?[`loop:${e.id}.stops`]:[`loop:${e.id}`]})}return n}function V(e,t){let n=new Set,i=(e,t)=>e.nodes.some(e=>e.id===t&&r(e)),a=new Map(t.edges.map(e=>[e.id,e]));for(let r of e.edges){let o=a.get(r.id);if(!o)continue;r.approval!==!0&&o.approval===!0&&n.add(`edge:${r.id}.approval`);let[s,c]=[r.evidence??[],o.evidence??[]];o.to===r.to&&i(e,r.to)&&i(t,r.to)&&s.every(e=>c.includes(e))&&n.add(`edge:${r.id}.evidence`)}return n}function H(e,t){let n=new Set,r=new Set(e.nodes.filter(e=>e.kind===`stop`&&e.outcome===`halt`).map(e=>e.id)),i=e=>e.kind===`bar-passed`||e.then!==void 0&&!r.has(e.then);for(let r of e.loops){let e=t.loops.find(e=>e.id===r.id);if(!e)continue;let a=new Map;e.stops.forEach((e,t)=>void(a.get(JSON.stringify(e))??a.set(JSON.stringify(e),[]).get(JSON.stringify(e))).push(t));let o=new Set(a.keys()),s=r.stops.map(e=>a.get(JSON.stringify(e))?.shift()),c=1/0,l=!1;for(let e=r.stops.length-1;e>=0;--e){let t=s[e];l||=i(r.stops[e])&&(t===void 0?!o.has(JSON.stringify(r.stops[e])):t>c),t!==void 0&&(c=Math.min(c,t))}l&&n.add(`loop:${r.id}.stops`)}return n}function U(e,t){let n=H(e,t);return n.size===0?W(e,t):W(e,t).map(e=>e.at.some(e=>n.has(e))?{...e,gain:!0}:e)}function W(e,t){let n=[...G(e,t),...B(e,t)],r=z(e,t);if(r.length===0)return n;let i=new Set(n.flatMap(e=>e.at)),a=V(e,t);return[...n,...r.filter(e=>!(a.has(e.at[0])&&!i.has(e.at[0])))]}function G(e,t){let n=new Set,r=L(e,t),i=N(e,t),a=P(e,t),o=[...a,...i.losses,...r.losses],s=new Set(o.flatMap(e=>e.at)),c=new Set,l=r.later.filter(e=>!e.at.some(e=>s.has(e))&&!c.has(e.at.join(` `))&&c.add(e.at.join(` `)));return[...a,...i.losses,...i.fired,...r.losses,...l].filter(e=>{let t=`${e.why}\n${e.at.join(` `)}`;return!n.has(t)&&(n.add(t),!0)})}var K=e=>JSON.stringify(e),q=[`fixed`,`propose`,`adaptive`],J=new Set([`grooph`,`id`,`name`,`version`,`lineage`,`notes`,`layout`,`nodes`,`edges`,`loops`,`policies`,`groups`]);function Y(e,t){let n=[],r=[[`node`,e.nodes,t.nodes],[`edge`,e.edges,t.edges],[`loop`,e.loops,t.loops],[`policy`,e.policies??[],t.policies??[]],[`group`,e.groups??[],t.groups??[]]];for(let[e,t,i]of r){let r=new Map(i.map(e=>[e.id,e])),a=new Set(t.map(e=>e.id));for(let i of t){let t=r.get(i.id);if(!t){n.push({name:`${e}:${i.id}`,kind:`remove`});continue}for(let r of new Set([...Object.keys(i),...Object.keys(t)]))r!==`id`&&K(i[r])!==K(t[r])&&n.push({name:`${e}:${i.id}.${r}`,kind:`change`})}for(let t of i)a.has(t.id)||n.push({name:`${e}:${t.id}`,kind:`add`})}let i=e,a=t;for(let e of new Set([...Object.keys(i),...Object.keys(a)]))!J.has(e)&&K(i[e])!==K(a[e])&&n.push({name:`graph:${e}`,kind:`change`});return n}function ee(e,n){let[r,i]=[t(e),t(n)];return q.indexOf(i)<=q.indexOf(r)?[]:[{why:`the adaptation level would go from "${r}" to "${i}": the lead may change more of the graph during a run`,at:K(e.adaptation)===K(n.adaptation)?[]:[`graph:adaptation`]}]}var X=(e,t)=>[...U(e,t),...ee(e,t)];function Z(e,t,n={}){let r=Y(e,t),i=new Set(r.map(e=>e.name)),a=(e,t,n)=>{for(let a of e){if(t!==`loosens`&&a.either)continue;let e=new Set(a.at.filter(e=>i.has(e)));(e.size!==0||n)&&(r=r.map(n=>e.size>0&&!e.has(n.name)||m(n[t],a.why)||t!==`loosens`&&(m(n.loosens,a.why)||n.kind===`add`&&n.name.startsWith(`loop:`))?n:{...n,[t]:n[t]===void 0?a.why:`${n[t]}; ${a.why}`}))}},o=X(e,t);a(o,`loosens`,!0);let s=X(t,e),c=o.some(e=>e.swap);c?a(s.map(e=>e.swap?{...e,why:e.swap}:e),`unjudged`,!1):(a(s.filter(e=>!e.gain),`tightens`,!1),a(s.filter(e=>e.gain),`unjudged`,!1)),r.sort((e,t)=>Number(t.loosens!==void 0)-Number(e.loosens!==void 0));let l=new Set(n.allow??[]);return{changes:r,refused:r.filter(e=>e.loosens!==void 0&&!l.has(e.name)),unknown:[...l].filter(e=>!i.has(e)),notices:R(e,t),swapped:c}}function te(e,t,n){let r=e=>/^[A-Za-z0-9_.:/@=+-]+$/.test(e)?e:`'${e.replace(/'/g,`'\\''`)}'`;return[`grooph`,`adopt`,r(e),...n===void 0?[]:[`--into`,r(n)],`--write`,...t.flatMap(e=>[`--allow`,r(e)])].join(` `)}var Q=e(),ne=e=>()=>void navigator.clipboard?.writeText(e).catch(()=>void 0),$=e=>e?.scrollIntoView({block:`start`});function re(e,t,n){if(!n)return(0,Q.jsx)(`p`,{className:`field-hint`,"data-brakes":`not-compared`,ref:$,children:`Its brakes were not compared with the graph's: the copy is not a valid graph. Open the copy to see why before you use it.`});let r=Z(e,t);if(r.refused.length+r.notices.length===0)return null;let i=r.notices.map(e=>(0,Q.jsxs)(`p`,{"data-brakes":`note`,children:[`Note: `,e]},e));return r.refused.length===0?(0,Q.jsx)(`div`,{className:`field-hint`,"data-brakes":`said`,ref:$,children:i}):(0,Q.jsxs)(`div`,{className:`refusal-hint`,"data-brakes":`proposed`,ref:$,children:[(0,Q.jsxs)(`p`,{children:[(0,Q.jsx)(`strong`,{children:`This copy loosens a brake the graph has.`}),` It is the run's working copy with this proposal applied; either may have done it, and it is yours to allow or not: read each line before you use the copy.`]}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`loosens`,children:r.refused.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` `,e.loosens]},e.name))}),i]})}function ie(e,t,n){let r=Z(e,t),i=r.changes.filter(e=>e.tightens!==void 0&&e.loosens===void 0),a=r.changes.filter(e=>e.unjudged!==void 0&&e.loosens===void 0),o=te(`.grooph/${e.id}/runs/${n}`,r.refused.map(e=>e.name)),s=(0,Q.jsxs)(Q.Fragment,{children:[i.length>0?(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`p`,{children:r.refused.length>0?`It also tightens a brake:`:`It tightens a brake:`}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`tightens`,children:i.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` undoing it: `,e.tightens]},e.name))})]}):null,a.length>0?(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`p`,{children:r.swapped?`With a check removed in this copy, no change is called a tightening. If the check that comes in is the same one under another id, these may be built around it:`:`An answer a gate did not give, a step marked irreversible that the graph did not have, or a stop of a loop that leads on, where it is new, changed or put ahead, lets a person or a run do what it could not before. A change that brings one is named here and not called a tightening, whatever else it does:`}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`unjudged`,children:a.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` undoing it: `,e.unjudged]},e.name))})]}):null,r.notices.map(e=>(0,Q.jsxs)(`p`,{"data-brakes":`note`,children:[`Note: `,e]},e))]});return r.refused.length===0?{ok:!0,view:i.length+a.length+r.notices.length>0?(0,Q.jsx)(`div`,{className:`field-hint`,"data-brakes":`said`,children:s}):null}:{ok:!1,view:(0,Q.jsxs)(`div`,{className:`refusal`,role:`alert`,"data-brakes":`refused`,children:[(0,Q.jsxs)(`p`,{children:[(0,Q.jsx)(`strong`,{children:`Not adopted: this working copy loosens a brake.`}),` A run may tighten a brake and never loosen one. Nothing was saved.`]}),(0,Q.jsx)(`ul`,{className:`brakes-list`,"data-brakes":`loosens`,children:r.refused.map(e=>(0,Q.jsxs)(`li`,{"data-change-name":e.name,children:[(0,Q.jsx)(`span`,{className:`mono`,children:e.name}),` `,e.loosens]},e.name))}),(0,Q.jsx)(`p`,{children:`To adopt it on purpose, run this in the project's folder. It names each change above:`}),(0,Q.jsx)(`pre`,{className:`issue-lines`,"data-brakes":`command`,children:o}),(0,Q.jsx)(`button`,{type:`button`,className:`btn`,onClick:ne(o),children:`Copy the command`}),s]})}}export{ie as judge,re as loosened};
|