@jagreehal/workflow 1.6.0 → 1.7.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/dist/visualize.js CHANGED
@@ -1,7 +1,1189 @@
1
- function N(e){if(e<1e3)return`${Math.round(e)}ms`;if(e<6e4)return`${(e/1e3).toFixed(1).replace(/\.0$/,"")}s`;let n=Math.floor(e/6e4),t=Math.round(e%6e4/1e3);return t===0?`${n}m`:`${n}m ${t}s`}function Y(){return`node_${Date.now()}_${Math.random().toString(36).slice(2,8)}`}function ce(e){for(let n of e)if((n.type==="parallel"||n.type==="race"||n.type==="sequence")&&!n.id.startsWith("detected_")||"decisionId"in n)return!0;return!1}function A(e,n={}){if(ce(e))return e;let{minOverlapMs:t=0,maxGapMs:o=5}=n,a=[],r=[];for(let c=0;c<e.length;c++){let s=e[c];s.type==="step"&&s.startTs!==void 0?a.push({node:s,startTs:s.startTs,endTs:s.endTs??s.startTs+(s.durationMs??0),originalIndex:c}):r.push({node:s,originalIndex:c})}if(a.length<=1)return e;a.sort((c,s)=>c.startTs-s.startTs);let u=[],h=[a[0]];for(let c=1;c<a.length;c++){let s=a[c],l=Math.min(...h.map(y=>y.startTs)),g=Math.max(...h.map(y=>y.endTs)),$=s.startTs<=l+o,k=s.startTs<g;if(!$&&!k){u.push(h),h=[s];continue}let w=k?Math.min(s.endTs,g)-s.startTs:0;$||w>=t?h.push(s):(u.push(h),h=[s])}u.push(h);let p=[];for(let c of u){let s=Math.min(...c.map(l=>l.originalIndex));if(c.length===1)p.push({node:c[0].node,position:s});else{let l=c.map(w=>w.node),g=Math.min(...c.map(w=>w.startTs)),$=Math.max(...c.map(w=>w.endTs)),k={type:"parallel",id:`detected_parallel_${g}`,name:`${l.length} parallel steps`,state:de(l),mode:"all",children:l,startTs:g,endTs:$,durationMs:$-g};p.push({node:k,position:s})}}for(let{node:c,originalIndex:s}of r)p.push({node:c,position:s});return p.sort((c,s)=>c.position-s.position),p.map(c=>c.node)}function de(e){return e.some(r=>r.state==="error")?"error":e.some(r=>r.state==="running")?"running":e.some(r=>r.state==="pending")?"pending":(e.every(r=>r.state==="success"||r.state==="cached"),"success")}function le(e={}){return{detect:n=>A(n,e)}}function F(e={}){let{detectParallel:n=!0,parallelDetection:t}=e,o,a,r="pending",u,h,p=new Map,c=[],s=[],l=[],g=Date.now(),$=g;function k(i){return i.stepId??i.stepKey??i.name??Y()}function w(i){if(s.length>0){let d=s[s.length-1];for(let E of d.branches.values())if(E.taken){E.children.push(i),$=Date.now();return}let m=Array.from(d.branches.values())[0];if(m){m.children.push(i),$=Date.now();return}}c.length>0?c[c.length-1].children.push(i):l.push(i),$=Date.now()}function y(i){switch(i.type){case"workflow_start":o=i.workflowId,a=i.ts,r="running",g=Date.now(),$=g;break;case"workflow_success":r="success",h=i.durationMs,$=Date.now();break;case"workflow_error":r="error",u=i.error,h=i.durationMs,$=Date.now();break;case"step_start":{let d=k(i);p.set(d,{id:d,name:i.name,key:i.stepKey,startTs:i.ts,retryCount:0,timedOut:!1}),$=Date.now();break}case"step_success":{let d=k(i),m=p.get(d);if(m){let E={type:"step",id:m.id,name:m.name,key:m.key,state:"success",startTs:m.startTs,endTs:i.ts,durationMs:i.durationMs,...m.retryCount>0&&{retryCount:m.retryCount},...m.timedOut&&{timedOut:!0,timeoutMs:m.timeoutMs}};w(E),p.delete(d)}break}case"step_error":{let d=k(i),m=p.get(d);if(m){let E={type:"step",id:m.id,name:m.name,key:m.key,state:"error",startTs:m.startTs,endTs:i.ts,durationMs:i.durationMs,error:i.error,...m.retryCount>0&&{retryCount:m.retryCount},...m.timedOut&&{timedOut:!0,timeoutMs:m.timeoutMs}};w(E),p.delete(d)}break}case"step_aborted":{let d=k(i),m=p.get(d);if(m){let E={type:"step",id:m.id,name:m.name,key:m.key,state:"aborted",startTs:m.startTs,endTs:i.ts,durationMs:i.durationMs,...m.retryCount>0&&{retryCount:m.retryCount},...m.timedOut&&{timedOut:!0,timeoutMs:m.timeoutMs}};w(E),p.delete(d)}break}case"step_cache_hit":{let m={type:"step",id:k(i),name:i.name,key:i.stepKey,state:"cached",startTs:i.ts,endTs:i.ts,durationMs:0};w(m);break}case"step_cache_miss":break;case"step_complete":break;case"step_timeout":{let d=k(i),m=p.get(d);m&&(m.timedOut=!0,m.timeoutMs=i.timeoutMs),$=Date.now();break}case"step_retry":{let d=k(i),m=p.get(d);m&&(m.retryCount=(i.attempt??1)-1),$=Date.now();break}case"step_retries_exhausted":$=Date.now();break;case"step_skipped":{let m={type:"step",id:k(i),name:i.name,key:i.stepKey,state:"skipped",startTs:i.ts,endTs:i.ts,durationMs:0};w(m);break}}}function x(i){if(i.type==="scope_start")c.push({id:i.scopeId,name:i.name,type:i.scopeType,startTs:i.ts,children:[]}),$=Date.now();else if(i.type==="scope_end"){let d=c.pop();if(d){let m=d.type==="race"?{type:"race",id:d.id,name:d.name,state:R(d.children),startTs:d.startTs,endTs:i.ts,durationMs:i.durationMs,children:d.children,winnerId:i.winnerId}:{type:"parallel",id:d.id,name:d.name,state:R(d.children),startTs:d.startTs,endTs:i.ts,durationMs:i.durationMs,children:d.children,mode:d.type==="allSettled"?"allSettled":"all"};w(m)}}}function T(i){if(i.type==="decision_start")s.push({id:i.decisionId,name:i.name,condition:i.condition,decisionValue:i.decisionValue,startTs:i.ts,branches:new Map}),$=Date.now();else if(i.type==="decision_branch"){let d=s[s.length-1];if(d&&d.id===i.decisionId){let m=i.branchLabel,E=d.branches.get(m);E?E.taken=i.taken:d.branches.set(m,{label:i.branchLabel,condition:i.condition,taken:i.taken,children:[]}),$=Date.now()}}else if(i.type==="decision_end"){let d=s.pop();if(d&&d.id===i.decisionId){let m=Array.from(d.branches.values()),E={type:"decision",id:d.id,name:d.name,state:R(m.flatMap(I=>I.taken?I.children:[])),startTs:d.startTs,endTs:i.ts,durationMs:i.durationMs,condition:d.condition,decisionValue:d.decisionValue,branchTaken:i.branchTaken??d.branchTaken,branches:m};w(E)}}}function R(i){return i.length===0?"success":i.some(I=>I.state==="error")?"error":i.every(I=>I.state==="success"||I.state==="cached")?"success":i.some(I=>I.state==="running")?"running":"pending"}function b(){let i=[...l];for(let[,d]of p)i.push({type:"step",id:d.id,name:d.name,key:d.key,state:"running",startTs:d.startTs,...d.retryCount>0&&{retryCount:d.retryCount},...d.timedOut&&{timedOut:!0,timeoutMs:d.timeoutMs}});return i}function O(){let i=b();return n&&(i=A(i,t)),{root:{type:"workflow",id:o??Y(),workflowId:o??"unknown",state:r,startTs:a,durationMs:h,children:i,error:u},metadata:{createdAt:g,lastUpdatedAt:$}}}function W(){o=void 0,a=void 0,r="pending",u=void 0,h=void 0,p.clear(),c.length=0,s.length=0,l=[],g=Date.now(),$=g}return{handleEvent:y,handleScopeEvent:x,handleDecisionEvent:T,getIR:O,reset:W,get hasActiveSteps(){return p.size>0},get state(){return r}}}function _(e){return e.type==="step"}function Be(e){return e.type==="sequence"}function G(e){return e.type==="parallel"}function U(e){return e.type==="race"}function K(e){return e.type==="decision"}function Le(e){return"children"in e||e.type==="decision"&&"branches"in e}var H="\x1B[0m",ue="\x1B[1m",re="\x1B[2m",pe="\x1B[31m",fe="\x1B[32m",he="\x1B[33m",me="\x1B[34m",ne="\x1B[90m",ge="\x1B[37m";function j(e,n){return n?`${n}${e}${H}`:e}function z(e){return`${ue}${e}${H}`}function v(e){return`${re}${e}${H}`}var M={pending:ge,running:he,success:fe,error:pe,aborted:ne,cached:me,skipped:re+ne};function $e(e){switch(e){case"pending":return"\u25CB";case"running":return"\u27F3";case"success":return"\u2713";case"error":return"\u2717";case"aborted":return"\u2298";case"cached":return"\u21BA";case"skipped":return"\u2298"}}function P(e,n){let t=$e(e);return j(t,n[e])}function X(e,n,t){return j(e,t[n])}function oe(e){return e.replace(/\x1b\[[0-9;]*m/g,"")}var f={topLeft:"\u250C",topRight:"\u2510",bottomLeft:"\u2514",bottomRight:"\u2518",horizontal:"\u2500",vertical:"\u2502",teeRight:"\u251C",teeLeft:"\u2524",teeDown:"\u252C",teeUp:"\u2534",cross:"\u253C"};function ie(e,n){let t=oe(e).length,o=Math.max(0,n-t);return e+" ".repeat(o)}function ke(e,n){if(!n)return f.horizontal.repeat(e);let t=` ${n} `,o=e-t.length;if(o<4)return f.horizontal.repeat(e);let a=2,r=o-a;return f.horizontal.repeat(a)+t+f.horizontal.repeat(r)}function L(){return{name:"ascii",supportsLive:!0,render(e,n){let t={...M,...n.colors},o=n.terminalWidth??60,a=o-4,r=[],u=e.root.name??"workflow",h=z(u);r.push(`${f.topLeft}${ke(o-2,h)}${f.topRight}`),r.push(`${f.vertical}${" ".repeat(o-2)}${f.vertical}`);let p=q(e.root.children,n,t,0);for(let c of p)r.push(`${f.vertical} ${ie(c,a)}${f.vertical}`);if(r.push(`${f.vertical}${" ".repeat(o-2)}${f.vertical}`),e.root.durationMs!==void 0&&n.showTimings){let c=e.root.state==="success"?"Completed":"Failed",l=`${X(c,e.root.state,t)} in ${N(e.root.durationMs)}`;r.push(`${f.vertical} ${ie(l,a)}${f.vertical}`),r.push(`${f.vertical}${" ".repeat(o-2)}${f.vertical}`)}return r.push(`${f.bottomLeft}${f.horizontal.repeat(o-2)}${f.bottomRight}`),r.join(`
2
- `)}}}function q(e,n,t,o){let a=[];for(let r of e)_(r)?a.push(Q(r,n,t)):G(r)?a.push(...we(r,n,t,o)):U(r)?a.push(...be(r,n,t,o)):K(r)&&a.push(...ye(r,n,t,o));return a}function Q(e,n,t){let o=P(e.state,t),a=e.name??e.key??"step",r=X(a,e.state,t),u=`${o} ${r}`;if(n.showKeys&&e.key&&(u+=v(` [key: ${e.key}]`)),e.input!==void 0){let h=typeof e.input=="string"?e.input:JSON.stringify(e.input).slice(0,30);u+=v(` [in: ${h}${h.length>=30?"...":""}]`)}if(e.output!==void 0&&e.state==="success"){let h=typeof e.output=="string"?e.output:JSON.stringify(e.output).slice(0,30);u+=v(` [out: ${h}${h.length>=30?"...":""}]`)}if(n.showTimings&&e.durationMs!==void 0&&(u+=v(` [${N(e.durationMs)}]`)),e.retryCount!==void 0&&e.retryCount>0&&(u+=v(` [${e.retryCount} ${e.retryCount===1?"retry":"retries"}]`)),e.timedOut){let h=e.timeoutMs!==void 0?` ${e.timeoutMs}ms`:"";u+=v(` [timeout${h}]`)}return u}function we(e,n,t,o){let a=[],r=" ".repeat(o),u=P(e.state,t),h=e.name??"parallel",p=e.mode==="allSettled"?" (allSettled)":"";if(a.push(`${r}${f.teeRight}${f.teeDown}${f.horizontal} ${u} ${z(h)}${p}`),e.children.length===0)a.push(`${r}${f.vertical} ${v("(operations not individually tracked)")}`),a.push(`${r}${f.vertical} ${v("(wrap each operation with step() to see individual steps)")}`);else for(let c=0;c<e.children.length;c++){let s=e.children[c],g=c===e.children.length-1?`${r}${f.vertical} ${f.bottomLeft}`:`${r}${f.vertical} ${f.teeRight}`;if(_(s))a.push(`${g} ${Q(s,n,t)}`);else{let $=q([s],n,t,o+1);for(let k of $)a.push(`${r}${f.vertical} ${k}`)}}return n.showTimings&&e.durationMs!==void 0&&a.push(`${r}${f.bottomLeft}${f.horizontal}${f.horizontal} ${v(`[${N(e.durationMs)}]`)}`),a}function be(e,n,t,o){let a=[],r=" ".repeat(o),u=P(e.state,t),h=e.name??"race";if(a.push(`${r}${f.teeRight}\u26A1 ${u} ${z(h)}`),e.children.length===0)a.push(`${r}${f.vertical} ${v("(operations not individually tracked)")}`),a.push(`${r}${f.vertical} ${v("(wrap each operation with step() to see individual steps)")}`);else for(let p=0;p<e.children.length;p++){let c=e.children[p],l=p===e.children.length-1?`${r}${f.vertical} ${f.bottomLeft}`:`${r}${f.vertical} ${f.teeRight}`,$=e.winnerId&&c.id===e.winnerId?v(" (winner)"):"";if(_(c))a.push(`${l} ${Q(c,n,t)}${$}`);else{let k=q([c],n,t,o+1);for(let w of k)a.push(`${r}${f.vertical} ${w}`)}}return n.showTimings&&e.durationMs!==void 0&&a.push(`${r}${f.bottomLeft}${f.horizontal}${f.horizontal} ${v(`[${N(e.durationMs)}]`)}`),a}function ye(e,n,t,o){let a=[],r=" ".repeat(o),u=P(e.state,t),h=e.name??"decision",p=e.condition?v(` (${e.condition})`):"",c=e.decisionValue!==void 0?v(` = ${String(e.decisionValue)}`):"",s=e.branchTaken!==void 0?v(` \u2192 ${String(e.branchTaken)}`):"";a.push(`${r}${f.teeRight}${f.teeDown}${f.horizontal} ${u} ${z(h)}${p}${c}${s}`);for(let l=0;l<e.branches.length;l++){let g=e.branches[l],k=l===e.branches.length-1?`${r}${f.vertical} ${f.bottomLeft}`:`${r}${f.vertical} ${f.teeRight}`,w=g.taken?"\u2713":"\u2298",y=g.taken?t.success:t.skipped,x=j(`${w} ${g.label}`,y),T=g.condition?v(` (${g.condition})`):"";if(a.push(`${k} ${x}${T}`),g.children.length>0){let R=q(g.children,n,t,o+1);for(let b of R)a.push(`${r}${f.vertical} ${b}`)}else g.taken||a.push(`${r}${f.vertical} ${v("(skipped)")}`)}return n.showTimings&&e.durationMs!==void 0&&a.push(`${r}${f.bottomLeft}${f.horizontal}${f.horizontal} ${v(`[${N(e.durationMs)}]`)}`),a}function Se(){return[" classDef pending fill:#f3f4f6,stroke:#9ca3af,stroke-width:2px,color:#374151"," classDef running fill:#fef3c7,stroke:#f59e0b,stroke-width:3px,color:#92400e"," classDef success fill:#d1fae5,stroke:#10b981,stroke-width:3px,color:#065f46"," classDef error fill:#fee2e2,stroke:#ef4444,stroke-width:3px,color:#991b1b"," classDef aborted fill:#f3f4f6,stroke:#6b7280,stroke-width:2px,color:#4b5563,stroke-dasharray: 5 5"," classDef cached fill:#dbeafe,stroke:#3b82f6,stroke-width:3px,color:#1e40af"," classDef skipped fill:#f9fafb,stroke:#d1d5db,stroke-width:2px,color:#6b7280,stroke-dasharray: 5 5"]}var se=0;function V(e="node"){return`${e}_${++se}`}function ve(){se=0}function D(e){return e.replace(/[{}[\]()]/g,"").replace(/[<>]/g,"").replace(/"/g,"'").trim()}function ae(e){return D(e).replace(/[[\]]/g,"")}function J(){return{name:"mermaid",supportsLive:!1,render(e,n){ve();let t=[];t.push("flowchart TD");let o="start";t.push(` ${o}(("\u25B6 Start"))`);let a=o;for(let r of e.root.children){let u=Z(r,n,t);t.push(` ${a} --> ${u.entryId}`),a=u.exitId}if(e.root.state==="success"||e.root.state==="error"){let r="finish",u=e.root.state==="success"?"\u2713":"\u2717",h=e.root.state==="success"?"Done":"Failed",p=`(("${u} ${h}"))`,c=e.root.state==="success"?":::success":":::error";t.push(` ${r}${p}${c}`),t.push(` ${a} --> ${r}`)}return t.push(""),t.push(...Se()),t.join(`
3
- `)}}}function Z(e,n,t){if(_(e))return Ee(e,n,t);if(G(e))return xe(e,n,t);if(U(e))return De(e,n,t);if(K(e))return Ie(e,n,t);let o=V("unknown");return t.push(` ${o}[Unknown Node]`),{entryId:o,exitId:o}}function Ee(e,n,t){let o=e.key?`step_${e.key.replace(/[^a-zA-Z0-9]/g,"_")}`:V("step"),a=D(e.name??e.key??"Step"),r=n.showTimings&&e.durationMs!==void 0?` ${N(e.durationMs)}`:"",u="";switch(e.state){case"success":u="\u2713 ";break;case"error":u="\u2717 ";break;case"cached":u="\u{1F4BE} ";break;case"running":u="\u23F3 ";break;case"skipped":u="\u2298 ";break}let h="";if(e.input!==void 0){let g=typeof e.input=="string"?D(e.input):D(JSON.stringify(e.input).slice(0,20));h+=`\\nin: ${g}`}if(e.output!==void 0&&e.state==="success"){let g=typeof e.output=="string"?D(e.output):D(JSON.stringify(e.output).slice(0,20));h+=`\\nout: ${g}`}let p="";if(e.retryCount!==void 0&&e.retryCount>0&&(p+=`\\n\u21BB ${e.retryCount} retr${e.retryCount===1?"y":"ies"}`),e.timedOut){let g=e.timeoutMs!==void 0?`${e.timeoutMs}ms`:"";p+=`\\n\u23F1 timeout ${g}`}let c=(u+a+h+p+r).trim(),s=e.state,l;switch(e.state){case"error":l=`{{${c}}}`;break;case"cached":l=`[(${c})]`;break;case"skipped":l=`[${c}]:::skipped`;break;default:l=`[${c}]`}return t.push(` ${o}${l}:::${s}`),{entryId:o,exitId:o}}function xe(e,n,t){let o=V("parallel"),a=`${o}_fork`,r=`${o}_join`,u=ae(e.name??"Parallel"),h=e.mode==="allSettled"?" (allSettled)":"";if(e.children.length===0){let s=o,l=D(`${u}${h}`),g="operations not individually tracked",$=n.showTimings&&e.durationMs!==void 0?` ${N(e.durationMs)}`:"";return t.push(` ${s}[${l}${$}\\n${g}]:::${e.state}`),{entryId:s,exitId:s}}t.push(` subgraph ${o}["${u}${h}"]`),t.push(" direction TB"),t.push(` ${a}{"\u26A1 Fork"}`);let p=[];for(let s of e.children){let l=Z(s,n,t);t.push(` ${a} --> ${l.entryId}`),p.push(l.exitId)}t.push(` ${r}{"\u2713 Join"}`);for(let s of p)t.push(` ${s} --> ${r}`);t.push(" end");let c=e.state;return t.push(` class ${o} ${c}`),{entryId:a,exitId:r}}function De(e,n,t){let o=V("race"),a=`${o}_start`,r=`${o}_end`,u=ae(e.name??"Race");if(e.children.length===0){let s=o,l=D(u),g="operations not individually tracked",$=n.showTimings&&e.durationMs!==void 0?` ${N(e.durationMs)}`:"";return t.push(` ${s}[\u26A1 ${l}${$}\\n${g}]:::${e.state}`),{entryId:s,exitId:s}}t.push(` subgraph ${o}["\u26A1 ${u}"]`),t.push(" direction TB"),t.push(` ${a}(("\u{1F3C1} Start"))`);let h=[],p;for(let s of e.children){let l=Z(s,n,t),g=_(s)&&e.winnerId===s.id;t.push(` ${a} --> ${l.entryId}`),g&&(p=l.exitId),h.push({exitId:l.exitId,isWinner:g})}t.push(` ${r}(("\u2713 First"))`);for(let{exitId:s,isWinner:l}of h)l&&p?t.push(` ${s} ==>|\u{1F3C6} Winner| ${r}`):e.winnerId?t.push(` ${s} -. cancelled .-> ${r}`):t.push(` ${s} --> ${r}`);t.push(" end");let c=e.state;return t.push(` class ${o} ${c}`),{entryId:a,exitId:r}}function Ie(e,n,t){let o=e.key?`decision_${e.key.replace(/[^a-zA-Z0-9]/g,"_")}`:V("decision"),a=D(e.condition??"condition"),r=e.decisionValue!==void 0?` = ${D(String(e.decisionValue)).slice(0,30)}`:"",u=`${a}${r}`.trim();t.push(` ${o}{${u}}`);let h=[],p;for(let c of e.branches){let s=`${o}_${c.label.replace(/[^a-zA-Z0-9]/g,"_")}`,l=D(c.label),g=c.taken?`${l} \u2713`:`${l} skipped`,$=c.taken?":::success":":::skipped";t.push(` ${s}[${g}]${$}`);let k=c.condition?`|${D(c.condition).replace(/\|/g,"")}|`:"";if(t.push(` ${o} -->${k} ${s}`),c.children.length>0){let w=s;for(let y of c.children){let x=Z(y,n,t);t.push(` ${w} --> ${x.entryId}`),w=x.exitId}h.push(w),c.taken&&(p=w)}else h.push(s),c.taken&&(p=s)}return p?{entryId:o,exitId:p}:{entryId:o,exitId:o}}var C={clearToEnd:"\x1B[J",cursorUp:e=>`\x1B[${e}A`,cursorToStart:"\x1B[G",hideCursor:"\x1B[?25l",showCursor:"\x1B[?25h",saveCursor:"\x1B[s",restoreCursor:"\x1B[u"};function Ne(e={}){let{workflowName:n,detectParallel:t=!0,showTimings:o=!0,showKeys:a=!1,colors:r,stream:u=process.stdout,updateInterval:h=100}=e,p=F({detectParallel:t}),c=L(),s={showTimings:o,showKeys:a,terminalWidth:u.columns??80,colors:{...M,...r}},l=!1,g="",$=0,k=null,w=!1;function y(S){u.writable&&u.write(S)}function x(){if(!l)return;let S=W(),B=c.render(S,s);B!==g&&($>0&&(y(C.cursorUp($)),y(C.cursorToStart),y(C.clearToEnd)),y(B),y(`
4
- `),g=B,$=B.split(`
5
- `).length)}function T(){l&&(w=!0,k===null&&(k=setTimeout(()=>{k=null,w&&(w=!1,x())},h)))}function R(S){if(S.type==="scope_start"||S.type==="scope_end"){b(S);return}p.handleEvent(S),l&&(S.type==="workflow_start"||S.type==="workflow_success"||S.type==="workflow_error"?x():T())}function b(S){p.handleScopeEvent(S),l&&T()}function O(S){p.handleDecisionEvent(S),l&&T()}function W(){let S=p.getIR();return n&&!S.root.name&&(S.root.name=n),S}function i(){return c.render(W(),s)}function d(){l||(l=!0,g="",$=0,y(C.hideCursor),x())}function m(){if(!l)return;l=!1,k!==null&&(clearTimeout(k),k=null);let S=W(),B=c.render(S,s);$>0&&(y(C.cursorUp($)),y(C.cursorToStart),y(C.clearToEnd)),y(B),y(`
6
- `),y(C.showCursor)}function E(){k!==null&&(clearTimeout(k),k=null),w=!1,x()}function I(){p.reset(),g="",$=0}return{handleEvent:R,handleScopeEvent:b,handleDecisionEvent:O,getIR:W,render:i,start:d,stop:m,refresh:E,reset:I}}function ee(e,n={}){let{condition:t,value:o,name:a,workflowId:r=crypto.randomUUID(),emit:u}=n,h=Date.now(),p,c=[];function s(g,$,k){c.push({label:g,condition:k,taken:$}),$&&(p=g),u?.({type:"decision_branch",workflowId:r,decisionId:e,branchLabel:g,condition:k,taken:$,ts:Date.now()})}function l(){let g=Date.now()-h;u?.({type:"decision_end",workflowId:r,decisionId:e,branchTaken:p,ts:Date.now(),durationMs:g})}return u?.({type:"decision_start",workflowId:r,decisionId:e,condition:t,decisionValue:o,name:a,ts:h}),{takeBranch:s,end:l,getBranchTaken:()=>p,getBranches:()=>[...c]}}function Te(e,n,t={}){let o=ee(e,{...t,condition:t.condition??String(n),value:t.value??n});return{...o,condition:n,then:()=>{o.takeBranch("if",!0)},else:()=>{o.takeBranch("else",!0)}}}function Re(e,n,t={}){let o=ee(e,{...t,condition:t.condition??`switch(${String(n)})`,value:n});return{...o,value:n,case:(a,r)=>{o.takeBranch(`case '${a}'`,r,`value === '${a}'`)},default:a=>{o.takeBranch("default",a)}}}function te(e={}){let{workflowName:n,detectParallel:t=!0,showTimings:o=!0,showKeys:a=!1,colors:r}=e,u=F({detectParallel:t}),h=new Set,p=L(),c=J(),s={showTimings:o,showKeys:a,terminalWidth:process.stdout?.columns??80,colors:{...M,...r}};function l(){if(h.size>0){let b=u.getIR();for(let O of h)O(b)}}function g(b){if(b.type==="scope_start"||b.type==="scope_end"){$(b);return}u.handleEvent(b),b.type,l()}function $(b){u.handleScopeEvent(b),l()}function k(b){u.handleDecisionEvent(b),l()}function w(){let b=u.getIR();return n&&!b.root.name&&(b.root.name=n),b}function y(){let b=w();return p.render(b,s)}function x(b){let O=w();switch(b){case"ascii":return p.render(O,s);case"mermaid":return c.render(O,s);case"json":return JSON.stringify(O,null,2);default:throw new Error(`Unknown format: ${b}`)}}function T(){u.reset(),l()}function R(b){return h.add(b),()=>h.delete(b)}return{handleEvent:g,handleScopeEvent:$,handleDecisionEvent:k,getIR:w,render:y,renderAs:x,reset:T,onUpdate:R}}function rt(e,n={}){let t=te(n);for(let o of e)o.type.startsWith("decision_")?t.handleDecisionEvent(o):t.handleEvent(o);return t.render()}function ot(e={}){let n=[];return{handleEvent:t=>{n.push(t)},handleDecisionEvent:t=>{n.push(t)},getEvents:()=>[...n],getWorkflowEvents:()=>n.filter(t=>!t.type.startsWith("decision_")),getDecisionEvents:()=>n.filter(t=>t.type.startsWith("decision_")),clear:()=>{n.length=0},visualize:()=>{let t=te(e);for(let o of n)o.type.startsWith("decision_")?t.handleDecisionEvent(o):t.handleEvent(o);return t.render()},visualizeAs:t=>{let o=te(e);for(let a of n)a.type.startsWith("decision_")?o.handleDecisionEvent(a):o.handleEvent(a);return o.renderAs(t)}}}export{L as asciiRenderer,ot as createEventCollector,F as createIRBuilder,Ne as createLiveVisualizer,le as createParallelDetector,te as createVisualizer,M as defaultColorScheme,A as detectParallelGroups,Le as hasChildren,K as isDecisionNode,G as isParallelNode,U as isRaceNode,Be as isSequenceNode,_ as isStepNode,J as mermaidRenderer,ee as trackDecision,Te as trackIf,Re as trackSwitch,rt as visualizeEvents};
1
+ function H(e){if(e<1e3)return`${Math.round(e)}ms`;if(e<6e4)return`${(e/1e3).toFixed(1).replace(/\.0$/,"")}s`;let r=Math.floor(e/6e4),t=Math.round(e%6e4/1e3);return t===0?`${r}m`:`${r}m ${t}s`}function le(){return`node_${Date.now()}_${Math.random().toString(36).slice(2,8)}`}function Ae(e){for(let r of e)if((r.type==="parallel"||r.type==="race"||r.type==="sequence")&&!r.id.startsWith("detected_")||"decisionId"in r)return!0;return!1}function oe(e,r={}){if(Ae(e))return e;let{minOverlapMs:t=0,maxGapMs:a=5}=r,o=[],n=[];for(let u=0;u<e.length;u++){let s=e[u];s.type==="step"&&s.startTs!==void 0?o.push({node:s,startTs:s.startTs,endTs:s.endTs??s.startTs+(s.durationMs??0),originalIndex:u}):n.push({node:s,originalIndex:u})}if(o.length<=1)return e;o.sort((u,s)=>u.startTs-s.startTs);let c=[],p=[o[0]];for(let u=1;u<o.length;u++){let s=o[u],l=Math.min(...p.map(R=>R.startTs)),f=Math.max(...p.map(R=>R.endTs)),h=s.startTs<=l+a,k=s.startTs<f;if(!h&&!k){c.push(p),p=[s];continue}let v=k?Math.min(s.endTs,f)-s.startTs:0;h||v>=t?p.push(s):(c.push(p),p=[s])}c.push(p);let d=[];for(let u of c){let s=Math.min(...u.map(l=>l.originalIndex));if(u.length===1)d.push({node:u[0].node,position:s});else{let l=u.map(v=>v.node),f=Math.min(...u.map(v=>v.startTs)),h=Math.max(...u.map(v=>v.endTs)),k={type:"parallel",id:`detected_parallel_${f}`,name:`${l.length} parallel steps`,state:ze(l),mode:"all",children:l,startTs:f,endTs:h,durationMs:h-f};d.push({node:k,position:s})}}for(let{node:u,originalIndex:s}of n)d.push({node:u,position:s});return d.sort((u,s)=>u.position-s.position),d.map(u=>u.node)}function ze(e){return e.some(n=>n.state==="error")?"error":e.some(n=>n.state==="running")?"running":e.some(n=>n.state==="pending")?"pending":(e.every(n=>n.state==="success"||n.state==="cached"),"success")}function Fe(e={}){return{detect:r=>oe(r,e)}}function q(e={}){let{detectParallel:r=!0,parallelDetection:t,enableSnapshots:a=!1,maxSnapshots:o=1e3}=e,n,c,p="pending",d,u,s=new Map,l=[],f=[],h=[],k=Date.now(),v=k,R={onAfterStep:new Map},T=[],B=0;function O(i){return i.stepId??i.stepKey??i.name??le()}function g(i){if(f.length>0){let m=f[f.length-1];for(let P of m.branches.values())if(P.taken){P.children.push(i),v=Date.now();return}let b=Array.from(m.branches.values())[0];if(b){b.children.push(i),v=Date.now();return}}l.length>0?l[l.length-1].children.push(i):h.push(i),v=Date.now()}function I(i){if(!a)return;let m=M(),b=new Map;for(let[F,G]of s)b.set(F,{id:G.id,name:G.name,key:G.key,startTs:G.startTs,retryCount:G.retryCount,timedOut:G.timedOut,timeoutMs:G.timeoutMs});let P={id:`snapshot_${B}`,eventIndex:B,event:structuredClone(i),ir:structuredClone(m),timestamp:Date.now(),activeSteps:b};T.push(P),T.length>o&&T.shift(),B++}function w(i){switch(i.type){case"workflow_start":n=i.workflowId,c=i.ts,p="running",k=Date.now(),v=k,R.onAfterStep=new Map;break;case"workflow_success":p="success",u=i.durationMs,v=Date.now();break;case"workflow_error":p="error",d=i.error,u=i.durationMs,v=Date.now();break;case"step_start":{let m=O(i);s.set(m,{id:m,name:i.name,key:i.stepKey,startTs:i.ts,retryCount:0,timedOut:!1}),v=Date.now();break}case"step_success":{let m=O(i),b=s.get(m);if(b){let P={type:"step",id:b.id,name:b.name,key:b.key,state:"success",startTs:b.startTs,endTs:i.ts,durationMs:i.durationMs,...b.retryCount>0&&{retryCount:b.retryCount},...b.timedOut&&{timedOut:!0,timeoutMs:b.timeoutMs}};g(P),s.delete(m)}break}case"step_error":{let m=O(i),b=s.get(m);if(b){let P={type:"step",id:b.id,name:b.name,key:b.key,state:"error",startTs:b.startTs,endTs:i.ts,durationMs:i.durationMs,error:i.error,...b.retryCount>0&&{retryCount:b.retryCount},...b.timedOut&&{timedOut:!0,timeoutMs:b.timeoutMs}};g(P),s.delete(m)}break}case"step_aborted":{let m=O(i),b=s.get(m);if(b){let P={type:"step",id:b.id,name:b.name,key:b.key,state:"aborted",startTs:b.startTs,endTs:i.ts,durationMs:i.durationMs,...b.retryCount>0&&{retryCount:b.retryCount},...b.timedOut&&{timedOut:!0,timeoutMs:b.timeoutMs}};g(P),s.delete(m)}break}case"step_cache_hit":{let b={type:"step",id:O(i),name:i.name,key:i.stepKey,state:"cached",startTs:i.ts,endTs:i.ts,durationMs:0};g(b);break}case"step_cache_miss":break;case"step_complete":break;case"step_timeout":{let m=O(i),b=s.get(m);b&&(b.timedOut=!0,b.timeoutMs=i.timeoutMs),v=Date.now();break}case"step_retry":{let m=O(i),b=s.get(m);b&&(b.retryCount=(i.attempt??1)-1),v=Date.now();break}case"step_retries_exhausted":v=Date.now();break;case"step_skipped":{let b={type:"step",id:O(i),name:i.name,key:i.stepKey,state:"skipped",startTs:i.ts,endTs:i.ts,durationMs:0};g(b);break}case"hook_should_run":{let m={type:"shouldRun",state:"success",ts:i.ts,durationMs:i.durationMs,context:{result:i.result,skipped:i.skipped}};R.shouldRun=m,v=Date.now();break}case"hook_should_run_error":{let m={type:"shouldRun",state:"error",ts:i.ts,durationMs:i.durationMs,error:i.error};R.shouldRun=m,v=Date.now();break}case"hook_before_start":{let m={type:"onBeforeStart",state:"success",ts:i.ts,durationMs:i.durationMs,context:{result:i.result,skipped:i.skipped}};R.onBeforeStart=m,v=Date.now();break}case"hook_before_start_error":{let m={type:"onBeforeStart",state:"error",ts:i.ts,durationMs:i.durationMs,error:i.error};R.onBeforeStart=m,v=Date.now();break}case"hook_after_step":{let m={type:"onAfterStep",state:"success",ts:i.ts,durationMs:i.durationMs,context:{stepKey:i.stepKey}};R.onAfterStep.set(i.stepKey,m),v=Date.now();break}case"hook_after_step_error":{let m={type:"onAfterStep",state:"error",ts:i.ts,durationMs:i.durationMs,error:i.error,context:{stepKey:i.stepKey}};R.onAfterStep.set(i.stepKey,m),v=Date.now();break}}I(i)}function $(i){if(i.type==="scope_start")l.push({id:i.scopeId,name:i.name,type:i.scopeType,startTs:i.ts,children:[]}),v=Date.now();else if(i.type==="scope_end"){let m=l.pop();if(m){let b=m.type==="race"?{type:"race",id:m.id,name:m.name,state:C(m.children),startTs:m.startTs,endTs:i.ts,durationMs:i.durationMs,children:m.children,winnerId:i.winnerId}:{type:"parallel",id:m.id,name:m.name,state:C(m.children),startTs:m.startTs,endTs:i.ts,durationMs:i.durationMs,children:m.children,mode:m.type==="allSettled"?"allSettled":"all"};g(b)}}}function W(i){if(i.type==="decision_start")f.push({id:i.decisionId,name:i.name,condition:i.condition,decisionValue:i.decisionValue,startTs:i.ts,branches:new Map}),v=Date.now();else if(i.type==="decision_branch"){let m=f[f.length-1];if(m&&m.id===i.decisionId){let b=i.branchLabel,P=m.branches.get(b);P?P.taken=i.taken:m.branches.set(b,{label:i.branchLabel,condition:i.condition,taken:i.taken,children:[]}),v=Date.now()}}else if(i.type==="decision_end"){let m=f.pop();if(m&&m.id===i.decisionId){let b=Array.from(m.branches.values()),P={type:"decision",id:m.id,name:m.name,state:C(b.flatMap(F=>F.taken?F.children:[])),startTs:m.startTs,endTs:i.ts,durationMs:i.durationMs,condition:m.condition,decisionValue:m.decisionValue,branchTaken:i.branchTaken??m.branchTaken,branches:b};g(P)}}}function C(i){return i.length===0?"success":i.some(F=>F.state==="error")?"error":i.every(F=>F.state==="success"||F.state==="cached")?"success":i.some(F=>F.state==="running")?"running":"pending"}function D(){let i=[...h];for(let[,m]of s)i.push({type:"step",id:m.id,name:m.name,key:m.key,state:"running",startTs:m.startTs,...m.retryCount>0&&{retryCount:m.retryCount},...m.timedOut&&{timedOut:!0,timeoutMs:m.timeoutMs}});return i}function M(){let i=D();r&&(i=oe(i,t));let m={type:"workflow",id:n??le(),workflowId:n??"unknown",state:p,startTs:c,durationMs:u,children:i,error:d},b=R.shouldRun!==void 0||R.onBeforeStart!==void 0||R.onAfterStep.size>0;return{root:m,metadata:{createdAt:k,lastUpdatedAt:v},...b&&{hooks:R}}}function N(){n=void 0,c=void 0,p="pending",d=void 0,u=void 0,s.clear(),l.length=0,f.length=0,h=[],k=Date.now(),v=k,R={onAfterStep:new Map},T.length=0,B=0}function S(){return[...T]}function x(i){return T[i]}function E(i){return T[i]?.ir}function L(){T.length=0,B=0}return{handleEvent:w,handleScopeEvent:$,handleDecisionEvent:W,getIR:M,reset:N,getSnapshots:S,getSnapshotAt:x,getIRAt:E,clearSnapshots:L,get hasActiveSteps(){return s.size>0},get state(){return p},get snapshotCount(){return T.length},get snapshotsEnabled(){return a}}}function V(e){return e.type==="step"}function Ct(e){return e.type==="sequence"}function J(e){return e.type==="parallel"}function Y(e){return e.type==="race"}function X(e){return e.type==="decision"}function Ot(e){return"children"in e||e.type==="decision"&&"branches"in e}var ue="\x1B[0m",Ve="\x1B[1m",Ie="\x1B[2m",Ue="\x1B[31m",je="\x1B[32m",Ke="\x1B[33m",Ge="\x1B[34m",Ee="\x1B[90m",qe="\x1B[37m";function U(e,r){return r?`${r}${e}${ue}`:e}function te(e){return`${Ve}${e}${ue}`}function _(e){return`${Ie}${e}${ue}`}var j={pending:qe,running:Ke,success:je,error:Ue,aborted:Ee,cached:Ge,skipped:Ie+Ee};function Je(e){switch(e){case"pending":return"\u25CB";case"running":return"\u27F3";case"success":return"\u2713";case"error":return"\u2717";case"aborted":return"\u2298";case"cached":return"\u21BA";case"skipped":return"\u2298"}}function ne(e,r){let t=Je(e);return U(t,r[e])}function pe(e,r,t){return U(e,t[r])}function De(e){return e.replace(/\x1b\[[0-9;]*m/g,"")}var y={topLeft:"\u250C",topRight:"\u2510",bottomLeft:"\u2514",bottomRight:"\u2518",horizontal:"\u2500",vertical:"\u2502",teeRight:"\u251C",teeLeft:"\u2524",teeDown:"\u252C",teeUp:"\u2534",cross:"\u253C"},Z={cold:"\x1B[34m",cool:"\x1B[36m",neutral:"",warm:"\x1B[33m",hot:"\x1B[31m",critical:"\x1B[41m"},Ye="\x1B[0m";function Xe(e){return e<.2?Z.cold:e<.4?Z.cool:e<.6?Z.neutral:e<.8?Z.warm:e<.95?Z.hot:Z.critical}function Te(e,r){let t=Xe(r);return t?`${t}${e}${Ye}`:e}var Ne="\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";function Ze(e,r=10){if(e.length===0)return"";let t=e.slice(-r),a=Math.min(...t),n=Math.max(...t)-a||1;return t.map(c=>{let p=(c-a)/n,d=Math.floor(p*(Ne.length-1));return Ne[d]}).join("")}function fe(e,r){let t=De(e).length,a=Math.max(0,r-t);return e+" ".repeat(a)}function Qe(e,r){if(!r)return y.horizontal.repeat(e);let t=` ${r} `,a=e-t.length;if(a<4)return y.horizontal.repeat(e);let o=2,n=a-o;return y.horizontal.repeat(o)+t+y.horizontal.repeat(n)}function Me(e,r,t){let a=e.state==="success"?U("\u2699",t.success):U("\u26A0",t.error),o=e.durationMs!==void 0?_(` [${H(e.durationMs)}]`):"",n="";e.type==="shouldRun"&&e.context?.skipped?n=_(" \u2192 workflow skipped"):e.type==="shouldRun"&&e.context?.result===!0?n=_(" \u2192 proceed"):e.type==="onBeforeStart"&&e.context?.skipped?n=_(" \u2192 workflow skipped"):e.type==="onAfterStep"&&e.context?.stepKey&&(n=_(` (${e.context.stepKey})`));let c=e.state==="error"&&e.error?_(` error: ${String(e.error)}`):"";return`${a} ${_(r)}${n}${o}${c}`}function et(e,r){let t=[];return e.shouldRun&&t.push(Me(e.shouldRun,"shouldRun",r)),e.onBeforeStart&&t.push(Me(e.onBeforeStart,"onBeforeStart",r)),t.length>0&&t.push(_("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),t}function Q(){return{name:"ascii",supportsLive:!0,render(e,r){let t={...j,...r.colors},a=r.terminalWidth??60,o=a-4,n=[],c=e.root.name??"workflow",p=te(c);if(n.push(`${y.topLeft}${Qe(a-2,p)}${y.topRight}`),n.push(`${y.vertical}${" ".repeat(a-2)}${y.vertical}`),e.hooks){let u=et(e.hooks,t);for(let s of u)n.push(`${y.vertical} ${fe(s,o)}${y.vertical}`)}let d=ie(e.root.children,r,t,0,e.hooks);for(let u of d)n.push(`${y.vertical} ${fe(u,o)}${y.vertical}`);if(n.push(`${y.vertical}${" ".repeat(a-2)}${y.vertical}`),e.root.durationMs!==void 0&&r.showTimings){let u=e.root.state==="success"?"Completed":"Failed",l=`${pe(u,e.root.state,t)} in ${H(e.root.durationMs)}`;n.push(`${y.vertical} ${fe(l,o)}${y.vertical}`),n.push(`${y.vertical}${" ".repeat(a-2)}${y.vertical}`)}return n.push(`${y.bottomLeft}${y.horizontal.repeat(a-2)}${y.bottomRight}`),n.join(`
2
+ `)}}}function ie(e,r,t,a,o){let n=[];for(let c of e)V(c)?n.push(me(c,r,t,o)):J(c)?n.push(...tt(c,r,t,a,o)):Y(c)?n.push(...nt(c,r,t,a,o)):X(c)&&n.push(...rt(c,r,t,a,o));return n}function me(e,r,t,a){let o=ne(e.state,t),n=e.name??e.key??"step",c=r,p=e.name??e.id,d=c.showHeatmap&&c.heatmapData?c.heatmapData.heat.get(e.id)??c.heatmapData.heat.get(p):void 0,u;d!==void 0?u=Te(n,d):u=pe(n,e.state,t);let s=`${o} ${u}`;if(r.showKeys&&e.key&&(s+=_(` [key: ${e.key}]`)),e.input!==void 0){let l=typeof e.input=="string"?e.input:JSON.stringify(e.input).slice(0,30);s+=_(` [in: ${l}${l.length>=30?"...":""}]`)}if(e.output!==void 0&&e.state==="success"){let l=typeof e.output=="string"?e.output:JSON.stringify(e.output).slice(0,30);s+=_(` [out: ${l}${l.length>=30?"...":""}]`)}if(r.showTimings&&e.durationMs!==void 0){let l=H(e.durationMs),f=d!==void 0?Te(`[${l}]`,d):_(`[${l}]`);s+=` ${f}`}if(c.showSparklines&&c.timingHistory){let l=c.timingHistory.get(p);l&&l.length>1&&(s+=` ${_(Ze(l))}`)}if(e.retryCount!==void 0&&e.retryCount>0&&(s+=_(` [${e.retryCount} ${e.retryCount===1?"retry":"retries"}]`)),e.timedOut){let l=e.timeoutMs!==void 0?` ${e.timeoutMs}ms`:"";s+=_(` [timeout${l}]`)}if(a&&e.key&&a.onAfterStep.has(e.key)){let l=a.onAfterStep.get(e.key),f=l.state==="success"?U("\u2699",t.success):U("\u26A0",t.error),h=l.durationMs!==void 0?_(` ${H(l.durationMs)}`):"";s+=` ${f}${h}`}return s}function tt(e,r,t,a,o){let n=[],c=" ".repeat(a),p=ne(e.state,t),d=e.name??"parallel",u=e.mode==="allSettled"?" (allSettled)":"";if(n.push(`${c}${y.teeRight}${y.teeDown}${y.horizontal} ${p} ${te(d)}${u}`),e.children.length===0)n.push(`${c}${y.vertical} ${_("(operations not individually tracked)")}`),n.push(`${c}${y.vertical} ${_("(wrap each operation with step() to see individual steps)")}`);else for(let s=0;s<e.children.length;s++){let l=e.children[s],h=s===e.children.length-1?`${c}${y.vertical} ${y.bottomLeft}`:`${c}${y.vertical} ${y.teeRight}`;if(V(l))n.push(`${h} ${me(l,r,t,o)}`);else{let k=ie([l],r,t,a+1,o);for(let v of k)n.push(`${c}${y.vertical} ${v}`)}}return r.showTimings&&e.durationMs!==void 0&&n.push(`${c}${y.bottomLeft}${y.horizontal}${y.horizontal} ${_(`[${H(e.durationMs)}]`)}`),n}function nt(e,r,t,a,o){let n=[],c=" ".repeat(a),p=ne(e.state,t),d=e.name??"race";if(n.push(`${c}${y.teeRight}\u26A1 ${p} ${te(d)}`),e.children.length===0)n.push(`${c}${y.vertical} ${_("(operations not individually tracked)")}`),n.push(`${c}${y.vertical} ${_("(wrap each operation with step() to see individual steps)")}`);else for(let u=0;u<e.children.length;u++){let s=e.children[u],f=u===e.children.length-1?`${c}${y.vertical} ${y.bottomLeft}`:`${c}${y.vertical} ${y.teeRight}`,k=e.winnerId&&s.id===e.winnerId?_(" (winner)"):"";if(V(s))n.push(`${f} ${me(s,r,t,o)}${k}`);else{let v=ie([s],r,t,a+1,o);for(let R of v)n.push(`${c}${y.vertical} ${R}`)}}return r.showTimings&&e.durationMs!==void 0&&n.push(`${c}${y.bottomLeft}${y.horizontal}${y.horizontal} ${_(`[${H(e.durationMs)}]`)}`),n}function rt(e,r,t,a,o){let n=[],c=" ".repeat(a),p=ne(e.state,t),d=e.name??"decision",u=e.condition?_(` (${e.condition})`):"",s=e.decisionValue!==void 0?_(` = ${String(e.decisionValue)}`):"",l=e.branchTaken!==void 0?_(` \u2192 ${String(e.branchTaken)}`):"";n.push(`${c}${y.teeRight}${y.teeDown}${y.horizontal} ${p} ${te(d)}${u}${s}${l}`);for(let f=0;f<e.branches.length;f++){let h=e.branches[f],v=f===e.branches.length-1?`${c}${y.vertical} ${y.bottomLeft}`:`${c}${y.vertical} ${y.teeRight}`,R=h.taken?"\u2713":"\u2298",T=h.taken?t.success:t.skipped,B=U(`${R} ${h.label}`,T),O=h.condition?_(` (${h.condition})`):"";if(n.push(`${v} ${B}${O}`),h.children.length>0){let g=ie(h.children,r,t,a+1,o);for(let I of g)n.push(`${c}${y.vertical} ${I}`)}else h.taken||n.push(`${c}${y.vertical} ${_("(skipped)")}`)}return r.showTimings&&e.durationMs!==void 0&&n.push(`${c}${y.bottomLeft}${y.horizontal}${y.horizontal} ${_(`[${H(e.durationMs)}]`)}`),n}function he(e){let r=[];for(let t of e)if(r.push(t),"children"in t&&Array.isArray(t.children)&&r.push(...he(t.children)),"branches"in t)for(let a of t.branches)r.push(...he(a.children));return r}function ae(e,r){if(e.length===0)return 0;let t=Math.floor(e.length*r);return e[Math.min(t,e.length-1)]}function ge(e){return e<.2?"cold":e<.4?"cool":e<.6?"neutral":e<.8?"warm":e<.95?"hot":"critical"}function ve(){let e=new Map,r=new Map,t=new Map,a=new Map,o=[];function n(g){return g.name??g.stepKey??g.stepId??"unknown"}function c(g){let I=new Map;for(let w of g)switch(w.type){case"step_start":{let $=n(w);I.set($,{retried:!1,timedOut:!1});break}case"step_retry":{let $=n(w),W=I.get($);W&&(W.retried=!0);break}case"step_timeout":{let $=n(w),W=I.get($);W&&(W.timedOut=!0);let C=a.get($)??{timedOut:0,total:0};C.timedOut++,C.total++,a.set($,C);break}case"step_success":{let $=n(w),W=I.get($),C=e.get($)??[];C.push(w.durationMs),e.set($,C);let D=r.get($)??{retried:0,total:0};D.total++,W?.retried&&D.retried++,r.set($,D);let M=t.get($)??{errors:0,total:0};M.total++,t.set($,M),I.delete($);break}case"step_error":{let $=n(w),W=I.get($),C=e.get($)??[];C.push(w.durationMs),e.set($,C);let D=r.get($)??{retried:0,total:0};D.total++,W?.retried&&D.retried++,r.set($,D);let M=t.get($)??{errors:0,total:0};M.total++,M.errors++,t.set($,M),I.delete($);break}}}function p(g){c(g.events)}function d(g){o.push(g)}function u(g){o.length>0&&(c(o),o=[])}function s(g){let I=e.get(g);if(!I||I.length===0)return;let w=[...I].sort((S,x)=>S-x),W=w.reduce((S,x)=>S+x,0)/w.length,C=w.reduce((S,x)=>S+(x-W)**2,0)/w.length,D=r.get(g)??{retried:0,total:1},M=t.get(g)??{errors:0,total:1},N=a.get(g)??{timedOut:0,total:1};return{nodeId:g,avgDurationMs:W,minDurationMs:w[0],maxDurationMs:w[w.length-1],stdDevMs:Math.sqrt(C),samples:w.length,retryRate:D.total>0?D.retried/D.total:0,timeoutRate:N.total>0?N.timedOut/N.total:0,errorRate:M.total>0?M.errors/M.total:0,percentiles:{p50:ae(w,.5),p90:ae(w,.9),p95:ae(w,.95),p99:ae(w,.99)}}}function l(g){return s(g)}function f(g,I="duration"){let w=new Map,$=he(g.root.children),W=[];for(let x of $){let E=x.name??x.id,L=s(E);if(L){let i;switch(I){case"duration":i=L.avgDurationMs;break;case"retryRate":i=L.retryRate;break;case"errorRate":i=L.errorRate;break}W.push({id:x.id,value:i})}}if(W.length===0)return{heat:w,metric:I,stats:{min:0,max:0,mean:0,threshold:0}};let C=W.map(x=>x.value),D=Math.min(...C),M=Math.max(...C),N=C.reduce((x,E)=>x+E,0)/C.length,S=M-D||1;for(let{id:x,value:E}of W)w.set(x,(E-D)/S);return{heat:w,metric:I,stats:{min:D,max:M,mean:N,threshold:N+(M-N)*.5}}}function h(){let g=new Map;for(let I of e.keys()){let w=s(I);w&&g.set(I,w)}return g}function k(g=10){return[...h().values()].sort((w,$)=>$.avgDurationMs-w.avgDurationMs).slice(0,g)}function v(g=10){return[...h().values()].filter(w=>w.errorRate>0).sort((w,$)=>$.errorRate-w.errorRate).slice(0,g)}function R(g=10){return[...h().values()].filter(w=>w.retryRate>0).sort((w,$)=>$.retryRate-w.retryRate).slice(0,g)}function T(){return JSON.stringify({timingData:Object.fromEntries(e),retryData:Object.fromEntries(r),errorData:Object.fromEntries(t),timeoutData:Object.fromEntries(a)})}function B(g){let I=JSON.parse(g);e.clear(),r.clear(),t.clear(),a.clear();for(let[w,$]of Object.entries(I.timingData??{}))e.set(w,$);for(let[w,$]of Object.entries(I.retryData??{}))r.set(w,$);for(let[w,$]of Object.entries(I.errorData??{}))t.set(w,$);for(let[w,$]of Object.entries(I.timeoutData??{}))a.set(w,$)}function O(){e.clear(),r.clear(),t.clear(),a.clear(),o=[]}return{addRun:p,addEvent:d,finalizeRun:u,getNodePerformance:l,getHeatmap:f,getSlowestNodes:k,getErrorProneNodes:v,getRetryProneNodes:R,getAllPerformance:h,exportData:T,importData:B,clear:O}}function ot(){return[" classDef pending fill:#f3f4f6,stroke:#9ca3af,stroke-width:2px,color:#374151"," classDef running fill:#fef3c7,stroke:#f59e0b,stroke-width:3px,color:#92400e"," classDef success fill:#d1fae5,stroke:#10b981,stroke-width:3px,color:#065f46"," classDef error fill:#fee2e2,stroke:#ef4444,stroke-width:3px,color:#991b1b"," classDef aborted fill:#f3f4f6,stroke:#6b7280,stroke-width:2px,color:#4b5563,stroke-dasharray: 5 5"," classDef cached fill:#dbeafe,stroke:#3b82f6,stroke-width:3px,color:#1e40af"," classDef skipped fill:#f9fafb,stroke:#d1d5db,stroke-width:2px,color:#6b7280,stroke-dasharray: 5 5"]}function it(){return[" classDef heat_cold fill:#dbeafe,stroke:#3b82f6,stroke-width:2px,color:#1e40af"," classDef heat_cool fill:#ccfbf1,stroke:#14b8a6,stroke-width:2px,color:#0f766e"," classDef heat_neutral fill:#f3f4f6,stroke:#6b7280,stroke-width:2px,color:#374151"," classDef heat_warm fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#92400e"," classDef heat_hot fill:#fed7aa,stroke:#f97316,stroke-width:3px,color:#c2410c"," classDef heat_critical fill:#fecaca,stroke:#ef4444,stroke-width:3px,color:#b91c1c"]}function at(e){return`heat_${e}`}function st(){return[" classDef hook_success fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0c4a6e"," classDef hook_error fill:#fef2f2,stroke:#dc2626,stroke-width:2px,color:#7f1d1d"]}function ct(e,r,t){let a;if(e.shouldRun){let o="hook_shouldRun",n=e.shouldRun.state==="success"?"hook_success":"hook_error",c=e.shouldRun.state==="success"?"\u2699":"\u26A0",p=t.showTimings&&e.shouldRun.durationMs!==void 0?` ${H(e.shouldRun.durationMs)}`:"",d=e.shouldRun.context?.skipped?"\\nskipped workflow":e.shouldRun.context?.result===!0?"\\nproceed":"";r.push(` ${o}[["${c} shouldRun${d}${p}"]]:::${n}`),a=o}if(e.onBeforeStart){let o="hook_beforeStart",n=e.onBeforeStart.state==="success"?"hook_success":"hook_error",c=e.onBeforeStart.state==="success"?"\u2699":"\u26A0",p=t.showTimings&&e.onBeforeStart.durationMs!==void 0?` ${H(e.onBeforeStart.durationMs)}`:"",d=e.onBeforeStart.context?.skipped?"\\nskipped workflow":"";r.push(` ${o}[["${c} onBeforeStart${d}${p}"]]:::${n}`),a&&r.push(` ${a} --> ${o}`),a=o}return{lastHookId:a}}var _e=0;function re(e="node"){return`${e}_${++_e}`}function dt(){_e=0}function z(e){return e.replace(/[{}[\]()]/g,"").replace(/[<>]/g,"").replace(/"/g,"'").trim()}function Ce(e){return z(e).replace(/[[\]]/g,"")}function se(){return{name:"mermaid",supportsLive:!1,render(e,r){dt();let t=[],a=r;t.push("flowchart TD");let o;e.hooks&&(o=ct(e.hooks,t,r).lastHookId);let n="start";t.push(` ${n}(("\u25B6 Start"))`),o&&t.push(` ${o} --> ${n}`);let c=n;for(let p of e.root.children){let d=ce(p,r,t,a,e.hooks);t.push(` ${c} --> ${d.entryId}`),c=d.exitId}if(e.root.state==="success"||e.root.state==="error"){let p="finish",d=e.root.state==="success"?"\u2713":"\u2717",u=e.root.state==="success"?"Done":"Failed",s=`(("${d} ${u}"))`,l=e.root.state==="success"?":::success":":::error";t.push(` ${p}${s}${l}`),t.push(` ${c} --> ${p}`)}return t.push(""),t.push(...ot()),a.showHeatmap&&t.push(...it()),e.hooks&&t.push(...st()),t.join(`
3
+ `)}}}function ce(e,r,t,a,o){if(V(e))return lt(e,r,t,a,o);if(J(e))return ut(e,r,t,a,o);if(Y(e))return pt(e,r,t,a,o);if(X(e))return ft(e,r,t,a,o);let n=re("unknown");return t.push(` ${n}[Unknown Node]`),{entryId:n,exitId:n}}function lt(e,r,t,a,o){let n=e.key?`step_${e.key.replace(/[^a-zA-Z0-9]/g,"_")}`:re("step"),c=z(e.name??e.key??"Step"),p=r.showTimings&&e.durationMs!==void 0?` ${H(e.durationMs)}`:"",d="";switch(e.state){case"success":d="\u2713 ";break;case"error":d="\u2717 ";break;case"cached":d="\u{1F4BE} ";break;case"running":d="\u23F3 ";break;case"skipped":d="\u2298 ";break}let u="";if(e.input!==void 0){let T=typeof e.input=="string"?z(e.input):z(JSON.stringify(e.input).slice(0,20));u+=`\\nin: ${T}`}if(e.output!==void 0&&e.state==="success"){let T=typeof e.output=="string"?z(e.output):z(JSON.stringify(e.output).slice(0,20));u+=`\\nout: ${T}`}let s="";if(e.retryCount!==void 0&&e.retryCount>0&&(s+=`\\n\u21BB ${e.retryCount} retr${e.retryCount===1?"y":"ies"}`),e.timedOut){let T=e.timeoutMs!==void 0?`${e.timeoutMs}ms`:"";s+=`\\n\u23F1 timeout ${T}`}let l="";if(o&&e.key&&o.onAfterStep.has(e.key)){let T=o.onAfterStep.get(e.key),B=T.state==="success"?"\u2699":"\u26A0",O=r.showTimings&&T.durationMs!==void 0?` ${H(T.durationMs)}`:"";l=`\\n${B} hook${O}`}let f=(d+c+u+s+l+p).trim(),h,k=e.name??e.id,v=a?.showHeatmap&&a.heatmapData?a.heatmapData.heat.get(e.id)??a.heatmapData.heat.get(k):void 0;if(v!==void 0){let T=ge(v);h=at(T)}else h=e.state;let R;switch(e.state){case"error":R=`{{${f}}}`;break;case"cached":R=`[(${f})]`;break;case"skipped":R=`[${f}]:::skipped`;break;default:R=`[${f}]`}return t.push(` ${n}${R}:::${h}`),{entryId:n,exitId:n}}function ut(e,r,t,a,o){let n=re("parallel"),c=`${n}_fork`,p=`${n}_join`,d=Ce(e.name??"Parallel"),u=e.mode==="allSettled"?" (allSettled)":"";if(e.children.length===0){let f=n,h=z(`${d}${u}`),k="operations not individually tracked",v=r.showTimings&&e.durationMs!==void 0?` ${H(e.durationMs)}`:"";return t.push(` ${f}[${h}${v}\\n${k}]:::${e.state}`),{entryId:f,exitId:f}}t.push(` subgraph ${n}["${d}${u}"]`),t.push(" direction TB"),t.push(` ${c}{"\u26A1 Fork"}`);let s=[];for(let f of e.children){let h=ce(f,r,t,a,o);t.push(` ${c} --> ${h.entryId}`),s.push(h.exitId)}t.push(` ${p}{"\u2713 Join"}`);for(let f of s)t.push(` ${f} --> ${p}`);t.push(" end");let l=e.state;return t.push(` class ${n} ${l}`),{entryId:c,exitId:p}}function pt(e,r,t,a,o){let n=re("race"),c=`${n}_start`,p=`${n}_end`,d=Ce(e.name??"Race");if(e.children.length===0){let f=n,h=z(d),k="operations not individually tracked",v=r.showTimings&&e.durationMs!==void 0?` ${H(e.durationMs)}`:"";return t.push(` ${f}[\u26A1 ${h}${v}\\n${k}]:::${e.state}`),{entryId:f,exitId:f}}t.push(` subgraph ${n}["\u26A1 ${d}"]`),t.push(" direction TB"),t.push(` ${c}(("\u{1F3C1} Start"))`);let u=[],s;for(let f of e.children){let h=ce(f,r,t,a,o),k=V(f)&&e.winnerId===f.id;t.push(` ${c} --> ${h.entryId}`),k&&(s=h.exitId),u.push({exitId:h.exitId,isWinner:k})}t.push(` ${p}(("\u2713 First"))`);for(let{exitId:f,isWinner:h}of u)h&&s?t.push(` ${f} ==>|\u{1F3C6} Winner| ${p}`):e.winnerId?t.push(` ${f} -. cancelled .-> ${p}`):t.push(` ${f} --> ${p}`);t.push(" end");let l=e.state;return t.push(` class ${n} ${l}`),{entryId:c,exitId:p}}function ft(e,r,t,a,o){let n=e.key?`decision_${e.key.replace(/[^a-zA-Z0-9]/g,"_")}`:re("decision"),c=z(e.condition??"condition"),p=e.decisionValue!==void 0?` = ${z(String(e.decisionValue)).slice(0,30)}`:"",d=`${c}${p}`.trim();t.push(` ${n}{${d}}`);let u=[],s;for(let l of e.branches){let f=`${n}_${l.label.replace(/[^a-zA-Z0-9]/g,"_")}`,h=z(l.label),k=l.taken?`${h} \u2713`:`${h} skipped`,v=l.taken?":::success":":::skipped";t.push(` ${f}[${k}]${v}`);let R=l.condition?`|${z(l.condition).replace(/\|/g,"")}|`:"";if(t.push(` ${n} -->${R} ${f}`),l.children.length>0){let T=f;for(let B of l.children){let O=ce(B,r,t,a,o);t.push(` ${T} --> ${O.entryId}`),T=O.exitId}u.push(T),l.taken&&(s=T)}else u.push(f),l.taken&&(s=f)}return s?{entryId:n,exitId:s}:{entryId:n,exitId:n}}function Oe(e){let r={bg:"#ffffff",bgSecondary:"#f8f9fa",text:"#212529",textMuted:"#6c757d",border:"#dee2e6",primary:"#0d6efd",success:"#198754",error:"#dc3545",warning:"#ffc107",info:"#0dcaf0",muted:"#6c757d",nodePending:"#e9ecef",nodeRunning:"#fff3cd",nodeSuccess:"#d1e7dd",nodeError:"#f8d7da",nodeAborted:"#e9ecef",nodeCached:"#cfe2ff",nodeSkipped:"#f8f9fa",heatCold:"#0d6efd",heatCool:"#0dcaf0",heatNeutral:"#6c757d",heatWarm:"#ffc107",heatHot:"#fd7e14",heatCritical:"#dc3545"},t={bg:"#212529",bgSecondary:"#343a40",text:"#f8f9fa",textMuted:"#adb5bd",border:"#495057",primary:"#0d6efd",success:"#198754",error:"#dc3545",warning:"#ffc107",info:"#0dcaf0",muted:"#6c757d",nodePending:"#495057",nodeRunning:"#664d03",nodeSuccess:"#0f5132",nodeError:"#842029",nodeAborted:"#495057",nodeCached:"#084298",nodeSkipped:"#343a40",heatCold:"#0d6efd",heatCool:"#0dcaf0",heatNeutral:"#6c757d",heatWarm:"#ffc107",heatHot:"#fd7e14",heatCritical:"#dc3545"},a=n=>`
4
+ --bg: ${n.bg};
5
+ --bg-secondary: ${n.bgSecondary};
6
+ --text: ${n.text};
7
+ --text-muted: ${n.textMuted};
8
+ --border: ${n.border};
9
+ --primary: ${n.primary};
10
+ --success: ${n.success};
11
+ --error: ${n.error};
12
+ --warning: ${n.warning};
13
+ --info: ${n.info};
14
+ --muted: ${n.muted};
15
+ --node-pending: ${n.nodePending};
16
+ --node-running: ${n.nodeRunning};
17
+ --node-success: ${n.nodeSuccess};
18
+ --node-error: ${n.nodeError};
19
+ --node-aborted: ${n.nodeAborted};
20
+ --node-cached: ${n.nodeCached};
21
+ --node-skipped: ${n.nodeSkipped};
22
+ --heat-cold: ${n.heatCold};
23
+ --heat-cool: ${n.heatCool};
24
+ --heat-neutral: ${n.heatNeutral};
25
+ --heat-warm: ${n.heatWarm};
26
+ --heat-hot: ${n.heatHot};
27
+ --heat-critical: ${n.heatCritical};
28
+ `,o;return e==="auto"?o=`
29
+ :root {
30
+ ${a(r)}
31
+ }
32
+ @media (prefers-color-scheme: dark) {
33
+ :root {
34
+ ${a(t)}
35
+ }
36
+ }
37
+ `:e==="dark"?o=`
38
+ :root {
39
+ ${a(t)}
40
+ }
41
+ `:o=`
42
+ :root {
43
+ ${a(r)}
44
+ }
45
+ `,`
46
+ ${o}
47
+
48
+ * {
49
+ box-sizing: border-box;
50
+ margin: 0;
51
+ padding: 0;
52
+ }
53
+
54
+ body {
55
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
56
+ background-color: var(--bg);
57
+ color: var(--text);
58
+ line-height: 1.5;
59
+ }
60
+
61
+ .workflow-visualizer {
62
+ display: flex;
63
+ flex-direction: column;
64
+ height: 100vh;
65
+ overflow: hidden;
66
+ }
67
+
68
+ /* Header */
69
+ .wv-header {
70
+ display: flex;
71
+ align-items: center;
72
+ justify-content: space-between;
73
+ padding: 12px 20px;
74
+ background-color: var(--bg-secondary);
75
+ border-bottom: 1px solid var(--border);
76
+ }
77
+
78
+ .wv-header h1 {
79
+ font-size: 1.25rem;
80
+ font-weight: 600;
81
+ }
82
+
83
+ .wv-controls {
84
+ display: flex;
85
+ gap: 8px;
86
+ align-items: center;
87
+ }
88
+
89
+ .wv-btn {
90
+ display: inline-flex;
91
+ align-items: center;
92
+ justify-content: center;
93
+ padding: 6px 12px;
94
+ font-size: 0.875rem;
95
+ font-weight: 500;
96
+ border: 1px solid var(--border);
97
+ border-radius: 6px;
98
+ background-color: var(--bg);
99
+ color: var(--text);
100
+ cursor: pointer;
101
+ transition: all 0.15s ease;
102
+ }
103
+
104
+ .wv-btn:hover {
105
+ background-color: var(--bg-secondary);
106
+ }
107
+
108
+ .wv-btn:disabled {
109
+ opacity: 0.5;
110
+ cursor: not-allowed;
111
+ }
112
+
113
+ .wv-btn--primary {
114
+ background-color: var(--primary);
115
+ border-color: var(--primary);
116
+ color: white;
117
+ }
118
+
119
+ .wv-btn--primary:hover {
120
+ opacity: 0.9;
121
+ }
122
+
123
+ .wv-btn--icon {
124
+ padding: 6px;
125
+ min-width: 32px;
126
+ }
127
+
128
+ /* Main content area */
129
+ .wv-main {
130
+ display: flex;
131
+ flex: 1;
132
+ overflow: hidden;
133
+ }
134
+
135
+ /* Diagram container */
136
+ .wv-diagram {
137
+ flex: 1;
138
+ position: relative;
139
+ overflow: hidden;
140
+ background-color: var(--bg);
141
+ background-image:
142
+ radial-gradient(circle, var(--border) 1px, transparent 1px);
143
+ background-size: 20px 20px;
144
+ }
145
+
146
+ .wv-diagram svg {
147
+ width: 100%;
148
+ height: 100%;
149
+ }
150
+
151
+ /* SVG Node styles */
152
+ .wv-node {
153
+ cursor: pointer;
154
+ transition: transform 0.15s ease;
155
+ }
156
+
157
+ .wv-node:hover {
158
+ transform: scale(1.02);
159
+ }
160
+
161
+ .wv-node rect,
162
+ .wv-node circle {
163
+ stroke: var(--border);
164
+ stroke-width: 2;
165
+ transition: all 0.2s ease;
166
+ }
167
+
168
+ .wv-node--pending rect { fill: var(--node-pending); }
169
+ .wv-node--running rect { fill: var(--node-running); stroke: var(--warning); }
170
+ .wv-node--success rect { fill: var(--node-success); stroke: var(--success); }
171
+ .wv-node--error rect { fill: var(--node-error); stroke: var(--error); }
172
+ .wv-node--aborted rect { fill: var(--node-aborted); }
173
+ .wv-node--cached rect { fill: var(--node-cached); stroke: var(--info); }
174
+ .wv-node--skipped rect { fill: var(--node-skipped); opacity: 0.6; }
175
+
176
+ .wv-node--selected rect {
177
+ stroke: var(--primary);
178
+ stroke-width: 3;
179
+ }
180
+
181
+ .wv-node text {
182
+ fill: var(--text);
183
+ font-size: 12px;
184
+ font-weight: 500;
185
+ dominant-baseline: middle;
186
+ text-anchor: middle;
187
+ }
188
+
189
+ .wv-node .wv-node-timing {
190
+ fill: var(--text-muted);
191
+ font-size: 10px;
192
+ }
193
+
194
+ /* Edge styles */
195
+ .wv-edge {
196
+ fill: none;
197
+ stroke: var(--border);
198
+ stroke-width: 2;
199
+ }
200
+
201
+ .wv-edge--active {
202
+ stroke: var(--success);
203
+ stroke-width: 2.5;
204
+ }
205
+
206
+ .wv-edge-arrow {
207
+ fill: var(--border);
208
+ }
209
+
210
+ /* Parallel/Race container */
211
+ .wv-container {
212
+ fill: transparent;
213
+ stroke: var(--border);
214
+ stroke-dasharray: 5 3;
215
+ }
216
+
217
+ .wv-container--parallel { stroke: var(--info); }
218
+ .wv-container--race { stroke: var(--warning); }
219
+
220
+ .wv-container-label {
221
+ fill: var(--text-muted);
222
+ font-size: 10px;
223
+ font-weight: 600;
224
+ text-transform: uppercase;
225
+ letter-spacing: 0.5px;
226
+ }
227
+
228
+ /* Heatmap overlay */
229
+ .wv-node--heat-cold rect { fill: var(--heat-cold) !important; opacity: 0.7; }
230
+ .wv-node--heat-cool rect { fill: var(--heat-cool) !important; opacity: 0.7; }
231
+ .wv-node--heat-neutral rect { fill: var(--heat-neutral) !important; opacity: 0.7; }
232
+ .wv-node--heat-warm rect { fill: var(--heat-warm) !important; opacity: 0.7; }
233
+ .wv-node--heat-hot rect { fill: var(--heat-hot) !important; opacity: 0.7; }
234
+ .wv-node--heat-critical rect { fill: var(--heat-critical) !important; opacity: 0.85; }
235
+
236
+ /* Timeline scrubber */
237
+ .wv-timeline {
238
+ height: 80px;
239
+ padding: 12px 20px;
240
+ background-color: var(--bg-secondary);
241
+ border-top: 1px solid var(--border);
242
+ }
243
+
244
+ .wv-timeline-track {
245
+ position: relative;
246
+ height: 24px;
247
+ background-color: var(--bg);
248
+ border-radius: 4px;
249
+ overflow: hidden;
250
+ }
251
+
252
+ .wv-timeline-progress {
253
+ position: absolute;
254
+ top: 0;
255
+ left: 0;
256
+ height: 100%;
257
+ background-color: var(--primary);
258
+ opacity: 0.3;
259
+ transition: width 0.1s ease;
260
+ }
261
+
262
+ .wv-timeline-marker {
263
+ position: absolute;
264
+ top: 0;
265
+ width: 3px;
266
+ height: 100%;
267
+ background-color: var(--primary);
268
+ cursor: ew-resize;
269
+ }
270
+
271
+ .wv-timeline-events {
272
+ display: flex;
273
+ gap: 2px;
274
+ height: 100%;
275
+ align-items: center;
276
+ padding: 4px;
277
+ }
278
+
279
+ .wv-timeline-event {
280
+ width: 4px;
281
+ height: 16px;
282
+ border-radius: 2px;
283
+ background-color: var(--muted);
284
+ }
285
+
286
+ .wv-timeline-event--success { background-color: var(--success); }
287
+ .wv-timeline-event--error { background-color: var(--error); }
288
+ .wv-timeline-event--running { background-color: var(--warning); }
289
+
290
+ .wv-timeline-controls {
291
+ display: flex;
292
+ gap: 8px;
293
+ margin-top: 8px;
294
+ align-items: center;
295
+ }
296
+
297
+ .wv-timeline-time {
298
+ font-size: 0.75rem;
299
+ color: var(--text-muted);
300
+ font-family: monospace;
301
+ }
302
+
303
+ /* Inspector panel */
304
+ .wv-inspector {
305
+ width: 320px;
306
+ background-color: var(--bg-secondary);
307
+ border-left: 1px solid var(--border);
308
+ overflow-y: auto;
309
+ transition: width 0.2s ease;
310
+ }
311
+
312
+ .wv-inspector--collapsed {
313
+ width: 0;
314
+ }
315
+
316
+ .wv-inspector-header {
317
+ display: flex;
318
+ align-items: center;
319
+ justify-content: space-between;
320
+ padding: 12px 16px;
321
+ border-bottom: 1px solid var(--border);
322
+ }
323
+
324
+ .wv-inspector-header h2 {
325
+ font-size: 0.875rem;
326
+ font-weight: 600;
327
+ }
328
+
329
+ .wv-inspector-content {
330
+ padding: 16px;
331
+ }
332
+
333
+ .wv-inspector-section {
334
+ margin-bottom: 20px;
335
+ }
336
+
337
+ .wv-inspector-section h3 {
338
+ font-size: 0.75rem;
339
+ font-weight: 600;
340
+ text-transform: uppercase;
341
+ letter-spacing: 0.5px;
342
+ color: var(--text-muted);
343
+ margin-bottom: 8px;
344
+ }
345
+
346
+ .wv-inspector-row {
347
+ display: flex;
348
+ justify-content: space-between;
349
+ padding: 4px 0;
350
+ font-size: 0.875rem;
351
+ }
352
+
353
+ .wv-inspector-label {
354
+ color: var(--text-muted);
355
+ }
356
+
357
+ .wv-inspector-value {
358
+ font-weight: 500;
359
+ font-family: monospace;
360
+ }
361
+
362
+ .wv-inspector-value--success { color: var(--success); }
363
+ .wv-inspector-value--error { color: var(--error); }
364
+ .wv-inspector-value--running { color: var(--warning); }
365
+
366
+ /* Status badge */
367
+ .wv-badge {
368
+ display: inline-flex;
369
+ align-items: center;
370
+ padding: 2px 8px;
371
+ font-size: 0.75rem;
372
+ font-weight: 500;
373
+ border-radius: 4px;
374
+ text-transform: capitalize;
375
+ }
376
+
377
+ .wv-badge--pending { background-color: var(--node-pending); }
378
+ .wv-badge--running { background-color: var(--node-running); color: #664d03; }
379
+ .wv-badge--success { background-color: var(--node-success); color: #0f5132; }
380
+ .wv-badge--error { background-color: var(--node-error); color: #842029; }
381
+ .wv-badge--cached { background-color: var(--node-cached); color: #084298; }
382
+
383
+ /* Live indicator */
384
+ .wv-live {
385
+ display: flex;
386
+ align-items: center;
387
+ gap: 6px;
388
+ padding: 4px 10px;
389
+ background-color: var(--error);
390
+ color: white;
391
+ font-size: 0.75rem;
392
+ font-weight: 600;
393
+ border-radius: 4px;
394
+ }
395
+
396
+ .wv-live-dot {
397
+ width: 8px;
398
+ height: 8px;
399
+ background-color: white;
400
+ border-radius: 50%;
401
+ animation: wv-pulse 1.5s infinite;
402
+ }
403
+
404
+ @keyframes wv-pulse {
405
+ 0%, 100% { opacity: 1; }
406
+ 50% { opacity: 0.5; }
407
+ }
408
+
409
+ /* Performance stats */
410
+ .wv-perf-bar {
411
+ height: 8px;
412
+ background-color: var(--bg);
413
+ border-radius: 4px;
414
+ overflow: hidden;
415
+ margin-top: 4px;
416
+ }
417
+
418
+ .wv-perf-bar-fill {
419
+ height: 100%;
420
+ border-radius: 4px;
421
+ transition: width 0.3s ease;
422
+ }
423
+
424
+ .wv-perf-bar-fill--cold { background-color: var(--heat-cold); }
425
+ .wv-perf-bar-fill--cool { background-color: var(--heat-cool); }
426
+ .wv-perf-bar-fill--neutral { background-color: var(--heat-neutral); }
427
+ .wv-perf-bar-fill--warm { background-color: var(--heat-warm); }
428
+ .wv-perf-bar-fill--hot { background-color: var(--heat-hot); }
429
+ .wv-perf-bar-fill--critical { background-color: var(--heat-critical); }
430
+
431
+ /* Tooltip */
432
+ .wv-tooltip {
433
+ position: fixed;
434
+ padding: 8px 12px;
435
+ background-color: var(--text);
436
+ color: var(--bg);
437
+ font-size: 0.75rem;
438
+ border-radius: 4px;
439
+ pointer-events: none;
440
+ z-index: 1000;
441
+ max-width: 300px;
442
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
443
+ }
444
+
445
+ /* Loading state */
446
+ .wv-loading {
447
+ display: flex;
448
+ align-items: center;
449
+ justify-content: center;
450
+ height: 100%;
451
+ color: var(--text-muted);
452
+ }
453
+
454
+ .wv-spinner {
455
+ width: 24px;
456
+ height: 24px;
457
+ border: 3px solid var(--border);
458
+ border-top-color: var(--primary);
459
+ border-radius: 50%;
460
+ animation: wv-spin 1s linear infinite;
461
+ margin-right: 8px;
462
+ }
463
+
464
+ @keyframes wv-spin {
465
+ to { transform: rotate(360deg); }
466
+ }
467
+
468
+ /* Empty state */
469
+ .wv-empty {
470
+ display: flex;
471
+ flex-direction: column;
472
+ align-items: center;
473
+ justify-content: center;
474
+ height: 100%;
475
+ color: var(--text-muted);
476
+ text-align: center;
477
+ padding: 40px;
478
+ }
479
+
480
+ .wv-empty svg {
481
+ width: 64px;
482
+ height: 64px;
483
+ margin-bottom: 16px;
484
+ opacity: 0.5;
485
+ }
486
+
487
+ /* Responsive */
488
+ @media (max-width: 768px) {
489
+ .wv-inspector {
490
+ position: fixed;
491
+ right: 0;
492
+ top: 0;
493
+ bottom: 0;
494
+ z-index: 100;
495
+ box-shadow: -4px 0 12px rgba(0, 0, 0, 0.1);
496
+ }
497
+
498
+ .wv-timeline {
499
+ height: auto;
500
+ }
501
+ }
502
+ `}function We(e){return`
503
+ (function() {
504
+ 'use strict';
505
+
506
+ // State
507
+ let selectedNodeId = null;
508
+ let transform = { x: 0, y: 0, scale: 1 };
509
+ let isDragging = false;
510
+ let dragStart = { x: 0, y: 0 };
511
+ let ws = null;
512
+ let snapshots = [];
513
+ let currentSnapshotIndex = -1;
514
+ let isPlaying = false;
515
+ let playbackSpeed = 1;
516
+ let heatmapEnabled = false;
517
+ let heatmapMetric = 'duration';
518
+
519
+ // DOM elements
520
+ const diagram = document.getElementById('diagram');
521
+ const svg = diagram?.querySelector('svg');
522
+ const inspector = document.getElementById('inspector');
523
+ const timeline = document.getElementById('timeline');
524
+
525
+ // Initialize
526
+ document.addEventListener('DOMContentLoaded', init);
527
+
528
+ function init() {
529
+ ${e.interactive?"setupInteractivity();":""}
530
+ ${e.timeTravel?"setupTimeTravel();":""}
531
+ ${e.wsUrl?`setupWebSocket('${e.wsUrl}');`:""}
532
+ ${e.heatmap?"setupHeatmap();":""}
533
+ setupKeyboardShortcuts();
534
+ }
535
+
536
+ // Interactivity
537
+ function setupInteractivity() {
538
+ if (!diagram || !svg) return;
539
+
540
+ // Zoom with mouse wheel
541
+ diagram.addEventListener('wheel', (e) => {
542
+ e.preventDefault();
543
+ const delta = e.deltaY > 0 ? 0.9 : 1.1;
544
+ const rect = diagram.getBoundingClientRect();
545
+ const x = e.clientX - rect.left;
546
+ const y = e.clientY - rect.top;
547
+
548
+ // Zoom towards cursor position
549
+ transform.scale *= delta;
550
+ transform.scale = Math.max(0.1, Math.min(5, transform.scale));
551
+ transform.x = x - (x - transform.x) * delta;
552
+ transform.y = y - (y - transform.y) * delta;
553
+
554
+ applyTransform();
555
+ });
556
+
557
+ // Pan with drag
558
+ diagram.addEventListener('mousedown', (e) => {
559
+ if (e.target === diagram || e.target === svg) {
560
+ isDragging = true;
561
+ dragStart = { x: e.clientX - transform.x, y: e.clientY - transform.y };
562
+ diagram.style.cursor = 'grabbing';
563
+ }
564
+ });
565
+
566
+ document.addEventListener('mousemove', (e) => {
567
+ if (!isDragging) return;
568
+ transform.x = e.clientX - dragStart.x;
569
+ transform.y = e.clientY - dragStart.y;
570
+ applyTransform();
571
+ });
572
+
573
+ document.addEventListener('mouseup', () => {
574
+ isDragging = false;
575
+ if (diagram) diagram.style.cursor = 'grab';
576
+ });
577
+
578
+ // Node selection
579
+ document.querySelectorAll('.wv-node').forEach((node) => {
580
+ node.addEventListener('click', (e) => {
581
+ e.stopPropagation();
582
+ selectNode(node.dataset.nodeId);
583
+ });
584
+ });
585
+
586
+ // Deselect on background click
587
+ diagram.addEventListener('click', (e) => {
588
+ if (e.target === diagram || e.target === svg) {
589
+ selectNode(null);
590
+ }
591
+ });
592
+
593
+ // Zoom buttons
594
+ document.getElementById('zoom-in')?.addEventListener('click', () => zoom(1.2));
595
+ document.getElementById('zoom-out')?.addEventListener('click', () => zoom(0.8));
596
+ document.getElementById('zoom-reset')?.addEventListener('click', resetZoom);
597
+
598
+ // Set initial cursor
599
+ diagram.style.cursor = 'grab';
600
+ }
601
+
602
+ function applyTransform() {
603
+ if (!svg) return;
604
+ const g = svg.querySelector('g.wv-root');
605
+ if (g) {
606
+ g.setAttribute('transform', 'translate(' + transform.x + ',' + transform.y + ') scale(' + transform.scale + ')');
607
+ }
608
+ }
609
+
610
+ function zoom(factor) {
611
+ if (!diagram) return;
612
+ const rect = diagram.getBoundingClientRect();
613
+ const centerX = rect.width / 2;
614
+ const centerY = rect.height / 2;
615
+
616
+ transform.scale *= factor;
617
+ transform.scale = Math.max(0.1, Math.min(5, transform.scale));
618
+ transform.x = centerX - (centerX - transform.x) * factor;
619
+ transform.y = centerY - (centerY - transform.y) * factor;
620
+
621
+ applyTransform();
622
+ }
623
+
624
+ function resetZoom() {
625
+ transform = { x: 0, y: 0, scale: 1 };
626
+ applyTransform();
627
+ }
628
+
629
+ function selectNode(nodeId) {
630
+ // Remove previous selection
631
+ document.querySelectorAll('.wv-node--selected').forEach((n) => {
632
+ n.classList.remove('wv-node--selected');
633
+ });
634
+
635
+ selectedNodeId = nodeId;
636
+
637
+ if (nodeId) {
638
+ const node = document.querySelector('[data-node-id="' + nodeId + '"]');
639
+ if (node) {
640
+ node.classList.add('wv-node--selected');
641
+ updateInspector(nodeId);
642
+ }
643
+ } else {
644
+ clearInspector();
645
+ }
646
+ }
647
+
648
+ function updateInspector(nodeId) {
649
+ const content = document.getElementById('inspector-content');
650
+ if (!content) return;
651
+
652
+ const nodeData = window.__WORKFLOW_DATA__?.nodes?.[nodeId];
653
+ if (!nodeData) {
654
+ // Clear and add empty message using safe DOM methods
655
+ while (content.firstChild) content.removeChild(content.firstChild);
656
+ const p = document.createElement('p');
657
+ p.className = 'wv-empty';
658
+ p.textContent = 'No data available';
659
+ content.appendChild(p);
660
+ return;
661
+ }
662
+
663
+ renderInspectorContent(content, nodeData);
664
+ }
665
+
666
+ function renderInspectorContent(container, node) {
667
+ // Clear container using safe DOM method
668
+ while (container.firstChild) container.removeChild(container.firstChild);
669
+
670
+ // Node Info section
671
+ const infoSection = createSection('Node Info');
672
+ infoSection.appendChild(createRow('Name', node.name || node.id));
673
+ infoSection.appendChild(createRow('Type', node.type));
674
+
675
+ // State badge
676
+ const stateRow = document.createElement('div');
677
+ stateRow.className = 'wv-inspector-row';
678
+ const stateLabel = document.createElement('span');
679
+ stateLabel.className = 'wv-inspector-label';
680
+ stateLabel.textContent = 'State';
681
+ const stateBadge = document.createElement('span');
682
+ stateBadge.className = 'wv-badge wv-badge--' + node.state;
683
+ stateBadge.textContent = node.state;
684
+ stateRow.appendChild(stateLabel);
685
+ stateRow.appendChild(stateBadge);
686
+ infoSection.appendChild(stateRow);
687
+
688
+ if (node.key) {
689
+ infoSection.appendChild(createRow('Key', node.key));
690
+ }
691
+ container.appendChild(infoSection);
692
+
693
+ // Timing section
694
+ if (node.durationMs !== undefined) {
695
+ const timingSection = createSection('Timing');
696
+ timingSection.appendChild(createRow('Duration', formatDuration(node.durationMs)));
697
+ if (node.startTs) {
698
+ timingSection.appendChild(createRow('Started', new Date(node.startTs).toLocaleTimeString()));
699
+ }
700
+ container.appendChild(timingSection);
701
+ }
702
+
703
+ // Retries section
704
+ if (node.retryCount !== undefined && node.retryCount > 0) {
705
+ const retrySection = createSection('Retries');
706
+ retrySection.appendChild(createRow('Retry Count', String(node.retryCount)));
707
+ container.appendChild(retrySection);
708
+ }
709
+
710
+ // Error section
711
+ if (node.error) {
712
+ const errorSection = createSection('Error');
713
+ const pre = document.createElement('pre');
714
+ pre.style.cssText = 'font-size:11px;overflow:auto;max-height:150px;background:var(--bg);padding:8px;border-radius:4px;';
715
+ pre.textContent = String(node.error);
716
+ errorSection.appendChild(pre);
717
+ container.appendChild(errorSection);
718
+ }
719
+ }
720
+
721
+ function createSection(title) {
722
+ const section = document.createElement('div');
723
+ section.className = 'wv-inspector-section';
724
+ const h3 = document.createElement('h3');
725
+ h3.textContent = title;
726
+ section.appendChild(h3);
727
+ return section;
728
+ }
729
+
730
+ function createRow(label, value) {
731
+ const row = document.createElement('div');
732
+ row.className = 'wv-inspector-row';
733
+ const labelSpan = document.createElement('span');
734
+ labelSpan.className = 'wv-inspector-label';
735
+ labelSpan.textContent = label;
736
+ const valueSpan = document.createElement('span');
737
+ valueSpan.className = 'wv-inspector-value';
738
+ valueSpan.textContent = value;
739
+ row.appendChild(labelSpan);
740
+ row.appendChild(valueSpan);
741
+ return row;
742
+ }
743
+
744
+ function clearInspector() {
745
+ const content = document.getElementById('inspector-content');
746
+ if (content) {
747
+ while (content.firstChild) content.removeChild(content.firstChild);
748
+ const p = document.createElement('p');
749
+ p.className = 'wv-empty';
750
+ p.textContent = 'Select a node to inspect';
751
+ content.appendChild(p);
752
+ }
753
+ }
754
+
755
+ // Time Travel
756
+ function setupTimeTravel() {
757
+ const playBtn = document.getElementById('tt-play');
758
+ const pauseBtn = document.getElementById('tt-pause');
759
+ const prevBtn = document.getElementById('tt-prev');
760
+ const nextBtn = document.getElementById('tt-next');
761
+ const speedSelect = document.getElementById('tt-speed');
762
+ const slider = document.getElementById('tt-slider');
763
+
764
+ playBtn?.addEventListener('click', play);
765
+ pauseBtn?.addEventListener('click', pause);
766
+ prevBtn?.addEventListener('click', stepBackward);
767
+ nextBtn?.addEventListener('click', stepForward);
768
+ speedSelect?.addEventListener('change', (e) => {
769
+ playbackSpeed = parseFloat(e.target.value);
770
+ });
771
+ slider?.addEventListener('input', (e) => {
772
+ seek(parseInt(e.target.value, 10));
773
+ });
774
+ }
775
+
776
+ function play() {
777
+ if (snapshots.length === 0) return;
778
+ isPlaying = true;
779
+ updatePlaybackUI();
780
+ playNext();
781
+ }
782
+
783
+ function pause() {
784
+ isPlaying = false;
785
+ updatePlaybackUI();
786
+ }
787
+
788
+ function playNext() {
789
+ if (!isPlaying) return;
790
+ if (currentSnapshotIndex < snapshots.length - 1) {
791
+ const current = snapshots[currentSnapshotIndex];
792
+ const next = snapshots[currentSnapshotIndex + 1];
793
+ const delay = (next.timestamp - current.timestamp) / playbackSpeed;
794
+
795
+ setTimeout(() => {
796
+ stepForward();
797
+ playNext();
798
+ }, Math.max(16, delay));
799
+ } else {
800
+ pause();
801
+ }
802
+ }
803
+
804
+ function stepForward() {
805
+ if (currentSnapshotIndex < snapshots.length - 1) {
806
+ seek(currentSnapshotIndex + 1);
807
+ }
808
+ }
809
+
810
+ function stepBackward() {
811
+ if (currentSnapshotIndex > 0) {
812
+ seek(currentSnapshotIndex - 1);
813
+ }
814
+ }
815
+
816
+ function seek(index) {
817
+ if (index < 0 || index >= snapshots.length) return;
818
+ currentSnapshotIndex = index;
819
+ updateTimelineUI();
820
+
821
+ // Request IR update from server or use cached
822
+ if (ws && ws.readyState === WebSocket.OPEN) {
823
+ ws.send(JSON.stringify({ type: 'time_travel_seek', payload: { index } }));
824
+ } else if (snapshots[index]?.ir) {
825
+ renderIR(snapshots[index].ir);
826
+ }
827
+ }
828
+
829
+ function updatePlaybackUI() {
830
+ const playBtn = document.getElementById('tt-play');
831
+ const pauseBtn = document.getElementById('tt-pause');
832
+
833
+ if (playBtn) playBtn.style.display = isPlaying ? 'none' : 'inline-flex';
834
+ if (pauseBtn) pauseBtn.style.display = isPlaying ? 'inline-flex' : 'none';
835
+ }
836
+
837
+ function updateTimelineUI() {
838
+ const slider = document.getElementById('tt-slider');
839
+ const timeDisplay = document.getElementById('tt-time');
840
+
841
+ if (slider) {
842
+ slider.max = String(Math.max(0, snapshots.length - 1));
843
+ slider.value = String(currentSnapshotIndex);
844
+ }
845
+
846
+ if (timeDisplay) {
847
+ timeDisplay.textContent = (currentSnapshotIndex + 1) + ' / ' + snapshots.length;
848
+ }
849
+ }
850
+
851
+ // WebSocket
852
+ function setupWebSocket(url) {
853
+ ws = new WebSocket(url);
854
+
855
+ ws.onopen = () => {
856
+ console.log('[Visualizer] Connected to server');
857
+ showLiveIndicator(true);
858
+ };
859
+
860
+ ws.onclose = () => {
861
+ console.log('[Visualizer] Disconnected from server');
862
+ showLiveIndicator(false);
863
+ // Attempt reconnect after 2 seconds
864
+ setTimeout(() => setupWebSocket(url), 2000);
865
+ };
866
+
867
+ ws.onmessage = (event) => {
868
+ try {
869
+ const msg = JSON.parse(event.data);
870
+ handleServerMessage(msg);
871
+ } catch (e) {
872
+ console.error('[Visualizer] Failed to parse message:', e);
873
+ }
874
+ };
875
+
876
+ ws.onerror = (error) => {
877
+ console.error('[Visualizer] WebSocket error:', error);
878
+ };
879
+ }
880
+
881
+ function handleServerMessage(msg) {
882
+ switch (msg.type) {
883
+ case 'ir_update':
884
+ renderIR(msg.payload);
885
+ break;
886
+ case 'snapshot':
887
+ snapshots.push(msg.payload);
888
+ currentSnapshotIndex = snapshots.length - 1;
889
+ updateTimelineUI();
890
+ break;
891
+ case 'snapshots_list':
892
+ snapshots = msg.payload;
893
+ currentSnapshotIndex = snapshots.length - 1;
894
+ updateTimelineUI();
895
+ break;
896
+ case 'performance_data':
897
+ window.__PERFORMANCE_DATA__ = msg.payload;
898
+ if (heatmapEnabled) applyHeatmap();
899
+ break;
900
+ case 'workflow_complete':
901
+ showLiveIndicator(false);
902
+ break;
903
+ case 'time_travel_state':
904
+ currentSnapshotIndex = msg.payload.currentIndex;
905
+ isPlaying = msg.payload.isPlaying;
906
+ playbackSpeed = msg.payload.playbackSpeed;
907
+ updateTimelineUI();
908
+ updatePlaybackUI();
909
+ break;
910
+ }
911
+ }
912
+
913
+ function showLiveIndicator(show) {
914
+ const indicator = document.getElementById('live-indicator');
915
+ if (indicator) {
916
+ indicator.style.display = show ? 'flex' : 'none';
917
+ }
918
+ }
919
+
920
+ // Heatmap
921
+ function setupHeatmap() {
922
+ const toggle = document.getElementById('heatmap-toggle');
923
+ const metricSelect = document.getElementById('heatmap-metric');
924
+
925
+ toggle?.addEventListener('click', () => {
926
+ heatmapEnabled = !heatmapEnabled;
927
+ toggle.classList.toggle('wv-btn--primary', heatmapEnabled);
928
+ if (heatmapEnabled) {
929
+ applyHeatmap();
930
+ } else {
931
+ removeHeatmap();
932
+ }
933
+ });
934
+
935
+ metricSelect?.addEventListener('change', (e) => {
936
+ heatmapMetric = e.target.value;
937
+ if (heatmapEnabled) applyHeatmap();
938
+ });
939
+ }
940
+
941
+ function applyHeatmap() {
942
+ const perfData = window.__PERFORMANCE_DATA__;
943
+ if (!perfData) return;
944
+
945
+ document.querySelectorAll('.wv-node').forEach((node) => {
946
+ const nodeId = node.dataset.nodeId;
947
+ const heat = perfData.heat?.[nodeId];
948
+
949
+ // Remove existing heat classes
950
+ node.classList.remove(
951
+ 'wv-node--heat-cold',
952
+ 'wv-node--heat-cool',
953
+ 'wv-node--heat-neutral',
954
+ 'wv-node--heat-warm',
955
+ 'wv-node--heat-hot',
956
+ 'wv-node--heat-critical'
957
+ );
958
+
959
+ if (heat !== undefined) {
960
+ const level = getHeatLevel(heat);
961
+ node.classList.add('wv-node--heat-' + level);
962
+ }
963
+ });
964
+ }
965
+
966
+ function removeHeatmap() {
967
+ document.querySelectorAll('.wv-node').forEach((node) => {
968
+ node.classList.remove(
969
+ 'wv-node--heat-cold',
970
+ 'wv-node--heat-cool',
971
+ 'wv-node--heat-neutral',
972
+ 'wv-node--heat-warm',
973
+ 'wv-node--heat-hot',
974
+ 'wv-node--heat-critical'
975
+ );
976
+ });
977
+ }
978
+
979
+ function getHeatLevel(heat) {
980
+ if (heat < 0.2) return 'cold';
981
+ if (heat < 0.4) return 'cool';
982
+ if (heat < 0.6) return 'neutral';
983
+ if (heat < 0.8) return 'warm';
984
+ if (heat < 0.95) return 'hot';
985
+ return 'critical';
986
+ }
987
+
988
+ // Keyboard shortcuts
989
+ function setupKeyboardShortcuts() {
990
+ document.addEventListener('keydown', (e) => {
991
+ // Don't trigger shortcuts when typing in inputs
992
+ if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
993
+
994
+ switch (e.key) {
995
+ case ' ':
996
+ e.preventDefault();
997
+ isPlaying ? pause() : play();
998
+ break;
999
+ case 'ArrowLeft':
1000
+ e.preventDefault();
1001
+ stepBackward();
1002
+ break;
1003
+ case 'ArrowRight':
1004
+ e.preventDefault();
1005
+ stepForward();
1006
+ break;
1007
+ case '0':
1008
+ resetZoom();
1009
+ break;
1010
+ case '+':
1011
+ case '=':
1012
+ zoom(1.2);
1013
+ break;
1014
+ case '-':
1015
+ zoom(0.8);
1016
+ break;
1017
+ case 'h':
1018
+ ${e.heatmap?"document.getElementById('heatmap-toggle')?.click();":""}
1019
+ break;
1020
+ case 'Escape':
1021
+ selectNode(null);
1022
+ break;
1023
+ }
1024
+ });
1025
+ }
1026
+
1027
+ // Render functions
1028
+ function renderIR(ir) {
1029
+ // Store node data for inspector
1030
+ window.__WORKFLOW_DATA__ = {
1031
+ nodes: flattenNodes(ir.root.children).reduce((acc, n) => {
1032
+ acc[n.id] = n;
1033
+ return acc;
1034
+ }, {})
1035
+ };
1036
+
1037
+ // Update SVG node states
1038
+ document.querySelectorAll('.wv-node').forEach((node) => {
1039
+ const nodeId = node.dataset.nodeId;
1040
+ const nodeData = window.__WORKFLOW_DATA__.nodes[nodeId];
1041
+ if (nodeData) {
1042
+ // Update state class
1043
+ node.className = node.className.replace(/wv-node--\\w+/g, '');
1044
+ node.classList.add('wv-node', 'wv-node--' + nodeData.state);
1045
+
1046
+ // Update timing text if present
1047
+ const timing = node.querySelector('.wv-node-timing');
1048
+ if (timing && nodeData.durationMs !== undefined) {
1049
+ timing.textContent = formatDuration(nodeData.durationMs);
1050
+ }
1051
+ }
1052
+ });
1053
+
1054
+ // Update selected node inspector
1055
+ if (selectedNodeId) {
1056
+ updateInspector(selectedNodeId);
1057
+ }
1058
+ }
1059
+
1060
+ function flattenNodes(nodes) {
1061
+ const result = [];
1062
+ for (const node of nodes) {
1063
+ result.push(node);
1064
+ if (node.children) {
1065
+ result.push(...flattenNodes(node.children));
1066
+ }
1067
+ if (node.branches) {
1068
+ for (const branch of node.branches) {
1069
+ result.push(...flattenNodes(branch.children));
1070
+ }
1071
+ }
1072
+ }
1073
+ return result;
1074
+ }
1075
+
1076
+ // Utilities
1077
+ function formatDuration(ms) {
1078
+ if (ms < 1) return '<1ms';
1079
+ if (ms < 1000) return Math.round(ms) + 'ms';
1080
+ if (ms < 60000) return (ms / 1000).toFixed(2) + 's';
1081
+ return (ms / 60000).toFixed(1) + 'm';
1082
+ }
1083
+ })();
1084
+ `}var ee=160,de=50,we=40,mt=30,A=20;function ht(e,r="TB"){let t=r==="TB"||r==="BT",a=[],o=A,n=A,c=0,p=0;for(let d of e){let u=be(d,o,n,t);a.push(u.node),t?(n+=u.height+mt,c=Math.max(c,u.width),p=n):(o+=u.width+we,p=Math.max(p,u.height),c=o)}return{nodes:a,width:c+A,height:p+A}}function be(e,r,t,a){if(V(e))return{node:{id:e.id,name:e.name??e.key??"step",type:"step",state:e.state,x:r,y:t,width:ee,height:de,durationMs:e.durationMs},width:ee,height:de};if(J(e)||Y(e)){let o=J(e)?"parallel":"race",n=e.name??o,c=[],p=r+A,d=t+A+20,u=0,s=0;for(let h of e.children){let k=be(h,p,d,!0);c.push(k.node),p+=k.width+we,s=Math.max(s,k.height)}u=p-r-A;let l=Math.max(u+A,ee+A*2),f=s+A*2+20;return{node:{id:e.id,name:n,type:o,state:e.state,x:r,y:t,width:l,height:f,durationMs:e.durationMs,children:c,containerType:o,containerLabel:o==="parallel"?"PARALLEL":"RACE"},width:l,height:f}}if(X(e)){let o=e.name??"decision",n=[],c=r+A,p=t+A+20,d=0;for(let l of e.branches)for(let f of l.children){let h=be(f,c,p,!0);n.push(h.node),c+=h.width+we,d=Math.max(d,h.height)}let u=Math.max(c-r,ee+A*2),s=d+A*2+20;return{node:{id:e.id,name:o,type:"decision",state:e.state,x:r,y:t,width:u,height:s,durationMs:e.durationMs,children:n,containerType:"decision",containerLabel:"DECISION"},width:u,height:s}}return{node:{id:e.id,name:e.name??"unknown",type:e.type,state:e.state,x:r,y:t,width:ee,height:de},width:ee,height:de}}function Le(e,r){return e.containerType?vt(e,r):gt(e,r)}function gt(e,r){let a=r&&e.durationMs!==void 0?H(e.durationMs):"";return`
1085
+ <g class="wv-node wv-node--${e.state}" data-node-id="${He(e.id)}" transform="translate(${e.x}, ${e.y})">
1086
+ <rect width="${e.width}" height="${e.height}" rx="8" ry="8" />
1087
+ <text x="${e.width/2}" y="${e.height/2-(a?4:0)}">${ye(kt(e.name,20))}</text>
1088
+ ${a?`<text class="wv-node-timing" x="${e.width/2}" y="${e.height/2+12}">${a}</text>`:""}
1089
+ </g>
1090
+ `}function vt(e,r){let a=e.children?.map(o=>Le(o,r)).join(`
1091
+ `)??"";return`
1092
+ <g class="wv-container wv-container--${e.containerType}" data-node-id="${He(e.id)}" transform="translate(${e.x}, ${e.y})">
1093
+ <rect width="${e.width}" height="${e.height}" rx="12" ry="12" />
1094
+ <text class="wv-container-label" x="${A}" y="16">${e.containerLabel}</text>
1095
+ <g transform="translate(${-e.x}, ${-e.y})">
1096
+ ${a}
1097
+ </g>
1098
+ </g>
1099
+ `}function wt(e){let r=[];for(let t=0;t<e.length-1;t++){let a=e[t],o=e[t+1],n=a.x+a.width/2,c=a.y+a.height,p=o.x+o.width/2,d=o.y;r.push(`
1100
+ <path class="wv-edge" d="M ${n} ${c} L ${p} ${d-8}" />
1101
+ <polygon class="wv-edge-arrow" points="${p-4},${d-8} ${p+4},${d-8} ${p},${d}" />
1102
+ `)}return r.join(`
1103
+ `)}function Be(e,r){let t=ht(e.root.children,r.layout),a=Math.max(t.width,400),o=Math.max(t.height,300),n=t.nodes.map(s=>Le(s,r.showTimings)).join(`
1104
+ `),c=wt(t.nodes),p=e.root.name??"Workflow",d=Oe(r.theme),u=We({wsUrl:r.wsUrl,interactive:r.interactive,timeTravel:r.timeTravel,heatmap:r.heatmap});return`<!DOCTYPE html>
1105
+ <html lang="en">
1106
+ <head>
1107
+ <meta charset="UTF-8">
1108
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1109
+ <title>${ye(p)} - Workflow Visualizer</title>
1110
+ <style>${d}</style>
1111
+ </head>
1112
+ <body>
1113
+ <div class="workflow-visualizer">
1114
+ <header class="wv-header">
1115
+ <h1>${ye(p)}</h1>
1116
+ <div class="wv-controls">
1117
+ ${r.wsUrl?'<div id="live-indicator" class="wv-live" style="display:none"><span class="wv-live-dot"></span>LIVE</div>':""}
1118
+ ${r.heatmap?`
1119
+ <button id="heatmap-toggle" class="wv-btn">Heatmap</button>
1120
+ <select id="heatmap-metric" class="wv-btn">
1121
+ <option value="duration">Duration</option>
1122
+ <option value="retryRate">Retry Rate</option>
1123
+ <option value="errorRate">Error Rate</option>
1124
+ </select>
1125
+ `:""}
1126
+ ${r.interactive?`
1127
+ <button id="zoom-out" class="wv-btn wv-btn--icon" title="Zoom out (-)">\u2212</button>
1128
+ <button id="zoom-reset" class="wv-btn wv-btn--icon" title="Reset zoom (0)">\u27F2</button>
1129
+ <button id="zoom-in" class="wv-btn wv-btn--icon" title="Zoom in (+)">+</button>
1130
+ `:""}
1131
+ </div>
1132
+ </header>
1133
+
1134
+ <div class="wv-main">
1135
+ <div id="diagram" class="wv-diagram">
1136
+ <svg viewBox="0 0 ${a} ${o}" preserveAspectRatio="xMidYMid meet">
1137
+ <g class="wv-root">
1138
+ ${c}
1139
+ ${n}
1140
+ </g>
1141
+ </svg>
1142
+ </div>
1143
+
1144
+ ${r.interactive?`
1145
+ <aside id="inspector" class="wv-inspector">
1146
+ <div class="wv-inspector-header">
1147
+ <h2>Inspector</h2>
1148
+ </div>
1149
+ <div id="inspector-content" class="wv-inspector-content">
1150
+ <p class="wv-empty">Select a node to inspect</p>
1151
+ </div>
1152
+ </aside>
1153
+ `:""}
1154
+ </div>
1155
+
1156
+ ${r.timeTravel?`
1157
+ <div id="timeline" class="wv-timeline">
1158
+ <div class="wv-timeline-track">
1159
+ <input type="range" id="tt-slider" min="0" max="0" value="0" style="width:100%">
1160
+ </div>
1161
+ <div class="wv-timeline-controls">
1162
+ <button id="tt-prev" class="wv-btn wv-btn--icon" title="Step backward (\u2190)">\u23EE</button>
1163
+ <button id="tt-play" class="wv-btn wv-btn--icon" title="Play (Space)">\u25B6</button>
1164
+ <button id="tt-pause" class="wv-btn wv-btn--icon" style="display:none" title="Pause (Space)">\u23F8</button>
1165
+ <button id="tt-next" class="wv-btn wv-btn--icon" title="Step forward (\u2192)">\u23ED</button>
1166
+ <select id="tt-speed" class="wv-btn">
1167
+ <option value="0.5">0.5x</option>
1168
+ <option value="1" selected>1x</option>
1169
+ <option value="2">2x</option>
1170
+ <option value="4">4x</option>
1171
+ <option value="10">10x</option>
1172
+ </select>
1173
+ <span id="tt-time" class="wv-timeline-time">0 / 0</span>
1174
+ </div>
1175
+ </div>
1176
+ `:""}
1177
+ </div>
1178
+
1179
+ <script>
1180
+ window.__WORKFLOW_DATA__ = ${yt(e)};
1181
+ </script>
1182
+ <script>${u}</script>
1183
+ </body>
1184
+ </html>`}function bt(e){let r={};function t(a){for(let o of a)if(r[o.id]={id:o.id,name:o.name,type:o.type,state:o.state,key:o.key,durationMs:o.durationMs,startTs:o.startTs,error:o.error?String(o.error):void 0,retryCount:o.retryCount},"children"in o&&Array.isArray(o.children)&&t(o.children),"branches"in o)for(let n of o.branches)t(n.children)}return t(e.root.children),{nodes:r}}function yt(e){return JSON.stringify(bt(e)).replace(/</g,"\\u003c").replace(/>/g,"\\u003e").replace(/&/g,"\\u0026").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}function ye(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function He(e){return e.replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function kt(e,r){return e.length<=r?e:e.slice(0,r-1)+"\u2026"}var Pe={interactive:!0,timeTravel:!0,heatmap:!0,animationDuration:200,theme:"auto",layout:"TB"};function St(){return{name:"html",supportsLive:!0,render(e,r){let t={...r,...Pe,...r};return Be(e,t)}}}function ke(e,r={}){let t={showTimings:!0,showKeys:!1,colors:{pending:"#6c757d",running:"#ffc107",success:"#198754",error:"#dc3545",aborted:"#6c757d",cached:"#0dcaf0",skipped:"#adb5bd"},...Pe,...r};return Be(e,t)}var K={clearToEnd:"\x1B[J",cursorUp:e=>`\x1B[${e}A`,cursorToStart:"\x1B[G",hideCursor:"\x1B[?25l",showCursor:"\x1B[?25h",saveCursor:"\x1B[s",restoreCursor:"\x1B[u"};function xt(e={}){let{workflowName:r,detectParallel:t=!0,showTimings:a=!0,showKeys:o=!1,colors:n,stream:c=process.stdout,updateInterval:p=100}=e,d=q({detectParallel:t}),u=Q(),s={showTimings:a,showKeys:o,terminalWidth:c.columns??80,colors:{...j,...n}},l=!1,f="",h=0,k=null,v=!1;function R(N){c.writable&&c.write(N)}function T(){if(!l)return;let N=w(),S=u.render(N,s);S!==f&&(h>0&&(R(K.cursorUp(h)),R(K.cursorToStart),R(K.clearToEnd)),R(S),R(`
1185
+ `),f=S,h=S.split(`
1186
+ `).length)}function B(){l&&(v=!0,k===null&&(k=setTimeout(()=>{k=null,v&&(v=!1,T())},p)))}function O(N){if(N.type==="scope_start"||N.type==="scope_end"){g(N);return}d.handleEvent(N),l&&(N.type==="workflow_start"||N.type==="workflow_success"||N.type==="workflow_error"?T():B())}function g(N){d.handleScopeEvent(N),l&&B()}function I(N){d.handleDecisionEvent(N),l&&B()}function w(){let N=d.getIR();return r&&!N.root.name&&(N.root.name=r),N}function $(){return u.render(w(),s)}function W(){l||(l=!0,f="",h=0,R(K.hideCursor),T())}function C(){if(!l)return;l=!1,k!==null&&(clearTimeout(k),k=null);let N=w(),S=u.render(N,s);h>0&&(R(K.cursorUp(h)),R(K.cursorToStart),R(K.clearToEnd)),R(S),R(`
1187
+ `),R(K.showCursor)}function D(){k!==null&&(clearTimeout(k),k=null),v=!1,T()}function M(){d.reset(),f="",h=0}return{handleEvent:O,handleScopeEvent:g,handleDecisionEvent:I,getIR:w,render:$,start:W,stop:C,refresh:D,reset:M}}function Se(e,r={}){let{condition:t,value:a,name:o,workflowId:n=crypto.randomUUID(),emit:c}=r,p=Date.now(),d,u=[];function s(f,h,k){u.push({label:f,condition:k,taken:h}),h&&(d=f),c?.({type:"decision_branch",workflowId:n,decisionId:e,branchLabel:f,condition:k,taken:h,ts:Date.now()})}function l(){let f=Date.now()-p;c?.({type:"decision_end",workflowId:n,decisionId:e,branchTaken:d,ts:Date.now(),durationMs:f})}return c?.({type:"decision_start",workflowId:n,decisionId:e,condition:t,decisionValue:a,name:o,ts:p}),{takeBranch:s,end:l,getBranchTaken:()=>d,getBranches:()=>[...u]}}function $t(e,r,t={}){let a=Se(e,{...t,condition:t.condition??String(r),value:t.value??r});return{...a,condition:r,then:()=>{a.takeBranch("if",!0)},else:()=>{a.takeBranch("else",!0)}}}function Rt(e,r,t={}){let a=Se(e,{...t,condition:t.condition??`switch(${String(r)})`,value:r});return{...a,value:r,case:(o,n)=>{a.takeBranch(`case '${o}'`,n,`value === '${o}'`)},default:o=>{a.takeBranch("default",o)}}}function xe(e={}){let{maxSnapshots:r=1e3,autoRecord:t=!0,builderOptions:a={}}=e,o=q({...a,enableSnapshots:!0,maxSnapshots:r}),n={snapshots:[],currentIndex:-1,isPlaying:!1,playbackSpeed:1,isRecording:t},c=new Set,p=null;function d(){let D=g();for(let M of c)M(D)}function u(){n.snapshots=o.getSnapshots(),n.isRecording&&n.snapshots.length>0&&(n.currentIndex=n.snapshots.length-1)}function s(D){o.handleEvent(D),n.isRecording&&(u(),d())}function l(D){let M=o.getSnapshots();if(!(D<0||D>=M.length))return n.currentIndex=D,n.snapshots=M,d(),M[D].ir}function f(){return l(n.currentIndex+1)}function h(){return l(n.currentIndex-1)}function k(D=1){n.playbackSpeed=D,n.isPlaying=!0,d();let M=()=>{if(!n.isPlaying)return;let N=o.getSnapshots();if(n.currentIndex<N.length-1){let S=N[n.currentIndex],L=(N[n.currentIndex+1].timestamp-S.timestamp)/n.playbackSpeed;p=setTimeout(()=>{f(),M()},Math.max(16,L))}else v()};M()}function v(){n.isPlaying=!1,p&&(clearTimeout(p),p=null),d()}function R(){let D=o.getSnapshots();return n.currentIndex>=0&&n.currentIndex<D.length?D[n.currentIndex].ir:o.getIR()}function T(D){return o.getIRAt(D)}function B(){return o.getSnapshots()}function O(D){return o.getSnapshotAt(D)}function g(){return{snapshots:o.getSnapshots(),currentIndex:n.currentIndex,isPlaying:n.isPlaying,playbackSpeed:n.playbackSpeed,isRecording:n.isRecording}}function I(D){return c.add(D),()=>c.delete(D)}function w(){n.isRecording=!0,d()}function $(){n.isRecording=!1,d()}function W(){v(),o.reset(),n={snapshots:[],currentIndex:-1,isPlaying:!1,playbackSpeed:1,isRecording:t},d()}function C(){return o}return{handleEvent:s,seek:l,stepForward:f,stepBackward:h,play:k,pause:v,getCurrentIR:R,getIRAt:T,getSnapshots:B,getSnapshotAt:O,getState:g,onStateChange:I,startRecording:w,stopRecording:$,reset:W,getBuilder:C}}import{createServer as Et}from"http";import{execFile as $e}from"child_process";async function It(e={}){let{port:r=3377,host:t="localhost",autoOpen:a=!0,workflowName:o="Workflow",timeTravel:n=!0,heatmap:c=!0,maxSnapshots:p=1e3}=e,d=xe({maxSnapshots:p}),u=ve(),s=null,l=null,f=r,h=!1;function k(S){if(!l)return;let x=JSON.stringify(S);for(let E of l.clients)E.readyState===E.OPEN&&E.send(x)}function v(S,x){try{let E=JSON.parse(typeof x=="string"?x:x.toString());switch(E.type){case"time_travel_seek":{let L=E.payload,i=d.seek(L.index);i&&S.send(JSON.stringify({type:"ir_update",payload:i}));break}case"time_travel_play":{let L=E.payload;d.play(L?.speed);break}case"time_travel_pause":d.pause();break;case"time_travel_step_forward":{let L=d.stepForward();L&&S.send(JSON.stringify({type:"ir_update",payload:L}));break}case"time_travel_step_backward":{let L=d.stepBackward();L&&S.send(JSON.stringify({type:"ir_update",payload:L}));break}case"request_snapshots":{let L=d.getSnapshots().map(i=>({id:i.id,eventIndex:i.eventIndex,timestamp:i.timestamp}));S.send(JSON.stringify({type:"snapshots_list",payload:L}));break}case"toggle_heatmap":case"set_heatmap_metric":break}}catch(E){console.error("[DevServer] Failed to handle message:",E)}}function R(){let S=d.getCurrentIR(),x=`ws://${t}:${f}`;return ke(S,{interactive:!0,timeTravel:n,heatmap:c,theme:"auto",layout:"TB",wsUrl:x})}function T(S,x){let E=S.url??"/";if(E==="/"||E==="/index.html"){x.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),x.end(R());return}if(E==="/api/snapshots"){let L=d.getSnapshots().map(i=>({id:i.id,eventIndex:i.eventIndex,timestamp:i.timestamp}));x.writeHead(200,{"Content-Type":"application/json"}),x.end(JSON.stringify(L));return}if(E==="/api/performance"){x.writeHead(200,{"Content-Type":"application/json"}),x.end(u.exportData());return}if(E==="/api/ir"){x.writeHead(200,{"Content-Type":"application/json"}),x.end(JSON.stringify(d.getCurrentIR()));return}x.writeHead(404,{"Content-Type":"text/plain"}),x.end("Not Found")}async function B(){try{let x=await import("ws"),E=x.WebSocketServer??x.default?.WebSocketServer;return E?new E({noServer:!0}):(console.warn("[DevServer] WebSocket server class not found in ws module"),null)}catch{return console.warn(`[DevServer] ws package not installed. Live updates disabled.
1188
+ Install with: npm install ws`),null}}function O(S){let x=process.platform;if(!S.startsWith("http://localhost:")&&!S.startsWith("http://127.0.0.1:")){console.warn("[DevServer] Refusing to open non-localhost URL");return}x==="darwin"?$e("open",[S],E=>{E&&console.warn("[DevServer] Failed to open browser:",E.message)}):x==="win32"?$e("cmd.exe",["/c","start","",S],E=>{E&&console.warn("[DevServer] Failed to open browser:",E.message)}):$e("xdg-open",[S],E=>{E&&console.warn("[DevServer] Failed to open browser:",E.message)})}async function g(){return h?{port:f,url:`http://${t}:${f}`}:(s=Et(T),l=await B(),l&&(s.on("upgrade",(S,x,E)=>{if(!l)return;l.handleUpgrade(S,x,E,i=>{i.send(JSON.stringify({type:"ir_update",payload:d.getCurrentIR()})),i.on("message",m=>v(i,m)),i.on("error",m=>console.error("[DevServer] WS error:",m))})}),d.onStateChange(S=>{k({type:"time_travel_state",payload:S})})),new Promise((S,x)=>{if(!s){x(new Error("HTTP server not initialized"));return}s.on("error",E=>{E.code==="EADDRINUSE"?(f++,s?.listen(f,t)):x(E)}),s.on("listening",()=>{h=!0;let E=`http://${t}:${f}`;console.log(`[DevServer] Visualizer running at ${E}`),a&&O(E),S({port:f,url:E})}),s.listen(f,t)}))}async function I(){if(h)return new Promise(S=>{l&&(l.close(),l=null),s?s.close(()=>{s=null,h=!1,S()}):S()})}function w(S){d.handleEvent(S),u.addEvent(S),k({type:"ir_update",payload:d.getCurrentIR()})}function $(S){k({type:"ir_update",payload:S})}function W(S){let x={};for(let[E,L]of S.heat)x[E]=L;k({type:"performance_data",payload:{...S,heat:x}})}function C(){u.finalizeRun("current"),k({type:"workflow_complete",payload:null})}function D(){return d}function M(){return u}function N(){return d.getCurrentIR()}return{start:g,stop:I,handleEvent:w,pushUpdate:$,pushHeatmap:W,complete:C,getTimeTravel:D,getAnalyzer:M,getCurrentIR:N}}function Re(e={}){let{workflowName:r,detectParallel:t=!0,showTimings:a=!0,showKeys:o=!1,colors:n}=e,c=q({detectParallel:t}),p=new Set,d=Q(),u=se(),s={showTimings:a,showKeys:o,terminalWidth:process.stdout?.columns??80,colors:{...j,...n}};function l(){if(p.size>0){let g=c.getIR();for(let I of p)I(g)}}function f(g){if(g.type==="scope_start"||g.type==="scope_end"){h(g);return}c.handleEvent(g),g.type,l()}function h(g){c.handleScopeEvent(g),l()}function k(g){c.handleDecisionEvent(g),l()}function v(){let g=c.getIR();return r&&!g.root.name&&(g.root.name=r),g}function R(){let g=v();return d.render(g,s)}function T(g){let I=v();switch(g){case"ascii":return d.render(I,s);case"mermaid":return u.render(I,s);case"json":return JSON.stringify(I,null,2);default:throw new Error(`Unknown format: ${g}`)}}function B(){c.reset(),l()}function O(g){return p.add(g),()=>p.delete(g)}return{handleEvent:f,handleScopeEvent:h,handleDecisionEvent:k,getIR:v,render:R,renderAs:T,reset:B,onUpdate:O}}function wn(e,r={}){let t=Re(r);for(let a of e)a.type.startsWith("decision_")?t.handleDecisionEvent(a):t.handleEvent(a);return t.render()}function bn(e={}){let r=[];return{handleEvent:t=>{r.push(t)},handleDecisionEvent:t=>{r.push(t)},getEvents:()=>[...r],getWorkflowEvents:()=>r.filter(t=>!t.type.startsWith("decision_")),getDecisionEvents:()=>r.filter(t=>t.type.startsWith("decision_")),clear:()=>{r.length=0},visualize:()=>{let t=Re(e);for(let a of r)a.type.startsWith("decision_")?t.handleDecisionEvent(a):t.handleEvent(a);return t.render()},visualizeAs:t=>{let a=Re(e);for(let o of r)o.type.startsWith("decision_")?a.handleDecisionEvent(o):a.handleEvent(o);return a.renderAs(t)}}}export{Q as asciiRenderer,It as createDevServer,bn as createEventCollector,q as createIRBuilder,xt as createLiveVisualizer,Fe as createParallelDetector,ve as createPerformanceAnalyzer,xe as createTimeTravelController,Re as createVisualizer,j as defaultColorScheme,oe as detectParallelGroups,ge as getHeatLevel,Ot as hasChildren,St as htmlRenderer,X as isDecisionNode,J as isParallelNode,Y as isRaceNode,Ct as isSequenceNode,V as isStepNode,se as mermaidRenderer,ke as renderToHTML,Se as trackDecision,$t as trackIf,Rt as trackSwitch,wn as visualizeEvents};
7
1189
  //# sourceMappingURL=visualize.js.map