grooph 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -31
- package/THIRD-PARTY-NOTICES.md +5 -1
- package/dist/app/assets/App-CT9KxzfQ.css +1 -0
- package/dist/app/assets/App-D1pDFbEY.js +5 -0
- package/dist/app/assets/EmbedApp-CTausQWY.js +1 -0
- package/dist/app/assets/ExportPanel-CbRH4C69.js +8 -0
- package/dist/app/assets/Import-DF0XLxRI.js +1 -0
- package/dist/app/assets/SketchView-BjeUHG4X.js +143 -0
- package/dist/app/assets/brakes-B9b3hDX8.js +1 -0
- package/dist/app/assets/{builtins-Cbs5iQtH.js → builtins-DzyPaYdd.js} +1 -1
- package/dist/app/assets/{compile-BAvi-rd0.js → compile-DL2budwP.js} +8 -8
- package/dist/app/assets/{front-BRl7rl-u.js → front-OxfL-OaD.js} +1 -1
- package/dist/app/assets/full-C0asYORc.js +1 -0
- package/dist/app/assets/graph-more-Dn_hNa20.js +2 -0
- package/dist/app/assets/graph-stage-CwNePnN4.js +4 -0
- package/dist/app/assets/graph-views-CmkQ41zC.js +2 -0
- package/dist/app/assets/{index-BoSi6XYh.js → index-B5ZkSF4L.js} +2 -2
- package/dist/app/assets/mermaid-read-cyqJ32v-.js +17 -0
- package/dist/app/assets/{plan-templates-BQu8G2sX.js → plan-templates-u2fF3GnS.js} +1 -1
- package/dist/app/assets/runs-BA5HKtsx.js +1 -0
- package/dist/app/assets/screens-CMMuexid.js +16 -0
- package/dist/app/assets/share-DV3wsAsJ.js +8 -0
- package/dist/app/assets/site-looks.v1.css +223 -0
- package/dist/app/assets/space-Cuy4YqyZ.js +1 -0
- package/dist/app/assets/styles-Dlp-yYlE.css +1 -0
- package/dist/app/assets/templates-DbAhWvP6.js +2 -0
- package/dist/app/assets/{themes-DtOBrLk0.js → themes-C34TrvOJ.js} +1 -1
- package/dist/app/assets/{units-DRaa5U2m.js → units-DlniUjfH.js} +1 -1
- package/dist/app/assets/{views-DCEDX6Qx.js → views-CFqRShXD.js} +2 -1
- package/dist/app/grooph-app.json +1 -1
- package/dist/app/index.html +14 -11
- package/dist/app/llms.txt +6 -7
- package/dist/app/manifest.webmanifest +1 -1
- package/dist/app/og.png +0 -0
- package/dist/app/routes.json +42 -33
- package/dist/app/sw.js +7 -2
- package/dist/browser/grooph.d.ts +44 -0
- package/dist/browser/grooph.global.js +7 -0
- package/dist/browser/grooph.js +7 -0
- package/dist/bundle/grooph.js +7082 -2606
- package/hooks/grooph-event.mjs +163 -14
- package/package.json +14 -6
- package/dist/app/assets/App-CFO6bPna.js +0 -5
- package/dist/app/assets/App-Cv1auMeh.css +0 -1
- package/dist/app/assets/EmbedApp-B5LWao3x.js +0 -1
- package/dist/app/assets/ExportPanel-VWus7GM3.js +0 -8
- package/dist/app/assets/Import-YEKofx4_.js +0 -1
- package/dist/app/assets/brakes-9E9PsV_Z.js +0 -1
- package/dist/app/assets/graph-more-BKW9C4-h.js +0 -2
- package/dist/app/assets/graph-stage-CWh3OWga.js +0 -4
- package/dist/app/assets/graph-views-tFUJK-be.js +0 -2
- package/dist/app/assets/runs-DcjRi7S6.js +0 -1
- package/dist/app/assets/screens-YUd2HaLm.js +0 -16
- package/dist/app/assets/share-BzIzB4EY.js +0 -8
- package/dist/app/assets/space-DWgrlnfB.js +0 -1
- package/dist/app/assets/styles-BA1aVO9R.css +0 -1
- package/dist/app/assets/templates-DvzLa5sE.js +0 -2
- package/dist/app/demo/run.txt +0 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import{gn as e,pn as t}from"./share-DV3wsAsJ.js";var n=`flowchart, graph and agentflow-beta text: nodes with their shapes and labels, edges with their labels, subgraphs and flows, @{ … } metadata, and %% comments (style, class and click lines are read and left out)`,r=class extends Error{line;constructor(e,t){super(e),this.line=t}},i={quot:`"`,lt:`<`,gt:`>`,amp:`&`,apos:`'`,nbsp:` `},a=e=>e.replace(/#(\d+|[a-z]+);/gi,(e,t)=>{if(/^\d+$/.test(t))return String.fromCodePoint(Math.min(Number(t),1114111));let n=t.toLowerCase();return Object.hasOwn(i,n)?i[n]:e});function o(e){let t=e.trim();return t.length>=2&&t.startsWith(`"`)&&t.endsWith(`"`)&&(t=t.slice(1,-1)),t.length>=2&&t.startsWith("`")&&t.endsWith("`")&&(t=t.slice(1,-1)),a(t.replace(/<br\s*\/?>/gi,`
|
|
2
|
+
`)).split(`
|
|
3
|
+
`).map(e=>e.replace(/\s+/g,` `).trim()).filter(e=>e!==``).join(`
|
|
4
|
+
`)}var s=/[\p{L}\p{N}_]+(?:[-.][\p{L}\p{N}_]+)*/uy;function c(e,t,n){return e.lastIndex=n,e.exec(t)}var l={text:1e6,statementLines:100,middleLabel:2e3,nodes:5e3,edges:2e4,boxes:1e3,depth:100},u=[[`(((`,[[`)))`,`double-circle`]]],[`((`,[[`))`,`circle`]]],[`([`,[[`])`,`stadium`]]],[`[[`,[[`]]`,`subroutine`]]],[`[(`,[[`)]`,`cylinder`]]],[`{{`,[[`}}`,`hexagon`]]],[`[/`,[[`\\]`,`trapezoid`],[`/]`,`lean-right`]]],[`[\\`,[[`/]`,`inv-trapezoid`],[`\\]`,`lean-left`]]],[`[`,[[`]`,`rect`]]],[`(`,[[`)`,`round`]]],[`{`,[[`}`,`diamond`]]],[`>`,[[`]`,`asymmetric`]]]];function d(e,t,n=!1){for(let r=t+1;r<e.length;r++)if(n&&e[r]===`\\`)r++;else if(e[r]===`"`)return r+1;return e.length}function f(e,t=()=>{}){let n=0,r=0,i=!1;for(let a=0;a<e.length;a++){let o=e[a];if(o===`"`){let t=d(e,a,n>0);if(t===e.length&&(e[t-1]!==`"`||t-1===a))return!0;a=t-1}else n>0?o===`{`?n++:o===`}`&&n--:o===`@`&&e[a+1]===`{`?(n=1,a++):o===`|`&&r===0&&(i||/[->=.ox]\s*$/.test(e.slice(Math.max(0,a-24),a)))?i=!i:i||(`[({`.includes(o)?r++:`])}`.includes(o)&&(r=Math.max(0,r-1)),t(o,a,r))}return n>0}function p(e,t,n){for(let[n,r]of u){if(!e.startsWith(n,t))continue;let i=t+n.length;for(;e[i]===` `;)i++;if(e[i]===`"`){let t=d(e,i),n=t;for(;e[n]===` `;)n++;let a=r.find(([t])=>e.startsWith(t,n));if(a)return{shape:a[1],label:e.slice(i,t),end:n+a[0].length};continue}let a;for(let[i,o]of r){let r=e.indexOf(i,t+n.length);r>=0&&(!a||r<a.end)&&(a={shape:o,end:r,close:i})}if(a)return{shape:a.shape,label:e.slice(t+n.length,a.end),end:a.end+a.close.length}}if(t<e.length&&`[({>`.includes(e[t]))throw new r(`a node's brackets that do not close: ${x(e.slice(t))}`,n)}function m(e,t){let n={n:`
|
|
5
|
+
`,t:` `,r:`\r`,b:`\b`,f:`\f`,0:`\0`,a:`\x07`,v:`\v`,e:`\x1B`," ":` `,"/":`/`,'"':`"`,"\\":`\\`,N:`
`,_:`\xA0`,L:`\u2028`,P:`\u2029`},r=``,i=t+1;for(;i<e.length&&e[i]!==`"`;i++){if(e[i]!==`\\`){r+=e[i];continue}let t=e[++i]??``,a=t===`x`?2:t===`u`?4:t===`U`?8:0;if(a>0){let t=/^[0-9a-fA-F]+$/.test(e.slice(i+1,i+1+a))?parseInt(e.slice(i+1,i+1+a),16):65533;r+=String.fromCodePoint(Math.min(t,1114111)),i+=a}else r+=Object.hasOwn(n,t)?n[t]:t}return{value:r,end:i+1}}function h(e,t){let n=new Map,i=0,a=()=>{for(;i<e.length&&/[\s,]/.test(e[i]);)i++};for(;;){if(a(),i>=e.length)return n;let o=c(/([A-Za-z_][\w-]*)\s*:/y,e,i);if(!o)throw new r(`metadata it cannot read: ${x(e.slice(i))}`,t);for(i+=o[0].length;e[i]===` `||e[i]===` `;)i++;let s,l=c(/([|>])[+-]?[ \t]*\n/y,e,i);if(l){let t=e.lastIndexOf(`
|
|
6
|
+
`,i-o[0].length)+1,n=/^[ \t]*/.exec(e.slice(t))[0].length;i+=l[0].length;let r=[],a=-1;for(;i<e.length;){let t=e.indexOf(`
|
|
7
|
+
`,i)<0?e.length:e.indexOf(`
|
|
8
|
+
`,i),o=e.slice(i,t),s=/^[ \t]*/.exec(o)[0].length;if(o.trim()!==``&&s<=n)break;o.trim()!==``&&a<0&&(a=s),r.push(o.slice(Math.min(s,Math.max(a,0)))),i=t+1}for(;r.length>0&&r[r.length-1].trim()===``;)r.pop();s=l[1]===`|`?r.join(`
|
|
9
|
+
`):r.join(` `).replace(/\s+/g,` `).trim()}else if(e[i]===`"`){let t=m(e,i);s=t.value,i=t.end}else if(e[i]===`'`){let t=``,n=i+1;for(;n<e.length;n++)if(e[n]===`'`&&e[n+1]===`'`)t+=`'`,n++;else if(e[n]===`'`)break;else t+=e[n];s=t,i=n+1}else if(e[i]===`{`||e[i]===`[`){let t=i,n=0;for(;i<e.length;i++)if(e[i]===`"`)i=d(e,i,!0)-1;else if(e[i]===`{`||e[i]===`[`)n++;else if((e[i]===`}`||e[i]===`]`)&&(n--,n===0)){i++;break}s=e.slice(t,i)}else{let t=c(/[^,\n]*/y,e,i);s=t[0].trim(),i+=t[0].length}[`__proto__`,`constructor`,`prototype`].includes(o[1])||n.set(o[1],s)}}function g(e,t,n){let i=0;for(let r=t;r<e.length;r++)if(e[r]===`"`)r=d(e,r,!0)-1;else if(e[r]===`{`)i++;else if(e[r]===`}`&&(i--,i===0))return{meta:h(e.slice(t+1,r),n),end:r+1};throw new r(`a @{ block that does not close`,n)}var _=/[<xo]?((?:-{2,}|={2,})>|(?:-{2,}|={2,})[xo]|-{3,}|={3,}|-\.+-(?:>|[xo])?|~{3,})/y,v=/[<xo]?(--|==|-\.)/y,y=/(-{2,}>|-{3,}|\.-+>|\.-+|={2,}>|={3,}|-{2,}[xo]|={2,}[xo])(?=[\s\p{L}\p{N}_"]|$)/uy;function b(e,t,n,r){let i=c(/([\p{L}\p{N}_]+)@(?=[-=.<xo~])/uy,e,t);i&&r.add(i[1]);let a=t+(i?i[0].length:0),o=(e,t,r,i)=>({...r===void 0?{}:{label:r},dotted:e.includes(`.`)||t===`-.`,head:e.endsWith(`>`)?`>`:e.endsWith(`x`)?`x`:e.endsWith(`o`)?`o`:``,reference:n===`agentflow`&&(e.includes(`.`)||t===`-.`)&&!e.endsWith(`>`),invisible:e.startsWith(`~`),end:i}),s=c(_,e,a);if(s){let t=a+s[0].length,n=c(/\s*\|("[^"]*"|[^|]*)\|/y,e,t);return n&&(t+=n[0].length),o(s[1],``,n?.[1],t)}let u=c(v,e,a);if(!u)return;let f=a+u[0].length;for(;e[f]===` `||e[f]===` `;)f++;let p=f;e[f]===`"`&&(f=d(e,f));for(let t=Math.min(e.length,p+l.middleLabel);f<t&&e[f]!==`
|
|
10
|
+
`;f++){if(e[f]===e[f-1])continue;let t=c(y,e,f);if(t&&e.slice(p,f).trim()!==``)return o(t[1],u[1],e.slice(p,f).trim(),f+t[0].length)}}var x=e=>e.length>40?`${e.slice(0,39)}…`:e;function S(e){let t=[],n=0;return f(e,(r,i,a)=>{r===`;`&&a===0&&(t.push(e.slice(n,i)),n=i+1)}),t.push(e.slice(n)),t.map(e=>e.trim()).filter(e=>e!==``)}var C=/^(flowchart|graph|agentflow-beta)(?:\s+(TB|TD|BT|LR|RL))?\s*$/;function w(e){if(e.length>l.text)throw new r(`text of ${e.length.toLocaleString(`en`)} characters: grooph reads Mermaid of up to ${l.text.toLocaleString(`en`)}`);let t=/^(`{3,}|~{3,})[ \t]*mermaid[^\n]*\n([\s\S]*?)^\1[ \t]*$/m.exec(e.replace(/\r\n?/g,`
|
|
11
|
+
`)),i=(t?t[2]:e).replace(/\r\n?/g,`
|
|
12
|
+
`).split(`
|
|
13
|
+
`),a=0,u=[];for(;a<i.length&&i[a].trim()===``;)a++;if(i[a]?.trim()===`---`){let e=i.findIndex((e,t)=>t>a&&e.trim()===`---`);if(e<0)throw new r(`front matter that does not close`,a+1);for(let t of i.slice(a+1,e)){let e=/^title:\s*(.+)$/.exec(t.trim());e&&u.push(`title: ${o(e[1].replace(/^['"]|['"]$/g,``))}`)}a=e+1}let d,m={kind:`flowchart`,nodes:new Map,containers:[],edges:[],comments:u,skipped:new Map,edgeIds:new Set,classes:new Map},h=[],_=(e,t)=>{let n=m.nodes.get(e);if(!n){if(m.nodes.size>=l.nodes)throw new r(`more than ${l.nodes.toLocaleString(`en`)} nodes, far more than grooph opens`,t);let i=h.some(e=>m.containers[e].kind===`global`)?void 0:[...h].reverse().find(e=>m.containers[e].kind!==`global`);n={id:e,classes:[],meta:new Map,line:t,...i===void 0?{}:{parent:i}},m.nodes.set(e,n)}return n},v=e=>void m.skipped.set(e,(m.skipped.get(e)??0)+1);for(;a<i.length;a++){let e=i[a],t=a+1,o=e.trim();if(o===``)continue;if(o.startsWith(`%%`)){u.push(o.replace(/^%%\s?/,``));continue}if(/^accDescr\s*\{/.test(o)&&!o.includes(`}`)){for(;a+1<i.length&&!i[a].includes(`}`);)a++;continue}for(let n=1;a+1<i.length&&f(e);n++){if(n>=l.statementLines)throw new r(`a quote or a @{ block that does not close within ${l.statementLines} lines`,t);e+=`\n${i[++a]}`}let s=S(e);if(d===void 0){let e=C.exec(s[0]??``);if(!e)throw new r(`this is not a diagram grooph reads: it starts with "${x(/^[^\s;{]+/.exec(o)?.[0]??o)}". grooph reads ${n}`,t);d=e[1]===`agentflow-beta`?`agentflow`:`flowchart`,m.kind=d,s.shift()}for(let e of s)y(e,t)}if(d===void 0)throw new r(`no diagram: the text is empty or only comments. grooph reads ${n}`);return m;function y(e,t){let n=/^[A-Za-z-]+/.exec(e)?.[0]??``;if(n===`end`&&e===`end`){if(h.length===0)throw new r(`an "end" with nothing open`,t);h.pop();return}if(n===`direction`&&/^direction\s+(TB|TD|BT|LR|RL)$/.test(e))return;let i=[`classDef`,`class`,`style`,`linkStyle`,`click`].includes(n)&&/^[A-Za-z]+\s/.test(e),a=[`accTitle`,`accDescr`].includes(n)&&/^[A-Za-z]+\s*[:{]/.test(e);if(i||a){if(n===`class`){let t=/^class\s+([^\s]+)\s+([\w-]+)/.exec(e);if(t)for(let e of t[1].split(`,`))m.classes.set(e.trim(),[...m.classes.get(e.trim())??[],t[2]])}else v(n);return}let o=/^(subgraph|flow)\s+(?![-=.~<]{2})/.exec(e);if(o&&(o[1]===`subgraph`?m.kind===`flowchart`:m.kind===`agentflow`))return w(o[1],e.slice(o[0].length).trim(),t);if(n===`global`&&m.kind===`agentflow`&&e===`global`){m.containers.push({id:``,label:``,kind:`global`,line:t,...h.length?{parent:h[h.length-1]}:{}}),h.push(m.containers.length-1);return}if(n===`connector`&&m.kind===`agentflow`&&/^connector\s/.test(e)){v(`connector`);return}let s=/^([\p{L}\p{N}_]+)@\{/u.exec(e);s&&m.edgeIds.has(s[1])||T(e,t)}function w(e,t,n){if(m.containers.length>=l.boxes)throw new r(`more than ${l.boxes.toLocaleString(`en`)} subgraphs and flows, far more than grooph opens`,n);if(h.length>=l.depth)throw new r(`subgraphs or flows nested more than ${l.depth} deep`,n);let i=c(s,t,0),a=``,u=``,d;if(i){u=i[0];let s=t.slice(i[0].length).trim();if(s.startsWith(`[`)){let e=p(s,0,n);e&&(a=o(e.label),s=s.slice(e.end).trim())}if(s.startsWith(`@{`)){let e=g(s,1,n);d=e.meta,s=s.slice(e.end).trim()}if(s!==``){if(e===`flow`)throw new r(`a flow it cannot read: ${x(t)}`,n);u=t,a=o(t)}}else if(t.startsWith(`"`))a=o(t),u=a;else throw new r(`a ${e} with no name`,n);if(d)for(let[e,t]of d)_(u,n).meta.set(e,t);m.containers.push({id:u,label:a||u,kind:e,line:n,...h.length?{parent:h[h.length-1]}:{}}),h.push(m.containers.length-1)}function T(e,t){let n=0,i,a;for(;;){for(;e[n]===` `||e[n]===` `;)n++;let u=[];for(;;){let i=c(s,e,n);if(!i)throw new r(`something it cannot read: ${x(e.slice(n))||x(e)}`,t);let a=_(i[0],t);n+=i[0].length;let l=p(e,n,t);if(l&&(a.shape=l.shape,a.label=o(l.label),n=l.end),e.startsWith(`@{`,n)){let r=g(e,n+1,t);for(let[e,t]of r.meta)a.meta.set(e,t);n=r.end}let d=c(/:::([\w-]+)/y,e,n);d&&(a.classes.push(d[1]),n+=d[0].length),u.push(a.id);let f=c(/\s*&\s*/y,e,n);if(!f)break;n+=f[0].length}if(i&&a){if(m.edges.length+i.length*u.length>l.edges)throw new r(`more than ${l.edges.toLocaleString(`en`)} edges, far more than grooph opens`,t);for(let e of i)for(let n of u)m.edges.push({from:e,to:n,...a.label===void 0?{}:{label:a.label},dotted:a.dotted,head:a.head,reference:a.reference,invisible:a.invisible,line:t})}for(;e[n]===` `||e[n]===` `;)n++;if(n>=e.length)return;if(a=b(e,n,m.kind,m.edgeIds),!a)throw new r(`something it cannot read after "${x(u.join(` & `))}": ${x(e.slice(n))}`,t);n=a.end,i=u}}}function T(e){let t=e.normalize(`NFKD`).replace(/[̀-ͯ]/g,``).toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``);return/^[a-z]/.test(t)?t:`n-${t||`node`}`}function E(e){let t=/ → ([a-z][a-z0-9-]*)$/.exec(e),n=t?{then:t[1]}:{},r=t?e.slice(0,t.index):e,i;if(r===`bar passed`)return{kind:`bar-passed`,...n};if(r===`human halt`)return{kind:`human`,...n};if(i=/^human halt, asked every ([1-9]\d*) round\(s\)$/.exec(r))return{kind:`human`,every:Number(i[1]),...n};if(i=/^max iterations: ([1-9]\d*)$/.exec(r))return{kind:`max-iterations`,n:Number(i[1]),...n};if(i=/^budget: (\d+(?:\.\d+)?) (dispatches|minutes|usd|turns|tokens)$/.exec(r))return{kind:`budget`,measure:i[2],limit:Number(i[1]),...n};if(i=/^evidence invalid for ([1-9]\d*) round\(s\)$/.exec(r))return{kind:`evidence-invalid`,rounds:Number(i[1]),...n};if(i=/^diminishing returns over ([1-9]\d*) round\(s\)(?: on (.+?))?(?: \(threshold (-?\d+(?:\.\d+)?)\))?$/.exec(r))return{kind:`diminishing-returns`,rounds:Number(i[1]),...i[2]===void 0?{}:{metric:i[2]},...i[3]===void 0?{}:{threshold:Number(i[3])},...n}}var D=[`lead`,`planner`,`builder`,`critic`,`tester`,`researcher`,`red-team`,`judge`,`synthesizer`],O=[`frontier`,`strong`,`fast`],k=[`command`,`tests`,`diff`,`metric`,`evidence`];function A(e){let t=e.replace(/\r\n?/g,`
|
|
14
|
+
`);if(/^(`{3,}|~{3,})[ \t]*mermaid\b/m.test(t))return!0;let n=(t.trimStart().startsWith(`---`)?t.trimStart().replace(/^---\n[\s\S]*?\n---[ \t]*(\n|$)/,``):t).split(`
|
|
15
|
+
`).map(e=>e.trim()).find(e=>e!==``&&!e.startsWith(`%%`));return n===void 0?!1:/^(flowchart|graph|agentflow-beta)(\s+(TB|TD|BT|LR|RL))?\s*(;.*)?$/.test(n)?!0:/^(sequenceDiagram|classDiagram(-v2)?|stateDiagram(-v2)?|erDiagram|journey|gantt|pie(\s+(title|showData)\b.*)?|quadrantChart|requirementDiagram|gitGraph(\s+(TB|BT|LR))?:?|C4Context|C4Container|C4Component|C4Dynamic|C4Deployment|mindmap|timeline(\s+(TB|TD|BT|LR|RL))?|zenuml|sankey(-beta)?|xychart(-beta)?(\s+horizontal)?|block(-beta)?|packet(-beta)?|kanban|architecture(-beta)?|radar(-beta)?|treemap(-beta)?|venn(-beta)?|ishikawa(-beta)?|railroad(-[a-z]+)?(-beta)?|usecase(-beta)?|swimlane(-beta)?(\s+(TB|TD|BT|LR|RL))?|cynefin(-beta)?|wardley(-beta)?|eventmodeling(-beta)?|treeView(-beta)?|info(\s+showInfo)?)\s*$/.test(n)}function j(n,i={}){try{let a=w(n),o=e({nodes:[...a.nodes.keys()],edges:a.edges},`graph`);if(o)throw new r(`a diagram too large to open: ${o.message}`);let s=M(a,i),c=t(s.doc);if(!c.doc)throw new r(`a diagram that does not make a valid document: ${c.issues[0]?.message??`it does not match the schema`}`);return s}catch(e){if(e instanceof r)return{ok:!1,error:e.message,...e.line===void 0?{}:{line:e.line}};if(e instanceof RangeError)return{ok:!1,error:`a diagram nested or chained too deeply to read`};throw e}}function M(e,t){let n=[],r=e.comments.map(e=>/^grooph mermaid(?: --agentflow)?: (?:a projection of )?(.+) \(([a-z][a-z0-9-]*)@(\d+)\)/.exec(e)).find(e=>e!==null)??void 0,i=r!==void 0,s=e=>T(i?e.replace(/^n_/,``):e),c=e.comments.find(e=>e.startsWith(`title: `))?.slice(7),l=(r?a(r[1]):void 0)??c??t.name??`Imported diagram`,u=r?.[2]??T(l);!r&&!c&&t.name===void 0&&n.push(`The graph's name: "${l}"`);let d=new Set([u]),f=new Set(e.containers.filter(e=>e.kind===`subgraph`).map(e=>s(e.id))),p=new Map,m=(e,t=!1)=>{let n=e;for(let r=p.get(e)??2;d.has(n)||!t&&f.has(n);r++)n=`${e}-${r}`,p.set(e,r+1);return d.add(n),n},h=new Set(e.containers.filter(e=>e.kind!==`global`).map(e=>e.id)),g=e=>h.has(e.id)&&e.shape===void 0&&e.label===void 0&&!e.meta.has(`shape`)&&!e.meta.has(`label`),_=t=>i&&(t.classes.includes(`stop`)||(e.classes.get(t.id)??[]).includes(`stop`)||t.id.startsWith(`stops_`)),v=new Set(e.containers.flatMap(t=>t.kind===`flow`&&t.parent!==void 0&&e.containers[t.parent].kind===`flow`?[t.parent]:[])),y=t=>{for(let n=t.parent;n!==void 0;n=e.containers[n].parent)if(e.containers[n].kind===`flow`)return v.has(n)?void 0:n},b=t=>e.kind===`agentflow`&&[`refdoc`,`lin-doc`,`doc`,`docs`].includes(t.meta.get(`shape`)??``),x=[],S=new Map,C,w=(e,t,r,i)=>{let a=i.person===!0||/ \(a person\)$/.test(t),o=t.replace(/ \(a person\)$/,``),s=r.get(`role`),c=r.get(`model`),l=r.get(`instruction`)??i.brief??``,u={id:e,kind:`agent`,name:o,...a?{by:`person`}:{},role:s===void 0?i.role??`builder`:D.includes(s)?s:{custom:s},...c!==void 0&&O.includes(c)?{model:{tier:c}}:{},brief:l,outputs:[`its work`]},d=[];return s===void 0&&d.push(`${i.why?`${i.why}, so `:``}${a?`a person's step`:`an agent`} with the ${typeof u.role==`string`?u.role:u.role.custom} role`),c!==void 0&&!u.model&&d.push(`the model "${c}" is not a tier grooph knows (frontier, strong, fast), so it was left out`),d.push(`${l===``?`its brief and `:``}its outputs are left to fill in`),n.push(`${o}: ${d.join(`; `)}`),u},A=(e,t,r,i)=>{let a=r.get(`check`),o=r.get(`pass`),s=r.get(`run`);return o===void 0&&n.push(`${t}: ${i}, so a check that passes when "${t}" holds`),{id:e,kind:`check`,name:t,check:{kind:a!==void 0&&k.includes(a)?a:`command`,...s===void 0?{}:{run:s},pass:o??t}}},j=(e,t,r,i)=>{let a=r.get(`question`)??r.get(`prompt`);return a===void 0&&n.push(`${t}: ${i}, so a human gate asking "Approve: ${t}?"`),{id:e,kind:`human-gate`,name:t,prompt:a??`Approve: ${t}?`}};e.kind===`agentflow`&&e.containers.forEach((t,r)=>{if(t.kind!==`flow`||v.has(r))return;let i=[...e.nodes.values()].filter(t=>!g(t)&&!b(t)&&!e.edgeIds.has(t.id)&&y(t)===r),a=m(s(t.id)),o=i[0];x.push(w(a,t.label,e.nodes.get(t.id)?.meta??new Map,{...o?.label?{brief:o.label.replace(/\n/g,` `)}:{},why:`a flow`})),S.set(t.id,a);for(let e of i)S.set(e.id,a);i.length>1&&n.push(`${t.label}: its ${i.length} steps are one agent`)});for(let t of e.nodes.values()){if(S.has(t.id)||_(t)||g(t)||e.edgeIds.has(t.id))continue;let r=(t.label??t.meta.get(`label`)??t.id).replace(/\n/g,` `);if(e.kind===`agentflow`){let e=t.meta.get(`shape`)??`task`;if([`input`,`lean-r`,`lean-right`,`in-out`].includes(e)&&C===void 0){C=t.meta.get(`value`)??r,S.set(t.id,``),i||n.push(`${r}: an input, so the graph's goal`);continue}if(b(t)){n.push(`${r}: reference material, not a step, so it was left out`),S.set(t.id,``);continue}let a=m(s(t.id));S.set(t.id,a);let o=t.meta.get(`kind`);[`action`,`hexagon`,`hex`].includes(e)?t.meta.has(`question`)||t.meta.has(`prompt`)?x.push(j(a,r,t.meta,`an action`)):x.push(w(a,r,t.meta,{person:!0,why:`an action`})):[`decision`,`diamond`,`diam`].includes(e)?x.push(A(a,r,t.meta,`a decision`)):o===`merge`?x.push({id:a,kind:`merge`,name:r,merges:[]}):o===`stop`?x.push({id:a,kind:`stop`,name:r}):x.push(w(a,r,t.meta,{why:`a ${e}`}));continue}let a=m(s(t.id));S.set(t.id,a);let o=t.meta.get(`shape`),c=t.shape??F(o);c===`diamond`?x.push(w(a,r,t.meta,{role:`critic`,why:`a diamond`})):c===`hexagon`?x.push(A(a,r,t.meta,`a hexagon`)):c===`trapezoid`?x.push(j(a,r,t.meta,`a trapezoid`)):c===`circle`?x.push({id:a,kind:`merge`,name:r,merges:[]}):c===`double-circle`?x.push({id:a,kind:`stop`,name:r}):x.push(w(a,r,t.meta,c===`stadium`?{role:`researcher`,why:`a stadium`}:{why:P(t.shape??o??c)}))}let M=[],N=new Set,L=new Map,R=new Set,z=0,V=0,H=0,U=0,W=new Set;for(let t of e.edges){if(t.reference){z++;continue}if(t.invisible){H++;continue}let e=S.get(t.from),r=S.get(t.to);if(e===void 0||r===void 0){for(let e of[t.from,t.to])h.has(e)&&!S.has(e)&&W.add(e);continue}if(e===``||r===``||e===r&&t.from!==t.to)continue;let i=t.label===void 0?[]:o(t.label).split(`
|
|
16
|
+
`),a=i.findIndex(e=>e.startsWith(`stops: `)),s=(a<0?i:i.slice(0,a)).join(` `),c=a<0?[]:[i[a].slice(7),...i.slice(a+1)].map(E),{when:l,approval:u,label:d}=I(s,t.head===`x`);t.head===`x`&&s===``&&V++;let f=`${e}>${r}>${JSON.stringify(l)}>${u}>${d??``}`;if(R.has(f)){U++;continue}R.add(f);let p=m(`${e}-to-${r}`);if(M.push({id:p,from:e,to:r,...l===`always`?{}:{when:l},...u?{approval:!0}:{},...d===void 0?{}:{label:d}}),t.dotted&&N.add(p),c.length>0){let t=c.filter(e=>e!==void 0);L.set(p,t),t.length<c.length&&n.push(`${e} → ${r}: ${c.length-t.length} stop(s) it could not read were left out`)}}H>0&&n.push(`${H} invisible link${H===1?``:`s`} (~~~) left out: they only place nodes`),V>0&&n.push(`${V} edge${V===1?``:`s`} with a cross at its head (--x), so on fail`),U>0&&n.push(`${U} edge${U===1?``:`s`} said twice, kept once`),z>0&&n.push(`${z} reference line${z===1?``:`s`} (-.-) left out: a reference is not a step`);for(let e of W)n.push(`An edge to the box "${e}" was left out: an edge in grooph joins two steps`);let{loops:G,groups:K}=B(e,x,M,N,L,S,i,s,m,n);if(!i)for(let[t,r]of e.skipped)n.push(`${r} ${t} line${r===1?``:`s`} left out: grooph draws in its own style`);return{ok:!0,doc:{grooph:0,id:u,name:l,version:r?Number(r[3]):1,...C===void 0?{}:{goal:C},nodes:x,edges:M,loops:G,...K.length>0?{groups:K}:{}},guesses:n}}var N={rect:`a box`,rectangle:`a box`,proc:`a box`,process:`a box`,plain:`a box`,event:`a rounded box`,round:`a rounded box`,rounded:`a rounded box`,subroutine:`a box with double sides`,"fr-rect":`a box with double sides`,"framed-rectangle":`a box with double sides`,subproc:`a box with double sides`,subprocess:`a box with double sides`,cylinder:`a cylinder`,cyl:`a cylinder`,database:`a cylinder`,db:`a cylinder`,doc:`a document shape`,document:`a document shape`,asymmetric:`a flag`,"inv-trapezoid":`a trapezoid wide at the top`,"trap-t":`a trapezoid wide at the top`,"lean-right":`a parallelogram`,"lean-r":`a parallelogram`,"lean-left":`a parallelogram`,"lean-l":`a parallelogram`,tri:`a triangle`,triangle:`a triangle`,extract:`a triangle`,"flip-tri":`an upside-down triangle`,"flipped-triangle":`an upside-down triangle`,"manual-file":`an upside-down triangle`,"sm-circ":`a small circle`,"small-circle":`a small circle`,start:`a small circle`,"f-circ":`a small filled circle`,"filled-circle":`a small filled circle`,junction:`a small filled circle`},P=e=>N[e]??`a shape Mermaid calls "${e}"`;function F(e){switch(e){case`diam`:case`diamond`:case`decision`:case`question`:return`diamond`;case`hex`:case`hexagon`:case`prepare`:return`hexagon`;case`trap-b`:case`trapezoid`:case`priority`:case`manual`:return`trapezoid`;case`circle`:case`circ`:return`circle`;case`dbl-circ`:case`double-circle`:case`fr-circ`:case`stop`:return`double-circle`;case`stadium`:case`terminal`:case`pill`:return`stadium`;default:return`rect`}}function I(e,t){let n=e.trim(),r=n===`approval`||n.endsWith(`, approval`),i=r?n.slice(0,Math.max(0,n.length-8)).replace(/,\s*$/,``).trim():n;if(i===``)return{when:t?`fail`:`always`,approval:r};if(i===`pass`||i===`fail`||i===`always`)return{when:i,approval:r};let a=/^verdict: (.+)$/.exec(i);return a?{when:{verdict:a[1]},approval:r}:{when:t?`fail`:`always`,approval:!1,label:n}}function L(e,t){let n=new Map;for(let e of t)(n.get(e.from)??n.set(e.from,[]).get(e.from)).push(e.to);let r=0,i=new Map,a=new Map,o=new Set,s=[],c=[];for(let t of e.map(e=>e.id)){if(i.has(t))continue;let e=[{v:t,i:0}];for(i.set(t,r),a.set(t,r++),s.push(t),o.add(t);e.length>0;){let t=e[e.length-1],l=(n.get(t.v)??[])[t.i++];if(l!==void 0){i.has(l)?o.has(l)&&a.set(t.v,Math.min(a.get(t.v),i.get(l))):(i.set(l,r),a.set(l,r++),s.push(l),o.add(l),e.push({v:l,i:0}));continue}if(e.pop(),e.length>0){let n=e[e.length-1].v;a.set(n,Math.min(a.get(n),a.get(t.v)))}if(a.get(t.v)===i.get(t.v)){let e=[],n;do n=s.pop(),o.delete(n),e.push(n);while(n!==t.v);c.push(e)}}}let l=new Map(e.map((e,t)=>[e.id,t]));return c.map(e=>e.sort((e,t)=>l.get(e)-l.get(t)))}function R(e,t,n,r){let i=t.filter(t=>e.has(t.from)&&e.has(t.to)),a=i.filter(e=>n.has(e.id));if(a.length>0&&!z(e,i.filter(e=>!n.has(e.id))))return a.map(e=>e.id);let o=[],s=new Map,c=new Map;for(let e of i)(c.get(e.from)??c.set(e.from,[]).get(e.from)).push(e);let l=[],u=e=>{for(s.set(e,1),l.push({v:e,i:0});l.length>0;){let e=l[l.length-1],t=(c.get(e.v)??[])[e.i++];if(!t){s.set(e.v,2),l.pop();continue}let n=s.get(t.to);n===1?o.push(t.id):n===void 0&&(s.set(t.to,1),l.push({v:t.to,i:0}))}};u(r);for(let t of e)s.has(t)||u(t);return o}function z(e,t){let n=new Map([...e].map(e=>[e,0])),r=new Map;for(let i of t)e.has(i.from)&&e.has(i.to)&&(n.set(i.to,n.get(i.to)+1),(r.get(i.from)??r.set(i.from,[]).get(i.from)).push(i.to));let i=[...e].filter(e=>n.get(e)===0),a=0;for(;i.length>0;){let e=i.pop();a++;for(let t of r.get(e)??[])n.set(t,n.get(t)-1),n.get(t)===0&&i.push(t)}return a<e.size}function B(e,t,n,r,i,a,o,s,c,l){let u=new Map(t.map(e=>[e.id,e.kind])),d=new Map(t.map((e,t)=>[e.id,t])),f=new Map(t.map(e=>[e.id,e.name])),p=e=>f.get(e)??e,m=e=>`${e.slice(0,5).map(p).join(`, `)}${e.length>5?` and ${e.length-5} more`:``}`,h=new Set([...o?r:[],...i.keys()]),g=e=>[...e].sort((e,t)=>d.get(e)-d.get(t)),_=e=>n.find(t=>!e.has(t.from)&&e.has(t.to))?.to??g(e)[0],v=(e,t)=>t.filter(t=>e.has(t.from)&&e.has(t.to)),y=e=>e.every(e=>u.get(n.find(t=>t.id===e).from)===`check`)?`grind`:`judgment`,b=new Set(e.containers.flatMap(t=>t.kind===`flow`&&t.parent!==void 0&&e.containers[t.parent].kind===`flow`?[t.parent]:[])),x=e.containers.map((e,t)=>({c:e,i:t})).filter(({c:e,i:t})=>e.kind===`subgraph`||b.has(t)),S=e.containers.map(()=>0);e.containers.forEach((t,n)=>{for(let r=t.parent;r!==void 0;r=e.containers[r].parent)S[n]++});let C=new Map;for(let t of e.nodes.values()){let n=a.get(t.id);if(n)for(let r=t.parent;r!==void 0;r=e.containers[r].parent)(C.get(r)??C.set(r,new Set).get(r)).add(n)}let w=e=>new Set(C.get(e)??[]),T=o?e.comments.flatMap(e=>/^(\S+) is also a member of loop (\S+)$/.exec(e)?.slice(1,3)??[]):[],D=new Set,O=()=>n.filter(e=>!D.has(e.id)),k=new Map;for(let{c:e,i:t}of[...x].sort((e,t)=>S[t.i]-S[e.i])){if(e.kind!==`subgraph`)continue;let n=w(t),r=s(e.id);for(let e=0;e+1<T.length;e+=2)r===T[e+1]&&d.has(T[e])&&n.add(T[e]);if(n.size===0||!z(n,v(n,O())))continue;let a=R(n,O(),h,_(n));for(let e of a)D.add(e);let u=/^(.*) · (grind|judgment) loop$/.exec(e.label),f=[...W(t),...a.flatMap(e=>i.get(e)??[])],p={id:c(s(e.id),!0),name:u?u[1]:e.label,members:g(n),back:a,...u&&u[2]!==y(a)?{mode:u[2]}:{},stops:f};k.set(t,p),o?f.length===0&&l.push(`${p.name}: a loop with no stops; grooph validate --loops says what it lacks`):l.push(`${p.name}: a box holding a cycle, so a loop${f.length===0?` with no stops; grooph validate --loops says what it lacks`:``}`)}let A=x.filter(({i:e})=>!k.has(e)),j=new Map(A.map(({c:e,i:t})=>[t,c(s(e.id),!0)])),M=t=>{for(let n=t;n!==void 0;n=e.containers[n].parent)if(j.has(n))return n},N=new Map,P=e=>N.get(e)??N.set(e,{nodes:new Set,groups:[]}).get(e);for(let t of e.nodes.values()){let e=M(t.parent),n=a.get(t.id);e!==void 0&&n&&P(e).nodes.add(n)}for(let t of A){let n=M(e.containers[t.i].parent);n!==void 0&&P(n).groups.push(j.get(t.i))}let F=A.flatMap(({c:e,i:t})=>{let n=[...g(N.get(t)?.nodes??[]),...N.get(t)?.groups??[]];return n.length===0?[]:(l.push(`${e.label}: a box with no loop in it, so a group`),[{id:j.get(t),name:e.label,members:n}])}),I=[...k.entries()].sort((e,t)=>e[0]-t[0]).map(([,e])=>e),B=O(),V=L(t,B),H=new Map;V.forEach((e,t)=>e.forEach(e=>H.set(e,t)));let U=V.map(()=>[]);for(let e of B)H.get(e.from)===H.get(e.to)&&U[H.get(e.from)].push(e);return V.forEach((e,t)=>{let n=new Set(e),r=U[t];if(e.length<2&&!r.some(e=>e.from===e.to)||!z(n,r))return;let a=R(n,r,h,_(n));for(let e of a)D.add(e);let o=a.flatMap(e=>i.get(e)??[]),s=`${p(e[0])} loop`;I.push({id:c(`${e[0]}-loop`),name:s,members:e,back:a,stops:o}),l.push(`${s}: the cycle through ${m(e)}, so a loop${o.length===0?` with no stops; grooph validate --loops says what it lacks`:``}`)}),{loops:I,groups:F};function W(t){let n=[];for(let r of e.nodes.values()){if(r.parent!==t||!o||!(r.classes.includes(`stop`)||(e.classes.get(r.id)??[]).includes(`stop`)||r.id.startsWith(`stops_`)))continue;let i=(r.label??``).split(`
|
|
17
|
+
`);for(let e of i[0]===`stops`?i.slice(1):i.map(e=>e.replace(/^stop: /,``))){let t=E(e);t?n.push(t):l.push(`A stop it could not read was left out: "${e}"`)}}return n}}export{j as n,A as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{cn as e}from"./share-BzIzB4EY.js";var t=Object.assign({"../../../../plans/literature-review.grooph.json":{grooph:0,id:`literature-review`,name:`A literature review, by hand with AI help`,version:1,goal:`{{question}} Done when REVIEW.md answers it from what is published, with a source for every claim.`,template:{kind:`graph`,title:`Literature review, by hand with AI help`,summary:`A review of published work that you read and write yourself; an agent finds candidate papers and reads your notes as a skeptic.`,whenToUse:`You want to know what is published on a question, you mean to read the papers yourself, and you want help finding them and a second reader for your notes.`,notFor:`A review an agent writes from abstracts. Here the reading and the judgment are yours.`,profile:{cost:`medium`,speed:`medium`,rigor:`standard`},slots:[{key:`question`,ask:`What do you want to know? One sentence, ending in a question mark.`,example:`Does spaced practice help adults remember new vocabulary for longer?`},{key:`sources`,ask:`Where should the search look?`,example:`Semantic Scholar, Google Scholar, and the reference lists of the two most recent reviews`}],tags:[`plan`,`research`,`human-gate`,`loop`]},description:`A plan a person follows, with two steps an agent may take. You frame the question and choose which papers to read; you read them and take the notes; you decide what goes in and you write the review. An agent searches for candidate papers, and an agent reads your notes as a skeptic and says what they do not show. Work comes back twice: the search runs again if the list misses part of the question, and the notes go back to you while the skeptic still finds a claim with no source. If a loop reaches its third round, stop and decide what to change. Nothing here needs a tool that runs agents: where a step is an agent's, give its brief to whatever AI assistant you use.`,nodes:[{id:`frame`,kind:`agent`,name:`Frame the question`,by:`person`,role:`planner`,brief:`Write the question in one sentence. Under it, say what would count as an answer, what is in and out of scope, and which years and kinds of study you will look at. Keep it to half a page: the search and the skeptic both work from this.`,inputs:[`{{question}}`],outputs:[`QUESTION.md: the question, what counts as an answer, what is in and out`]},{id:`find`,kind:`agent`,name:`Find candidate papers`,role:`researcher`,brief:`Search {{sources}} for papers that bear on the question. List each with its full reference, where you found it, and one line on why it may matter. Open a paper before you say what it found, and say so plainly when you could not open one. Do not rank them and do not leave any out for being inconvenient. If you find nothing for some part of the question, list that part as having none. On a later round, add to the list; do not start it over.`,inputs:[`QUESTION.md`,`{{sources}}`,`what the list is missing (from the second round on)`],outputs:[`CANDIDATES.md: one entry per paper, with its reference and where it was found, and any part of the question with no paper`],allow:[`read-files`,`web`,`write-outputs`]},{id:`choose`,kind:`human-gate`,name:`Choose what to read`,prompt:`Read CANDIDATES.md beside QUESTION.md, and mark in CANDIDATES.md the papers you will read in full. If part of the question has no paper and you think another search could find one, say what is missing and search again.`,options:[`read these`,`search again`]},{id:`read`,kind:`agent`,name:`Read and take notes`,by:`person`,role:`researcher`,brief:`Read each paper you marked, yourself. For each, write in your own words what it claims, what that rests on, and what it does not show, with the paper and page for each claim. When two papers disagree, write the disagreement down as it is. On a later round, start from SKEPTIC.md, or from what you said you still need to read.`,inputs:[`CANDIDATES.md, with the papers you marked`,`QUESTION.md`,`SKEPTIC.md (from the second round on)`],outputs:[`NOTES.md: one section per paper`]},{id:`skeptic`,kind:`agent`,name:`A skeptic reads your notes`,role:`critic`,brief:`Read the notes against the question as a skeptic. For each claim the notes lean on, say whether the notes name the paper and page it comes from, whether another paper in the notes cuts against it, and what is missing for the question to be answered. You judge the notes, not papers you were not given, and you do not rewrite them. Verdict pass only when every claim names its paper and page and every disagreement is written down.`,inputs:[`NOTES.md`,`QUESTION.md`],outputs:[`SKEPTIC.md: one line per claim, and a verdict line`,`verdict: pass | fail`],allow:[`read-files`,`write-outputs`],deny:[`edit-files`]},{id:`decide`,kind:`human-gate`,name:`Decide what is in`,prompt:`You have your notes and the skeptic's list. Which findings go into the review, which papers are left out, and why? If you need to read more first, write down what.`,options:[`write it up`,`read more`]},{id:`write`,kind:`agent`,name:`Write the review`,by:`person`,role:`synthesizer`,brief:`Write the review from your notes: what is known, what is contested, and what nobody has looked at. Give a source for every claim. Say which papers you left out and why. Where the skeptic's list still stands, say so in the text.`,inputs:[`NOTES.md`,`SKEPTIC.md`,`QUESTION.md`],outputs:[`REVIEW.md`]},{id:`done`,kind:`stop`,name:`Done`,outcome:`success`}],edges:[{id:`e-frame-find`,from:`frame`,to:`find`},{id:`e-find-choose`,from:`find`,to:`choose`},{id:`e-choose-read`,from:`choose`,to:`read`,when:`pass`},{id:`e-choose-again`,from:`choose`,to:`find`,when:`fail`,evidence:[`what the list is missing, in your words`]},{id:`e-read-skeptic`,from:`read`,to:`skeptic`,evidence:[`NOTES.md`,`QUESTION.md`]},{id:`e-skeptic-fail`,from:`skeptic`,to:`read`,when:`fail`,evidence:[`SKEPTIC.md`]},{id:`e-skeptic-pass`,from:`skeptic`,to:`decide`,when:`pass`},{id:`e-decide-write`,from:`decide`,to:`write`,when:`pass`},{id:`e-decide-more`,from:`decide`,to:`read`,when:`fail`,evidence:[`what you still need to read`]},{id:`e-write-done`,from:`write`,to:`done`}],loops:[{id:`search`,name:`Search`,members:[`find`,`choose`],back:[`e-choose-again`],mode:`judgment`,bar:{name:`A reading list that covers the question`,inspects:[{kind:`file`,ref:`CANDIDATES.md`},{kind:`file`,ref:`QUESTION.md`}],acceptance:`Every part of QUESTION.md has a candidate paper in CANDIDATES.md, or is listed there as having none.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]},{id:`notes`,name:`Notes`,members:[`read`,`skeptic`,`decide`],back:[`e-skeptic-fail`,`e-decide-more`],mode:`judgment`,bar:{name:`Notes that stand up`,inspects:[{kind:`file`,ref:`NOTES.md`},{kind:`file`,ref:`QUESTION.md`}],acceptance:`Every claim the notes lean on names its paper and page, and every disagreement between papers is written down.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]}],policies:[{id:`p-critic-isolation`,kind:`critic-isolation`,scope:`graph`}]},"../../../../plans/research-study.grooph.json":{grooph:0,id:`research-study`,name:`A research study`,version:1,goal:`{{question}} Done when REPORT.md says what was planned, what was found, and what it does not show.`,template:{kind:`graph`,title:`Research study`,summary:`A study of your own: a design locked in writing before any data, collection, the planned analysis and a report, with a critic's reading of the design and of the analysis.`,whenToUse:`You are running a study of your own and want the plan written down and locked before you see any data, and a second reader for the design and for the analysis.`,notFor:`Looking through data you already have to see what turns up. Here the plan comes first.`,profile:{cost:`medium`,speed:`medium`,rigor:`standard`},slots:[{key:`question`,ask:`What is the question, in one sentence?`,example:`Do short daily quizzes raise exam scores in a first statistics course?`},{key:`data-source`,ask:`What will you measure, and where will the data come from?`,example:`End-of-term exam scores for two sections of the course, one with quizzes and one without`}],tags:[`plan`,`research`,`human-gate`,`loop`]},description:`A plan a person follows, with three steps an agent may take. You state the question, design the study, and lock the design in writing before any data is collected. You collect the data and write the report. An agent may read the design as a critic, run the analysis that was planned, and read the analysis as a critic against the plan. Work comes back twice: the design while it still leaves out what would count against the idea, and the analysis while it departs from the plan without saying so. After the gate before collection the plan asks that the design not be edited: a later change is written in the collection log with its date and reason. If a loop reaches its third round, stop and decide what to change. Nothing here needs a tool that runs agents: where a step is an agent's, give its brief to whatever AI assistant you use.`,nodes:[{id:`question`,kind:`agent`,name:`State the question`,by:`person`,role:`planner`,brief:`Write the question in one sentence, why it matters, and what answer would change what you do. If no answer would change anything, say so now.`,inputs:[`{{question}}`],outputs:[`QUESTION.md`]},{id:`design`,kind:`agent`,name:`Design the study`,by:`person`,role:`planner`,brief:`Say what you will measure and on what, how many, and how you will analyze it. Name in advance the result that would count for the idea, the result that would count against it, and what else could produce the hoped-for result. If you cannot name a result that would count against it, the design is not finished. On a later round, start from DESIGN-REVIEW.md, or from what you said was not settled.`,inputs:[`QUESTION.md`,`{{data-source}}`,`DESIGN-REVIEW.md (from the second round on)`],outputs:[`DESIGN.md: the measure, the sample, the analysis, what would count for and against, and what else could explain the result`]},{id:`design-critic`,kind:`agent`,name:`A critic reads the design`,role:`critic`,brief:`Read the design as a skeptic. Can the question be answered by this measure on this sample? Is there a result that would count against the idea, and would the planned analysis show it? Does the design say what else could produce the hoped-for result? You judge the design and do not rewrite it. Verdict pass only when each of those has an answer in DESIGN.md.`,inputs:[`DESIGN.md`,`QUESTION.md`],outputs:[`DESIGN-REVIEW.md: one line per point, and a verdict line`,`verdict: pass | fail`],allow:[`read-files`,`write-outputs`],deny:[`edit-files`]},{id:`lock`,kind:`human-gate`,name:`Lock the design`,prompt:`Is this the study you will run? Once you say yes, the design is written out as the plan of record, and the plan asks you not to edit it again. If not yet, write down what is not settled.`,options:[`lock it`,`not yet`]},{id:`preregister`,kind:`agent`,name:`Pre-register the plan`,by:`person`,role:`planner`,brief:`Write PREREGISTRATION.md: copy from DESIGN.md what will be measured, on what and how many, the analysis, and the results that would count for and against. Date it. From here this file is not edited: a change is written in COLLECTION-LOG.md with its date and the reason.`,inputs:[`DESIGN.md`],outputs:[`PREREGISTRATION.md, dated`]},{id:`collect`,kind:`agent`,name:`Collect the data`,by:`person`,role:`researcher`,brief:`Collect what PREREGISTRATION.md says, as it says. Keep a log as you go: what was collected and when, anything that went differently from the plan, and anything you left out and why.`,inputs:[`PREREGISTRATION.md`,`{{data-source}}`],outputs:[`the data, as collected`,`COLLECTION-LOG.md`]},{id:`analyze`,kind:`agent`,name:`Run the planned analysis`,role:`researcher`,brief:`Run the analysis PREREGISTRATION.md names, first and as written. Anything else you look at goes in a section of its own, headed as exploratory. Give the numbers before the conclusions, and say what each conclusion rests on. On a later round, start from ANALYSIS-REVIEW.md.`,inputs:[`PREREGISTRATION.md`,`the data, as collected`,`COLLECTION-LOG.md`,`ANALYSIS-REVIEW.md (from the second round on)`],outputs:[`ANALYSIS.md: the planned analysis, then anything exploratory, each labeled`],allow:[`read-files`,`run-commands`,`write-outputs`]},{id:`analysis-critic`,kind:`agent`,name:`A critic reads the analysis`,role:`critic`,brief:`Read the analysis beside PREREGISTRATION.md. Was each planned analysis run as written? Is everything else labeled exploratory? Does each conclusion follow from its numbers? You judge and do not rerun or rewrite. Verdict pass only when all three hold.`,inputs:[`ANALYSIS.md`,`PREREGISTRATION.md`,`COLLECTION-LOG.md`],outputs:[`ANALYSIS-REVIEW.md: one line per point, and a verdict line`,`verdict: pass | fail`],allow:[`read-files`,`write-outputs`],deny:[`edit-files`]},{id:`write`,kind:`agent`,name:`Write the report`,by:`person`,role:`synthesizer`,brief:`Write what was asked, what was planned before any data was seen, what was found, and what it does not show. Report the planned result whichever way it came out, and every departure the log records. Keep exploratory findings apart and call them that.`,inputs:[`QUESTION.md`,`PREREGISTRATION.md`,`COLLECTION-LOG.md`,`ANALYSIS.md`,`ANALYSIS-REVIEW.md`],outputs:[`REPORT.md`]},{id:`done`,kind:`stop`,name:`Done`,outcome:`success`}],edges:[{id:`e-question-design`,from:`question`,to:`design`},{id:`e-design-critic`,from:`design`,to:`design-critic`,evidence:[`DESIGN.md`,`QUESTION.md`]},{id:`e-design-critic-fail`,from:`design-critic`,to:`design`,when:`fail`,evidence:[`DESIGN-REVIEW.md`]},{id:`e-design-critic-pass`,from:`design-critic`,to:`lock`,when:`pass`},{id:`e-lock-preregister`,from:`lock`,to:`preregister`,when:`pass`},{id:`e-lock-not-yet`,from:`lock`,to:`design`,when:`fail`,evidence:[`what is not settled yet`]},{id:`e-preregister-collect`,from:`preregister`,to:`collect`},{id:`e-collect-analyze`,from:`collect`,to:`analyze`},{id:`e-analyze-critic`,from:`analyze`,to:`analysis-critic`,evidence:[`ANALYSIS.md`,`PREREGISTRATION.md`,`COLLECTION-LOG.md`]},{id:`e-analysis-critic-fail`,from:`analysis-critic`,to:`analyze`,when:`fail`,evidence:[`ANALYSIS-REVIEW.md`]},{id:`e-analysis-critic-pass`,from:`analysis-critic`,to:`write`,when:`pass`},{id:`e-write-done`,from:`write`,to:`done`}],loops:[{id:`design-loop`,name:`Design`,members:[`design`,`design-critic`,`lock`],back:[`e-design-critic-fail`,`e-lock-not-yet`],mode:`judgment`,bar:{name:`A design that could fail`,inspects:[{kind:`file`,ref:`DESIGN.md`},{kind:`file`,ref:`QUESTION.md`}],acceptance:`DESIGN.md says what is measured and on how many, what result would count against the idea, and what else could explain it.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]},{id:`analysis-loop`,name:`Analysis`,members:[`analyze`,`analysis-critic`],back:[`e-analysis-critic-fail`],mode:`judgment`,bar:{name:`The planned analysis`,inspects:[{kind:`file`,ref:`PREREGISTRATION.md`},{kind:`file`,ref:`ANALYSIS.md`}],acceptance:`Every planned analysis is in ANALYSIS.md as planned, the rest is labeled exploratory, and each conclusion follows from its numbers.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]}],policies:[{id:`p-critic-isolation`,kind:`critic-isolation`,scope:`graph`}]},"../../../../plans/solo-project.grooph.json":{grooph:0,id:`solo-project`,name:`A solo project`,version:1,goal:`{{project}} Done when every line of DONE.md is met and it is out at {{where}}.`,template:{kind:`graph`,title:`Solo project`,summary:`One person's project: what done means written first, the work, a review of your own work with fresh eyes, and a decision before anything is published.`,whenToUse:`You work alone on something you will put in front of other people, and you want what done means, and the decision to publish, written down first.`,notFor:`Work with a second person available to review it (use team-handoffs).`,profile:{cost:`medium`,speed:`medium`,rigor:`standard`},slots:[{key:`project`,ask:`What are you making? One or two sentences.`,example:`A one-page website for my woodworking, with six photographs and a way to reach me.`},{key:`where`,ask:`Where will it be published? Finish the sentence: it is out at ...`,example:`its own web address`}],tags:[`plan`,`solo`,`human-gate`,`loop`,`irreversible`]},description:`A plan for one person; no step here is an agent's. You write down what you will make and how you will know it is done, before you start. You make it. Then you come back later, the next day if you can, and read your own work against that list as if someone else had made it, and it goes back to you while a line is not met. Before anything is published you stop and decide. If the review reaches its third round, stop and decide what to change: the work, the list, or the plan.`,nodes:[{id:`plan`,kind:`agent`,name:`Write what done means`,by:`person`,role:`planner`,brief:`Before you start, write what you are making in two sentences, and under it a short list of things that will be true when it is done, each one something you could point at. Add what you will not do. Three to seven lines: this is the list you will be held to.`,inputs:[`{{project}}`],outputs:[`DONE.md: what you are making, and what will be true when it is done`]},{id:`make`,kind:`agent`,name:`Make it`,by:`person`,role:`builder`,brief:`Make what DONE.md describes. Stop when you believe every line is met. On a later round, start from REVIEW.md: deal with each line that was not met, and with anything you wrote there at the gate.`,inputs:[`DONE.md`,`REVIEW.md (from the second round on)`],outputs:[`the work`]},{id:`review`,kind:`agent`,name:`Review it with fresh eyes`,by:`person`,role:`critic`,brief:`Come back after a break, the next day if you can. Read the work against DONE.md as if someone else had made it, one line each: met, with where to see it, or not met. Fix nothing in this step: write it down and take it back to the making. Pass it when every line is met.`,inputs:[`the work`,`DONE.md`],outputs:[`REVIEW.md: one line for each line of DONE.md, ending in pass or go again`]},{id:`publish-gate`,kind:`human-gate`,name:`Decide to publish`,prompt:`Every line of DONE.md is met. Do you put it out at {{where}}? If not yet, write what is holding you back at the foot of REVIEW.md.`,options:[`publish`,`not yet`]},{id:`publish`,kind:`agent`,name:`Publish it`,by:`person`,role:`builder`,brief:`Put the work out at {{where}}, and write down where it is and when it went out. Check it from somewhere else, as a visitor would see it.`,inputs:[`the work`,`{{where}}`],outputs:[`the work, published`,`PUBLISHED.md: where and when`],irreversible:[`publish`]},{id:`done`,kind:`stop`,name:`Out`,outcome:`success`}],edges:[{id:`e-plan-make`,from:`plan`,to:`make`},{id:`e-make-review`,from:`make`,to:`review`,evidence:[`the work`,`DONE.md`]},{id:`e-review-fail`,from:`review`,to:`make`,when:`fail`,evidence:[`REVIEW.md`]},{id:`e-review-pass`,from:`review`,to:`publish-gate`,when:`pass`},{id:`e-publish-gate-publish`,from:`publish-gate`,to:`publish`,when:`pass`},{id:`e-publish-gate-not-yet`,from:`publish-gate`,to:`make`,when:`fail`,evidence:[`REVIEW.md, with what is holding you back`]},{id:`e-publish-done`,from:`publish`,to:`done`}],loops:[{id:`review-loop`,name:`Review`,members:[`make`,`review`,`publish-gate`],back:[`e-review-fail`,`e-publish-gate-not-yet`],mode:`judgment`,bar:{name:`What done means`,inspects:[{kind:`checklist`,ref:`DONE.md`},{kind:`artifact`,ref:`the work`}],acceptance:`Every line of DONE.md is met, and you can point to where.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]}]},"../../../../plans/team-handoffs.grooph.json":{grooph:0,id:`team-handoffs`,name:`A small team's handoffs`,version:1,goal:`{{work}} Done when {{reviewer}} has passed it against the request and {{approver}} has signed off.`,template:{kind:`graph`,title:`Team handoffs`,summary:`Who hands what to whom on a small team: a written request, the work with a handoff note, a review that can send it back, and one person who signs off.`,whenToUse:`A few people pass a piece of work between them, and you want each handoff, and who decides it is done, written down.`,notFor:`Work one person does alone (use solo-project), or a team large enough to need a tracker.`,profile:{cost:`medium`,speed:`medium`,rigor:`standard`},slots:[{key:`work`,ask:`What is being done? One or two sentences.`,example:`The spring newsletter, written, laid out and ready to send.`},{key:`requester`,ask:`Who is asking for it?`,example:`Priya`},{key:`author`,ask:`Who does the work?`,example:`Sam`},{key:`reviewer`,ask:`Who reviews it?`,example:`Noor`},{key:`approver`,ask:`Who signs off?`,example:`Priya`}],tags:[`plan`,`team`,`human-gate`,`loop`]},description:`A plan for people; no step here is an agent's. {{requester}} writes down what is wanted. {{author}} does the work and hands it over with a note on what to look at first. {{reviewer}} reads it against the request, and it goes back to {{author}} while something asked for is missing. {{approver}} signs off, or sends it back with the reason in writing. Each handoff says in writing what is being handed, and one person, named in advance, decides it is done. If the review reaches its third round, stop and decide together what to change.`,nodes:[{id:`request`,kind:`agent`,name:`{{requester}} writes the request`,by:`person`,role:`planner`,brief:`Write what is wanted, by when, and what done looks like, as a short list someone else could check. Say what is not wanted too. If {{author}} has to guess, the request is not finished.`,inputs:[`{{work}}`],outputs:[`REQUEST.md: what is wanted, by when, and what done looks like`]},{id:`do`,kind:`agent`,name:`{{author}} does the work`,by:`person`,role:`builder`,brief:`Do what the request asks. Hand it over with a note: what is done, what is not and why, and what to look at first. On a later round, start from REVIEW.md and answer each point, or say why it does not apply.`,inputs:[`REQUEST.md`,`REVIEW.md (from the second round on)`],outputs:[`the work`,`HANDOFF.md: what is done, what is not, what to look at first`]},{id:`review`,kind:`agent`,name:`{{reviewer}} reviews`,by:`person`,role:`critic`,brief:`Read the work against the request, one line for each thing it asks for: there, with where to see it, or not there. Say what you could not check. You judge and do not fix: send it back. Pass it when everything asked for is there, or is named in the handoff note as left out for a reason you accept.`,inputs:[`the work`,`HANDOFF.md`,`REQUEST.md`],outputs:[`REVIEW.md: one line per thing asked for, ending in pass or send back`]},{id:`sign-off`,kind:`human-gate`,name:`{{approver}} signs off`,prompt:`{{reviewer}} has passed it. REVIEW.md and HANDOFF.md say what was left out. Do you sign off? If you send it back, add the reason to REVIEW.md.`,options:[`sign off`,`send it back`]},{id:`done`,kind:`stop`,name:`Handed over`,outcome:`success`}],edges:[{id:`e-request-do`,from:`request`,to:`do`},{id:`e-do-review`,from:`do`,to:`review`,evidence:[`the work`,`HANDOFF.md`,`REQUEST.md`]},{id:`e-review-fail`,from:`review`,to:`do`,when:`fail`,evidence:[`REVIEW.md`]},{id:`e-review-pass`,from:`review`,to:`sign-off`,when:`pass`},{id:`e-sign-off-done`,from:`sign-off`,to:`done`,when:`pass`},{id:`e-sign-off-back`,from:`sign-off`,to:`do`,when:`fail`,evidence:[`REVIEW.md, with the reason it was sent back`]}],loops:[{id:`review-loop`,name:`Review`,members:[`do`,`review`,`sign-off`],back:[`e-review-fail`,`e-sign-off-back`],mode:`judgment`,bar:{name:`The request`,inspects:[{kind:`file`,ref:`REQUEST.md`},{kind:`artifact`,ref:`the work, with HANDOFF.md`}],acceptance:`Everything REQUEST.md asks for is there, or is named in HANDOFF.md as left out for a reason the reviewer accepts.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]}]}});function n(){let n=[];for(let[r,i]of Object.entries(t)){let t=e(i);t.doc?.template?n.push(t.doc):console.warn(`grooph: skipped ${r}: not a template document`)}return n.sort((e,t)=>e.template.title.localeCompare(t.template.title))}var r=n();export{r as PLAN_TEMPLATES};
|
|
1
|
+
import{pn as e}from"./share-DV3wsAsJ.js";var t=Object.assign({"../../../../plans/literature-review.grooph.json":{grooph:0,id:`literature-review`,name:`A literature review, by hand with AI help`,version:1,goal:`{{question}} Done when REVIEW.md answers it from what is published, with a source for every claim.`,template:{kind:`graph`,title:`Literature review, by hand with AI help`,summary:`A review of published work that you read and write yourself; an agent finds candidate papers and reads your notes as a skeptic.`,whenToUse:`You want to know what is published on a question, you mean to read the papers yourself, and you want help finding them and a second reader for your notes.`,notFor:`A review an agent writes from abstracts. Here the reading and the judgment are yours.`,profile:{cost:`medium`,speed:`medium`,rigor:`standard`},slots:[{key:`question`,ask:`What do you want to know? One sentence, ending in a question mark.`,example:`Does spaced practice help adults remember new vocabulary for longer?`},{key:`sources`,ask:`Where should the search look?`,example:`Semantic Scholar, Google Scholar, and the reference lists of the two most recent reviews`}],tags:[`plan`,`research`,`human-gate`,`loop`]},description:`A plan a person follows, with two steps an agent may take. You frame the question and choose which papers to read; you read them and take the notes; you decide what goes in and you write the review. An agent searches for candidate papers, and an agent reads your notes as a skeptic and says what they do not show. Work comes back twice: the search runs again if the list misses part of the question, and the notes go back to you while the skeptic still finds a claim with no source. If a loop reaches its third round, stop and decide what to change. Nothing here needs a tool that runs agents: where a step is an agent's, give its brief to whatever AI assistant you use.`,nodes:[{id:`frame`,kind:`agent`,name:`Frame the question`,by:`person`,role:`planner`,brief:`Write the question in one sentence. Under it, say what would count as an answer, what is in and out of scope, and which years and kinds of study you will look at. Keep it to half a page: the search and the skeptic both work from this.`,inputs:[`{{question}}`],outputs:[`QUESTION.md: the question, what counts as an answer, what is in and out`]},{id:`find`,kind:`agent`,name:`Find candidate papers`,role:`researcher`,brief:`Search {{sources}} for papers that bear on the question. List each with its full reference, where you found it, and one line on why it may matter. Open a paper before you say what it found, and say so plainly when you could not open one. Do not rank them and do not leave any out for being inconvenient. If you find nothing for some part of the question, list that part as having none. On a later round, add to the list; do not start it over.`,inputs:[`QUESTION.md`,`{{sources}}`,`what the list is missing (from the second round on)`],outputs:[`CANDIDATES.md: one entry per paper, with its reference and where it was found, and any part of the question with no paper`],allow:[`read-files`,`web`,`write-outputs`]},{id:`choose`,kind:`human-gate`,name:`Choose what to read`,prompt:`Read CANDIDATES.md beside QUESTION.md, and mark in CANDIDATES.md the papers you will read in full. If part of the question has no paper and you think another search could find one, say what is missing and search again.`,options:[`read these`,`search again`]},{id:`read`,kind:`agent`,name:`Read and take notes`,by:`person`,role:`researcher`,brief:`Read each paper you marked, yourself. For each, write in your own words what it claims, what that rests on, and what it does not show, with the paper and page for each claim. When two papers disagree, write the disagreement down as it is. On a later round, start from SKEPTIC.md, or from what you said you still need to read.`,inputs:[`CANDIDATES.md, with the papers you marked`,`QUESTION.md`,`SKEPTIC.md (from the second round on)`],outputs:[`NOTES.md: one section per paper`]},{id:`skeptic`,kind:`agent`,name:`A skeptic reads your notes`,role:`critic`,brief:`Read the notes against the question as a skeptic. For each claim the notes lean on, say whether the notes name the paper and page it comes from, whether another paper in the notes cuts against it, and what is missing for the question to be answered. You judge the notes, not papers you were not given, and you do not rewrite them. Verdict pass only when every claim names its paper and page and every disagreement is written down.`,inputs:[`NOTES.md`,`QUESTION.md`],outputs:[`SKEPTIC.md: one line per claim, and a verdict line`,`verdict: pass | fail`],allow:[`read-files`,`write-outputs`],deny:[`edit-files`]},{id:`decide`,kind:`human-gate`,name:`Decide what is in`,prompt:`You have your notes and the skeptic's list. Which findings go into the review, which papers are left out, and why? If you need to read more first, write down what.`,options:[`write it up`,`read more`]},{id:`write`,kind:`agent`,name:`Write the review`,by:`person`,role:`synthesizer`,brief:`Write the review from your notes: what is known, what is contested, and what nobody has looked at. Give a source for every claim. Say which papers you left out and why. Where the skeptic's list still stands, say so in the text.`,inputs:[`NOTES.md`,`SKEPTIC.md`,`QUESTION.md`],outputs:[`REVIEW.md`]},{id:`done`,kind:`stop`,name:`Done`,outcome:`success`}],edges:[{id:`e-frame-find`,from:`frame`,to:`find`},{id:`e-find-choose`,from:`find`,to:`choose`},{id:`e-choose-read`,from:`choose`,to:`read`,when:`pass`},{id:`e-choose-again`,from:`choose`,to:`find`,when:`fail`,evidence:[`what the list is missing, in your words`]},{id:`e-read-skeptic`,from:`read`,to:`skeptic`,evidence:[`NOTES.md`,`QUESTION.md`]},{id:`e-skeptic-fail`,from:`skeptic`,to:`read`,when:`fail`,evidence:[`SKEPTIC.md`]},{id:`e-skeptic-pass`,from:`skeptic`,to:`decide`,when:`pass`},{id:`e-decide-write`,from:`decide`,to:`write`,when:`pass`},{id:`e-decide-more`,from:`decide`,to:`read`,when:`fail`,evidence:[`what you still need to read`]},{id:`e-write-done`,from:`write`,to:`done`}],loops:[{id:`search`,name:`Search`,members:[`find`,`choose`],back:[`e-choose-again`],mode:`judgment`,bar:{name:`A reading list that covers the question`,inspects:[{kind:`file`,ref:`CANDIDATES.md`},{kind:`file`,ref:`QUESTION.md`}],acceptance:`Every part of QUESTION.md has a candidate paper in CANDIDATES.md, or is listed there as having none.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]},{id:`notes`,name:`Notes`,members:[`read`,`skeptic`,`decide`],back:[`e-skeptic-fail`,`e-decide-more`],mode:`judgment`,bar:{name:`Notes that stand up`,inspects:[{kind:`file`,ref:`NOTES.md`},{kind:`file`,ref:`QUESTION.md`}],acceptance:`Every claim the notes lean on names its paper and page, and every disagreement between papers is written down.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]}],policies:[{id:`p-critic-isolation`,kind:`critic-isolation`,scope:`graph`}]},"../../../../plans/research-study.grooph.json":{grooph:0,id:`research-study`,name:`A research study`,version:1,goal:`{{question}} Done when REPORT.md says what was planned, what was found, and what it does not show.`,template:{kind:`graph`,title:`Research study`,summary:`A study of your own: a design locked in writing before any data, collection, the planned analysis and a report, with a critic's reading of the design and of the analysis.`,whenToUse:`You are running a study of your own and want the plan written down and locked before you see any data, and a second reader for the design and for the analysis.`,notFor:`Looking through data you already have to see what turns up. Here the plan comes first.`,profile:{cost:`medium`,speed:`medium`,rigor:`standard`},slots:[{key:`question`,ask:`What is the question, in one sentence?`,example:`Do short daily quizzes raise exam scores in a first statistics course?`},{key:`data-source`,ask:`What will you measure, and where will the data come from?`,example:`End-of-term exam scores for two sections of the course, one with quizzes and one without`}],tags:[`plan`,`research`,`human-gate`,`loop`]},description:`A plan a person follows, with three steps an agent may take. You state the question, design the study, and lock the design in writing before any data is collected. You collect the data and write the report. An agent may read the design as a critic, run the analysis that was planned, and read the analysis as a critic against the plan. Work comes back twice: the design while it still leaves out what would count against the idea, and the analysis while it departs from the plan without saying so. After the gate before collection the plan asks that the design not be edited: a later change is written in the collection log with its date and reason. If a loop reaches its third round, stop and decide what to change. Nothing here needs a tool that runs agents: where a step is an agent's, give its brief to whatever AI assistant you use.`,nodes:[{id:`question`,kind:`agent`,name:`State the question`,by:`person`,role:`planner`,brief:`Write the question in one sentence, why it matters, and what answer would change what you do. If no answer would change anything, say so now.`,inputs:[`{{question}}`],outputs:[`QUESTION.md`]},{id:`design`,kind:`agent`,name:`Design the study`,by:`person`,role:`planner`,brief:`Say what you will measure and on what, how many, and how you will analyze it. Name in advance the result that would count for the idea, the result that would count against it, and what else could produce the hoped-for result. If you cannot name a result that would count against it, the design is not finished. On a later round, start from DESIGN-REVIEW.md, or from what you said was not settled.`,inputs:[`QUESTION.md`,`{{data-source}}`,`DESIGN-REVIEW.md (from the second round on)`],outputs:[`DESIGN.md: the measure, the sample, the analysis, what would count for and against, and what else could explain the result`]},{id:`design-critic`,kind:`agent`,name:`A critic reads the design`,role:`critic`,brief:`Read the design as a skeptic. Can the question be answered by this measure on this sample? Is there a result that would count against the idea, and would the planned analysis show it? Does the design say what else could produce the hoped-for result? You judge the design and do not rewrite it. Verdict pass only when each of those has an answer in DESIGN.md.`,inputs:[`DESIGN.md`,`QUESTION.md`],outputs:[`DESIGN-REVIEW.md: one line per point, and a verdict line`,`verdict: pass | fail`],allow:[`read-files`,`write-outputs`],deny:[`edit-files`]},{id:`lock`,kind:`human-gate`,name:`Lock the design`,prompt:`Is this the study you will run? Once you say yes, the design is written out as the plan of record, and the plan asks you not to edit it again. If not yet, write down what is not settled.`,options:[`lock it`,`not yet`]},{id:`preregister`,kind:`agent`,name:`Pre-register the plan`,by:`person`,role:`planner`,brief:`Write PREREGISTRATION.md: copy from DESIGN.md what will be measured, on what and how many, the analysis, and the results that would count for and against. Date it. From here this file is not edited: a change is written in COLLECTION-LOG.md with its date and the reason.`,inputs:[`DESIGN.md`],outputs:[`PREREGISTRATION.md, dated`]},{id:`collect`,kind:`agent`,name:`Collect the data`,by:`person`,role:`researcher`,brief:`Collect what PREREGISTRATION.md says, as it says. Keep a log as you go: what was collected and when, anything that went differently from the plan, and anything you left out and why.`,inputs:[`PREREGISTRATION.md`,`{{data-source}}`],outputs:[`the data, as collected`,`COLLECTION-LOG.md`]},{id:`analyze`,kind:`agent`,name:`Run the planned analysis`,role:`researcher`,brief:`Run the analysis PREREGISTRATION.md names, first and as written. Anything else you look at goes in a section of its own, headed as exploratory. Give the numbers before the conclusions, and say what each conclusion rests on. On a later round, start from ANALYSIS-REVIEW.md.`,inputs:[`PREREGISTRATION.md`,`the data, as collected`,`COLLECTION-LOG.md`,`ANALYSIS-REVIEW.md (from the second round on)`],outputs:[`ANALYSIS.md: the planned analysis, then anything exploratory, each labeled`],allow:[`read-files`,`run-commands`,`write-outputs`]},{id:`analysis-critic`,kind:`agent`,name:`A critic reads the analysis`,role:`critic`,brief:`Read the analysis beside PREREGISTRATION.md. Was each planned analysis run as written? Is everything else labeled exploratory? Does each conclusion follow from its numbers? You judge and do not rerun or rewrite. Verdict pass only when all three hold.`,inputs:[`ANALYSIS.md`,`PREREGISTRATION.md`,`COLLECTION-LOG.md`],outputs:[`ANALYSIS-REVIEW.md: one line per point, and a verdict line`,`verdict: pass | fail`],allow:[`read-files`,`write-outputs`],deny:[`edit-files`]},{id:`write`,kind:`agent`,name:`Write the report`,by:`person`,role:`synthesizer`,brief:`Write what was asked, what was planned before any data was seen, what was found, and what it does not show. Report the planned result whichever way it came out, and every departure the log records. Keep exploratory findings apart and call them that.`,inputs:[`QUESTION.md`,`PREREGISTRATION.md`,`COLLECTION-LOG.md`,`ANALYSIS.md`,`ANALYSIS-REVIEW.md`],outputs:[`REPORT.md`]},{id:`done`,kind:`stop`,name:`Done`,outcome:`success`}],edges:[{id:`e-question-design`,from:`question`,to:`design`},{id:`e-design-critic`,from:`design`,to:`design-critic`,evidence:[`DESIGN.md`,`QUESTION.md`]},{id:`e-design-critic-fail`,from:`design-critic`,to:`design`,when:`fail`,evidence:[`DESIGN-REVIEW.md`]},{id:`e-design-critic-pass`,from:`design-critic`,to:`lock`,when:`pass`},{id:`e-lock-preregister`,from:`lock`,to:`preregister`,when:`pass`},{id:`e-lock-not-yet`,from:`lock`,to:`design`,when:`fail`,evidence:[`what is not settled yet`]},{id:`e-preregister-collect`,from:`preregister`,to:`collect`},{id:`e-collect-analyze`,from:`collect`,to:`analyze`},{id:`e-analyze-critic`,from:`analyze`,to:`analysis-critic`,evidence:[`ANALYSIS.md`,`PREREGISTRATION.md`,`COLLECTION-LOG.md`]},{id:`e-analysis-critic-fail`,from:`analysis-critic`,to:`analyze`,when:`fail`,evidence:[`ANALYSIS-REVIEW.md`]},{id:`e-analysis-critic-pass`,from:`analysis-critic`,to:`write`,when:`pass`},{id:`e-write-done`,from:`write`,to:`done`}],loops:[{id:`design-loop`,name:`Design`,members:[`design`,`design-critic`,`lock`],back:[`e-design-critic-fail`,`e-lock-not-yet`],mode:`judgment`,bar:{name:`A design that could fail`,inspects:[{kind:`file`,ref:`DESIGN.md`},{kind:`file`,ref:`QUESTION.md`}],acceptance:`DESIGN.md says what is measured and on how many, what result would count against the idea, and what else could explain it.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]},{id:`analysis-loop`,name:`Analysis`,members:[`analyze`,`analysis-critic`],back:[`e-analysis-critic-fail`],mode:`judgment`,bar:{name:`The planned analysis`,inspects:[{kind:`file`,ref:`PREREGISTRATION.md`},{kind:`file`,ref:`ANALYSIS.md`}],acceptance:`Every planned analysis is in ANALYSIS.md as planned, the rest is labeled exploratory, and each conclusion follows from its numbers.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]}],policies:[{id:`p-critic-isolation`,kind:`critic-isolation`,scope:`graph`}]},"../../../../plans/solo-project.grooph.json":{grooph:0,id:`solo-project`,name:`A solo project`,version:1,goal:`{{project}} Done when every line of DONE.md is met and it is out at {{where}}.`,template:{kind:`graph`,title:`Solo project`,summary:`One person's project: what done means written first, the work, a review of your own work with fresh eyes, and a decision before anything is published.`,whenToUse:`You work alone on something you will put in front of other people, and you want what done means, and the decision to publish, written down first.`,notFor:`Work with a second person available to review it (use team-handoffs).`,profile:{cost:`medium`,speed:`medium`,rigor:`standard`},slots:[{key:`project`,ask:`What are you making? One or two sentences.`,example:`A one-page website for my woodworking, with six photographs and a way to reach me.`},{key:`where`,ask:`Where will it be published? Finish the sentence: it is out at ...`,example:`its own web address`}],tags:[`plan`,`solo`,`human-gate`,`loop`,`irreversible`]},description:`A plan for one person; no step here is an agent's. You write down what you will make and how you will know it is done, before you start. You make it. Then you come back later, the next day if you can, and read your own work against that list as if someone else had made it, and it goes back to you while a line is not met. Before anything is published you stop and decide. If the review reaches its third round, stop and decide what to change: the work, the list, or the plan.`,nodes:[{id:`plan`,kind:`agent`,name:`Write what done means`,by:`person`,role:`planner`,brief:`Before you start, write what you are making in two sentences, and under it a short list of things that will be true when it is done, each one something you could point at. Add what you will not do. Three to seven lines: this is the list you will be held to.`,inputs:[`{{project}}`],outputs:[`DONE.md: what you are making, and what will be true when it is done`]},{id:`make`,kind:`agent`,name:`Make it`,by:`person`,role:`builder`,brief:`Make what DONE.md describes. Stop when you believe every line is met. On a later round, start from REVIEW.md: deal with each line that was not met, and with anything you wrote there at the gate.`,inputs:[`DONE.md`,`REVIEW.md (from the second round on)`],outputs:[`the work`]},{id:`review`,kind:`agent`,name:`Review it with fresh eyes`,by:`person`,role:`critic`,brief:`Come back after a break, the next day if you can. Read the work against DONE.md as if someone else had made it, one line each: met, with where to see it, or not met. Fix nothing in this step: write it down and take it back to the making. Pass it when every line is met.`,inputs:[`the work`,`DONE.md`],outputs:[`REVIEW.md: one line for each line of DONE.md, ending in pass or go again`]},{id:`publish-gate`,kind:`human-gate`,name:`Decide to publish`,prompt:`Every line of DONE.md is met. Do you put it out at {{where}}? If not yet, write what is holding you back at the foot of REVIEW.md.`,options:[`publish`,`not yet`]},{id:`publish`,kind:`agent`,name:`Publish it`,by:`person`,role:`builder`,brief:`Put the work out at {{where}}, and write down where it is and when it went out. Check it from somewhere else, as a visitor would see it.`,inputs:[`the work`,`{{where}}`],outputs:[`the work, published`,`PUBLISHED.md: where and when`],irreversible:[`publish`]},{id:`done`,kind:`stop`,name:`Out`,outcome:`success`}],edges:[{id:`e-plan-make`,from:`plan`,to:`make`},{id:`e-make-review`,from:`make`,to:`review`,evidence:[`the work`,`DONE.md`]},{id:`e-review-fail`,from:`review`,to:`make`,when:`fail`,evidence:[`REVIEW.md`]},{id:`e-review-pass`,from:`review`,to:`publish-gate`,when:`pass`},{id:`e-publish-gate-publish`,from:`publish-gate`,to:`publish`,when:`pass`},{id:`e-publish-gate-not-yet`,from:`publish-gate`,to:`make`,when:`fail`,evidence:[`REVIEW.md, with what is holding you back`]},{id:`e-publish-done`,from:`publish`,to:`done`}],loops:[{id:`review-loop`,name:`Review`,members:[`make`,`review`,`publish-gate`],back:[`e-review-fail`,`e-publish-gate-not-yet`],mode:`judgment`,bar:{name:`What done means`,inspects:[{kind:`checklist`,ref:`DONE.md`},{kind:`artifact`,ref:`the work`}],acceptance:`Every line of DONE.md is met, and you can point to where.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]}]},"../../../../plans/team-handoffs.grooph.json":{grooph:0,id:`team-handoffs`,name:`A small team's handoffs`,version:1,goal:`{{work}} Done when {{reviewer}} has passed it against the request and {{approver}} has signed off.`,template:{kind:`graph`,title:`Team handoffs`,summary:`Who hands what to whom on a small team: a written request, the work with a handoff note, a review that can send it back, and one person who signs off.`,whenToUse:`A few people pass a piece of work between them, and you want each handoff, and who decides it is done, written down.`,notFor:`Work one person does alone (use solo-project), or a team large enough to need a tracker.`,profile:{cost:`medium`,speed:`medium`,rigor:`standard`},slots:[{key:`work`,ask:`What is being done? One or two sentences.`,example:`The spring newsletter, written, laid out and ready to send.`},{key:`requester`,ask:`Who is asking for it?`,example:`Priya`},{key:`author`,ask:`Who does the work?`,example:`Sam`},{key:`reviewer`,ask:`Who reviews it?`,example:`Noor`},{key:`approver`,ask:`Who signs off?`,example:`Priya`}],tags:[`plan`,`team`,`human-gate`,`loop`]},description:`A plan for people; no step here is an agent's. {{requester}} writes down what is wanted. {{author}} does the work and hands it over with a note on what to look at first. {{reviewer}} reads it against the request, and it goes back to {{author}} while something asked for is missing. {{approver}} signs off, or sends it back with the reason in writing. Each handoff says in writing what is being handed, and one person, named in advance, decides it is done. If the review reaches its third round, stop and decide together what to change.`,nodes:[{id:`request`,kind:`agent`,name:`{{requester}} writes the request`,by:`person`,role:`planner`,brief:`Write what is wanted, by when, and what done looks like, as a short list someone else could check. Say what is not wanted too. If {{author}} has to guess, the request is not finished.`,inputs:[`{{work}}`],outputs:[`REQUEST.md: what is wanted, by when, and what done looks like`]},{id:`do`,kind:`agent`,name:`{{author}} does the work`,by:`person`,role:`builder`,brief:`Do what the request asks. Hand it over with a note: what is done, what is not and why, and what to look at first. On a later round, start from REVIEW.md and answer each point, or say why it does not apply.`,inputs:[`REQUEST.md`,`REVIEW.md (from the second round on)`],outputs:[`the work`,`HANDOFF.md: what is done, what is not, what to look at first`]},{id:`review`,kind:`agent`,name:`{{reviewer}} reviews`,by:`person`,role:`critic`,brief:`Read the work against the request, one line for each thing it asks for: there, with where to see it, or not there. Say what you could not check. You judge and do not fix: send it back. Pass it when everything asked for is there, or is named in the handoff note as left out for a reason you accept.`,inputs:[`the work`,`HANDOFF.md`,`REQUEST.md`],outputs:[`REVIEW.md: one line per thing asked for, ending in pass or send back`]},{id:`sign-off`,kind:`human-gate`,name:`{{approver}} signs off`,prompt:`{{reviewer}} has passed it. REVIEW.md and HANDOFF.md say what was left out. Do you sign off? If you send it back, add the reason to REVIEW.md.`,options:[`sign off`,`send it back`]},{id:`done`,kind:`stop`,name:`Handed over`,outcome:`success`}],edges:[{id:`e-request-do`,from:`request`,to:`do`},{id:`e-do-review`,from:`do`,to:`review`,evidence:[`the work`,`HANDOFF.md`,`REQUEST.md`]},{id:`e-review-fail`,from:`review`,to:`do`,when:`fail`,evidence:[`REVIEW.md`]},{id:`e-review-pass`,from:`review`,to:`sign-off`,when:`pass`},{id:`e-sign-off-done`,from:`sign-off`,to:`done`,when:`pass`},{id:`e-sign-off-back`,from:`sign-off`,to:`do`,when:`fail`,evidence:[`REVIEW.md, with the reason it was sent back`]}],loops:[{id:`review-loop`,name:`Review`,members:[`do`,`review`,`sign-off`],back:[`e-review-fail`,`e-sign-off-back`],mode:`judgment`,bar:{name:`The request`,inspects:[{kind:`file`,ref:`REQUEST.md`},{kind:`artifact`,ref:`the work, with HANDOFF.md`}],acceptance:`Everything REQUEST.md asks for is there, or is named in HANDOFF.md as left out for a reason the reviewer accepts.`},stops:[{kind:`bar-passed`},{kind:`max-iterations`,n:3}]}]}});function n(){let n=[];for(let[r,i]of Object.entries(t)){let t=e(i);t.doc?.template?n.push(t.doc):console.warn(`grooph: skipped ${r}: not a template document`)}return n.sort((e,t)=>e.template.title.localeCompare(t.template.title))}var r=n();export{r as PLAN_TEMPLATES};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{At as e,F as t,Gt as n,Ht as r,I as i,N as a,P as o,V as s,at as c,fn as l,gn as u,it as d,mn as f,ot as p,pn as m,vt as h}from"./share-DV3wsAsJ.js";var ee=`grooph`,g=`graphs`,_=`templates`,v=`runs`,y=()=>{};function b(e){y=e}var x=e=>new Promise((t,n)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>n(e.error)});function te(){return new Promise((e,t)=>{let n=indexedDB.open(ee,3);n.onupgradeneeded=()=>{let e=n.result;e.objectStoreNames.contains(g)||e.createObjectStore(g,{keyPath:`key`}),e.objectStoreNames.contains(_)||e.createObjectStore(_,{keyPath:`id`}),e.objectStoreNames.contains(v)||e.createObjectStore(v,{keyPath:`key`})},n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error),n.onblocked=()=>t(Error(`IndexedDB upgrade blocked by another tab`))})}var S=class{db;name;constructor(e,t){this.db=e,this.name=t}tx(e){return this.db.transaction(this.name,e).objectStore(this.name)}async list(){return x(this.tx(`readonly`).getAll())}async get(e){return x(this.tx(`readonly`).get(e))}async put(e){await x(this.tx(`readwrite`).put(e)),y()}async delete(e){await x(this.tx(`readwrite`).delete(e))}},C=class extends S{persistent=!0;templates;runs;constructor(e){super(e,g),this.templates=new S(e,_),this.runs=new S(e,v)}},w=class{keyOf;records=new Map;constructor(e){this.keyOf=e}async list(){return[...this.records.values()].map(e=>structuredClone(e))}async get(e){let t=this.records.get(e);return t&&structuredClone(t)}async put(e){this.records.set(this.keyOf(e),structuredClone(e))}async delete(e){this.records.delete(e)}},T=class extends w{persistent=!1;templates=new w(e=>e.id);runs=new w(e=>e.key);constructor(){super(e=>e.key)}},E;function D(){return E??=te().then(e=>new C(e),()=>new T),E}function ne(){return`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function O(e){let t=m(e);return t.doc?p(t.doc,{forExport:!0,loops:`advice`}).filter(e=>!k(e)):t.issues}var k=e=>e.code===`E_NO_TARGET`||e.code===`E_NO_GOAL`||e.code===`E_PERSON_STEP_NOT_COMPILED`;function re(e){let t=m(e);return t.doc?p(t.doc,{forExport:!0}).filter(k):[]}function ie(e){let n=s(e.notes,e.working),r=t(e.source,e.working);return{bundle:e,summary:n,diff:r,why:i(r.changes,n.amendments),adoption:a(e.source,e.working,{run:e.run}),moved:e.source.version!==e.working.version,issues:O(e.working)}}function A(e){if(e.at===`graph`)return{kind:`graph`};let t=e.at.indexOf(`:`);return{kind:e.at.slice(0,t),id:e.at.slice(t+1)}}function j(e,t){if(e.kind===`graph`)return`The run`;let n=e=>t.nodes.find(t=>t.id===e);if(e.kind===`node`)return n(e.id)?.name||e.id;if(e.kind===`loop`)return`Loop ${t.loops.find(t=>t.id===e.id)?.name||e.id}`;let r=t.edges.find(t=>t.id===e.id);return r?`Edge ${n(r.from)?.name||r.from} → ${n(r.to)?.name||r.to}`:`Edge ${e.id}`}function M(e,t){if(e.kind===`node`)return{nodes:[e.id],edges:[]};if(e.kind===`edge`){let n=t.edges.find(t=>t.id===e.id);return{nodes:n?[n.from,n.to]:[],edges:[e.id]}}if(e.kind===`loop`){let n=t.loops.find(t=>t.id===e.id);return{nodes:n?.members??[],edges:n?.back??[],loop:e.id}}return{nodes:[],edges:[]}}function N(e,t){return e===`passed`&&t&&![`pass`,`fail`,`halt`,`invalid-evidence`,`started`,`ending`].includes(t)?t:e}function P(e){if(e!==void 0){if(e===`started`)return`running`;if(e!==`ending`)return e===`pass`?`passed`:e===`fail`||e===`invalid-evidence`?`failed`:e===`halt`?`halted`:`passed`}}function F(e,t){let n=e=>e===void 0||Array.isArray(e)&&e.every(e=>typeof e==`string`);if(!n(e)||!n(t)||e===void 0&&t===void 0)return;let r=e??[],i=t??[],a=r.filter(e=>!i.includes(e)),o=i.filter(e=>!r.includes(e));return{removed:a,added:o,kept:r.length-a.length,reordered:a.length===0&&o.length===0}}function I(e,t){let n=o(t.proposal?.patch);if(n.kind===`none`)return{ok:!1,message:`This proposal carries no patch, only its summary; make the change by hand if you agree with it.`};if(n.kind===`other`)return{ok:!1,message:n.why};let r=d(e.working,n.ops);if(!r.ok)return{ok:!1,message:`The patch does not apply to the run's working copy: ${c(r.error)}. Nothing was saved.`};let{source:i}=e,{notes:a,...s}=r.doc,l={...s,id:i.id,name:i.name,version:i.version+1,lineage:{...r.doc.lineage,from:`${i.id}@${i.version}`},...i.notes&&i.notes.length>0?{notes:i.notes}:{}},u=JSON.parse(JSON.stringify(l)),f=m(u);return{ok:!0,doc:u,issues:O(u),graph:f.doc!==void 0}}var L=(e,t)=>t&&e.state===`running`?[...e.timeline].reverse():e.timeline,R=e=>`${e.working.id}/${e.run}`,z=e=>`#/run/${encodeURIComponent(e)}`;function B(e,t){if(!e||!t)return;let n=Date.parse(t)-Date.parse(e);if(!Number.isFinite(n)||n<0)return;let r=Math.round(n/6e4);return r<60?`${r} min`:`${Math.floor(r/60)} h ${r%60} min`}async function V(){return(await(await D()).list()).sort((e,t)=>t.updatedAt-e.updatedAt)}async function H(){return new Set((await(await D()).list()).map(e=>e.doc.id))}async function U(e){let t=Date.now(),n={key:ne(),doc:e,createdAt:t,updatedAt:t};return await(await D()).put(n),n}async function W(){let e=n(`untitled-graph`,await H()),t=e===`untitled-graph`?`Untitled graph`:`Untitled graph ${e.slice(15)}`;return U(h({name:t,id:e}))}async function G(e){let t=await(await D()).get(e);if(!t)return;let r=n(`${t.doc.id}-copy`,await H());return U({...structuredClone(t.doc),id:r,name:`${t.doc.name} (copy)`})}async function K(t,n,r={}){let i=await D(),a=await i.get(t);if(!a)return;let o=e(a.doc,n);await i.put({...a,doc:r.keepId===void 0?o:q(o,r.keepId),updatedAt:Date.now()})}function q(e,t){if(e.id===t)return e;let n=r(e);return n.delete(e.id),n.has(t)?e:{...e,id:t}}async function J(e){await(await D()).delete(e)}function ae(e){let t=f(e);if(t.doc)return{doc:t.doc,issues:[]};let n;try{n=JSON.parse(e)}catch{return{issues:t.issues}}return u(n,`graph`)?{issues:t.issues}:se(n)?{doc:n,issues:t.issues}:{issues:t.issues}}async function Y(e){return U(e)}async function oe(e){let t=l(e),n=(await V()).find(n=>n.doc.id===e.id&&l(n.doc)===t);return n?{record:n,existed:!0}:{record:await U(structuredClone(e)),existed:!1}}var X=e=>typeof e==`object`&&!!e&&!Array.isArray(e),Z=(e,t)=>Array.isArray(e)&&e.every(e=>X(e)&&t.every(t=>typeof e[t]==`string`));function se(e){return!X(e)||typeof e.id!=`string`||typeof e.name!=`string`||!Z(e.nodes,[`id`,`kind`])||!Z(e.edges,[`id`,`from`,`to`])||!Array.isArray(e.loops)?!1:e.loops.every(e=>X(e)&&typeof e.id==`string`&&Array.isArray(e.members)&&Array.isArray(e.back)&&Array.isArray(e.stops))}async function Q(){return(await(await D()).runs.list()).sort((e,t)=>t.savedAt-e.savedAt)}async function ce(e){return(await D()).runs.get(e)}async function le(e){let t=await D(),n=R(e),r=await t.runs.get(n)!==void 0,i={key:n,graphId:e.working.id,run:e.run,bundle:structuredClone(e),savedAt:Date.now()};return await t.runs.put(i),{record:i,replaced:r}}async function ue(e){await(await D()).runs.delete(e)}async function de(e){return Y(structuredClone(e))}async function fe(e,t){let i=await D(),a=(await V()).find(t=>t.doc.id===e.source.id),o=structuredClone(a?.doc??e.source),s=(o.notes??[]).find(e=>$(e)===$(t));if(s&&a)return{record:a,created:!1,already:!0,id:s.id};let c=r(o).has(t.id)?n(t.id,r(o)):t.id;if(o.notes=[...o.notes??[],{...t,id:c}],a){let e={...a,doc:o,updatedAt:Date.now()};return await i.put(e),{record:e,created:!1,already:!1,id:c}}return{record:await Y(o),created:!0,already:!1,id:c}}function $(e){let t=e=>Array.isArray(e)?e.map(t):typeof e==`object`&&e?Object.fromEntries(Object.keys(e).sort().map(n=>[n,t(e[n])])):e,{id:n,...r}=e;return JSON.stringify(t(r))}export{b as A,R as C,j as D,M as E,O,z as S,N as T,F as _,le as a,P as b,J as c,q as d,V as f,B as g,oe as h,fe as i,D as j,re as k,G as l,K as m,ce as n,de as o,ae as p,Q as r,W as s,ue as t,Y as u,A as v,ie as w,I as x,L as y};
|