clementine-agent 1.2.2 → 1.3.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/agent/assistant.js +12 -0
- package/dist/cli/dashboard.js +3034 -734
- package/dist/cli/static/LICENSE-NOTICES.md +12 -0
- package/dist/cli/static/drawflow.min.css +1 -0
- package/dist/cli/static/drawflow.min.js +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +16 -0
- package/dist/dashboard/builder/dry-run.d.ts +31 -0
- package/dist/dashboard/builder/dry-run.js +138 -0
- package/dist/dashboard/builder/events.d.ts +23 -0
- package/dist/dashboard/builder/events.js +28 -0
- package/dist/dashboard/builder/mcp-invoke.d.ts +25 -0
- package/dist/dashboard/builder/mcp-invoke.js +143 -0
- package/dist/dashboard/builder/runner.d.ts +68 -0
- package/dist/dashboard/builder/runner.js +418 -0
- package/dist/dashboard/builder/serializer.d.ts +79 -0
- package/dist/dashboard/builder/serializer.js +547 -0
- package/dist/dashboard/builder/snapshots.d.ts +32 -0
- package/dist/dashboard/builder/snapshots.js +138 -0
- package/dist/dashboard/builder/validation.d.ts +26 -0
- package/dist/dashboard/builder/validation.js +183 -0
- package/dist/gateway/router.js +31 -2
- package/dist/index.js +38 -0
- package/dist/memory/chunker.js +13 -2
- package/dist/memory/hot-cache.d.ts +38 -0
- package/dist/memory/hot-cache.js +73 -0
- package/dist/memory/integrity.d.ts +28 -0
- package/dist/memory/integrity.js +119 -0
- package/dist/memory/maintenance.d.ts +23 -2
- package/dist/memory/maintenance.js +140 -3
- package/dist/memory/store.d.ts +259 -2
- package/dist/memory/store.js +751 -21
- package/dist/memory/write-queue.d.ts +96 -0
- package/dist/memory/write-queue.js +165 -0
- package/dist/tools/builder-tools.d.ts +13 -0
- package/dist/tools/builder-tools.js +437 -0
- package/dist/tools/mcp-server.js +2 -0
- package/dist/tools/memory-tools.js +38 -1
- package/dist/types.d.ts +56 -2
- package/package.json +2 -2
- package/vault/00-System/skills/builder-canvas.md +126 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Vendored static assets
|
|
2
|
+
|
|
3
|
+
## Drawflow
|
|
4
|
+
- File: `drawflow.min.js`, `drawflow.min.css`
|
|
5
|
+
- Version: 0.0.59
|
|
6
|
+
- License: MIT
|
|
7
|
+
- Source: https://github.com/jerosoler/Drawflow
|
|
8
|
+
- Used by: dashboard Builder page (visual workflow canvas)
|
|
9
|
+
|
|
10
|
+
The minified files are vendored verbatim from the official jsdelivr CDN
|
|
11
|
+
for reproducibility. To upgrade, replace both files and update the
|
|
12
|
+
version line above.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.drawflow,.drawflow .parent-node{position:relative}.parent-drawflow{display:flex;overflow:hidden;touch-action:none;outline:0}.drawflow{width:100%;height:100%;user-select:none;perspective:0}.drawflow .drawflow-node{display:flex;align-items:center;position:absolute;background:#0ff;width:160px;min-height:40px;border-radius:4px;border:2px solid #000;color:#000;z-index:2;padding:15px}.drawflow .drawflow-node.selected{background:red}.drawflow .drawflow-node:hover{cursor:move}.drawflow .drawflow-node .inputs,.drawflow .drawflow-node .outputs{width:0}.drawflow .drawflow-node .drawflow_content_node{width:100%;display:block}.drawflow .drawflow-node .input,.drawflow .drawflow-node .output{position:relative;width:20px;height:20px;background:#fff;border-radius:50%;border:2px solid #000;cursor:crosshair;z-index:1;margin-bottom:5px}.drawflow .drawflow-node .input{left:-27px;top:2px;background:#ff0}.drawflow .drawflow-node .output{right:-3px;top:2px}.drawflow svg{z-index:0;position:absolute;overflow:visible!important}.drawflow .connection{position:absolute;pointer-events:none;aspect-ratio:1/1}.drawflow .connection .main-path{fill:none;stroke-width:5px;stroke:#4682b4;pointer-events:all}.drawflow .connection .main-path:hover{stroke:#1266ab;cursor:pointer}.drawflow .connection .main-path.selected{stroke:#43b993}.drawflow .connection .point{cursor:move;stroke:#000;stroke-width:2;fill:#fff;pointer-events:all}.drawflow .connection .point.selected,.drawflow .connection .point:hover{fill:#1266ab}.drawflow .main-path{fill:none;stroke-width:5px;stroke:#4682b4}.drawflow-delete{position:absolute;display:block;width:30px;height:30px;background:#000;color:#fff;z-index:4;border:2px solid #fff;line-height:30px;font-weight:700;text-align:center;border-radius:50%;font-family:monospace;cursor:pointer}.drawflow>.drawflow-delete{margin-left:-15px;margin-top:15px}.parent-node .drawflow-delete{right:-15px;top:-15px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Drawflow=t():e.Drawflow=t()}("undefined"!=typeof self?self:this,(function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var s=t[i]={i:i,l:!1,exports:{}};return e[i].call(s.exports,s,s.exports,n),s.l=!0,s.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)n.d(i,s,function(t){return e[t]}.bind(null,s));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t),n.d(t,"default",(function(){return i}));class i{constructor(e,t=null,n=null){this.events={},this.container=e,this.precanvas=null,this.nodeId=1,this.ele_selected=null,this.node_selected=null,this.drag=!1,this.reroute=!1,this.reroute_fix_curvature=!1,this.curvature=.5,this.reroute_curvature_start_end=.5,this.reroute_curvature=.5,this.reroute_width=6,this.drag_point=!1,this.editor_selected=!1,this.connection=!1,this.connection_ele=null,this.connection_selected=null,this.canvas_x=0,this.canvas_y=0,this.pos_x=0,this.pos_x_start=0,this.pos_y=0,this.pos_y_start=0,this.mouse_x=0,this.mouse_y=0,this.line_path=5,this.first_click=null,this.force_first_input=!1,this.draggable_inputs=!0,this.useuuid=!1,this.parent=n,this.noderegister={},this.render=t,this.drawflow={drawflow:{Home:{data:{}}}},this.module="Home",this.editor_mode="edit",this.zoom=1,this.zoom_max=1.6,this.zoom_min=.5,this.zoom_value=.1,this.zoom_last_value=1,this.evCache=new Array,this.prevDiff=-1}start(){this.container.classList.add("parent-drawflow"),this.container.tabIndex=0,this.precanvas=document.createElement("div"),this.precanvas.classList.add("drawflow"),this.container.appendChild(this.precanvas),this.container.addEventListener("mouseup",this.dragEnd.bind(this)),this.container.addEventListener("mousemove",this.position.bind(this)),this.container.addEventListener("mousedown",this.click.bind(this)),this.container.addEventListener("touchend",this.dragEnd.bind(this)),this.container.addEventListener("touchmove",this.position.bind(this)),this.container.addEventListener("touchstart",this.click.bind(this)),this.container.addEventListener("contextmenu",this.contextmenu.bind(this)),this.container.addEventListener("keydown",this.key.bind(this)),this.container.addEventListener("wheel",this.zoom_enter.bind(this)),this.container.addEventListener("input",this.updateNodeValue.bind(this)),this.container.addEventListener("dblclick",this.dblclick.bind(this)),this.container.onpointerdown=this.pointerdown_handler.bind(this),this.container.onpointermove=this.pointermove_handler.bind(this),this.container.onpointerup=this.pointerup_handler.bind(this),this.container.onpointercancel=this.pointerup_handler.bind(this),this.container.onpointerout=this.pointerup_handler.bind(this),this.container.onpointerleave=this.pointerup_handler.bind(this),this.load()}pointerdown_handler(e){this.evCache.push(e)}pointermove_handler(e){for(var t=0;t<this.evCache.length;t++)if(e.pointerId==this.evCache[t].pointerId){this.evCache[t]=e;break}if(2==this.evCache.length){var n=Math.abs(this.evCache[0].clientX-this.evCache[1].clientX);this.prevDiff>100&&(n>this.prevDiff&&this.zoom_in(),n<this.prevDiff&&this.zoom_out()),this.prevDiff=n}}pointerup_handler(e){this.remove_event(e),this.evCache.length<2&&(this.prevDiff=-1)}remove_event(e){for(var t=0;t<this.evCache.length;t++)if(this.evCache[t].pointerId==e.pointerId){this.evCache.splice(t,1);break}}load(){for(var e in this.drawflow.drawflow[this.module].data)this.addNodeImport(this.drawflow.drawflow[this.module].data[e],this.precanvas);if(this.reroute)for(var e in this.drawflow.drawflow[this.module].data)this.addRerouteImport(this.drawflow.drawflow[this.module].data[e]);for(var e in this.drawflow.drawflow[this.module].data)this.updateConnectionNodes("node-"+e);const t=this.drawflow.drawflow;let n=1;Object.keys(t).map((function(e,i){Object.keys(t[e].data).map((function(e,t){parseInt(e)>=n&&(n=parseInt(e)+1)}))})),this.nodeId=n}removeReouteConnectionSelected(){this.dispatch("connectionUnselected",!0),this.reroute_fix_curvature&&this.connection_selected.parentElement.querySelectorAll(".main-path").forEach((e,t)=>{e.classList.remove("selected")})}click(e){if(this.dispatch("click",e),"fixed"===this.editor_mode){if(e.preventDefault(),"parent-drawflow"!==e.target.classList[0]&&"drawflow"!==e.target.classList[0])return!1;this.ele_selected=e.target.closest(".parent-drawflow")}else"view"===this.editor_mode?(null!=e.target.closest(".drawflow")||e.target.matches(".parent-drawflow"))&&(this.ele_selected=e.target.closest(".parent-drawflow"),e.preventDefault()):(this.first_click=e.target,this.ele_selected=e.target,0===e.button&&this.contextmenuDel(),null!=e.target.closest(".drawflow_content_node")&&(this.ele_selected=e.target.closest(".drawflow_content_node").parentElement));switch(this.ele_selected.classList[0]){case"drawflow-node":null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected!=this.ele_selected&&this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.node_selected!=this.ele_selected&&this.dispatch("nodeSelected",this.ele_selected.id.slice(5)),this.node_selected=this.ele_selected,this.node_selected.classList.add("selected"),this.draggable_inputs?"SELECT"!==e.target.tagName&&(this.drag=!0):"INPUT"!==e.target.tagName&&"TEXTAREA"!==e.target.tagName&&"SELECT"!==e.target.tagName&&!0!==e.target.hasAttribute("contenteditable")&&(this.drag=!0);break;case"output":this.connection=!0,null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.drawConnection(e.target);break;case"parent-drawflow":case"drawflow":null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.editor_selected=!0;break;case"main-path":null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.connection_selected=this.ele_selected,this.connection_selected.classList.add("selected");const t=this.connection_selected.parentElement.classList;t.length>1&&(this.dispatch("connectionSelected",{output_id:t[2].slice(14),input_id:t[1].slice(13),output_class:t[3],input_class:t[4]}),this.reroute_fix_curvature&&this.connection_selected.parentElement.querySelectorAll(".main-path").forEach((e,t)=>{e.classList.add("selected")}));break;case"point":this.drag_point=!0,this.ele_selected.classList.add("selected");break;case"drawflow-delete":this.node_selected&&this.removeNodeId(this.node_selected.id),this.connection_selected&&this.removeConnection(),null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null)}"touchstart"===e.type?(this.pos_x=e.touches[0].clientX,this.pos_x_start=e.touches[0].clientX,this.pos_y=e.touches[0].clientY,this.pos_y_start=e.touches[0].clientY,this.mouse_x=e.touches[0].clientX,this.mouse_y=e.touches[0].clientY):(this.pos_x=e.clientX,this.pos_x_start=e.clientX,this.pos_y=e.clientY,this.pos_y_start=e.clientY),["input","output","main-path"].includes(this.ele_selected.classList[0])&&e.preventDefault(),this.dispatch("clickEnd",e)}position(e){if("touchmove"===e.type)var t=e.touches[0].clientX,n=e.touches[0].clientY;else t=e.clientX,n=e.clientY;if(this.connection&&this.updateConnection(t,n),this.editor_selected&&(i=this.canvas_x+-(this.pos_x-t),s=this.canvas_y+-(this.pos_y-n),this.dispatch("translate",{x:i,y:s}),this.precanvas.style.transform="translate("+i+"px, "+s+"px) scale("+this.zoom+")"),this.drag){e.preventDefault();var i=(this.pos_x-t)*this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom),s=(this.pos_y-n)*this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom);this.pos_x=t,this.pos_y=n,this.ele_selected.style.top=this.ele_selected.offsetTop-s+"px",this.ele_selected.style.left=this.ele_selected.offsetLeft-i+"px",this.drawflow.drawflow[this.module].data[this.ele_selected.id.slice(5)].pos_x=this.ele_selected.offsetLeft-i,this.drawflow.drawflow[this.module].data[this.ele_selected.id.slice(5)].pos_y=this.ele_selected.offsetTop-s,this.updateConnectionNodes(this.ele_selected.id)}if(this.drag_point){i=(this.pos_x-t)*this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom),s=(this.pos_y-n)*this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom);this.pos_x=t,this.pos_y=n;var o=this.pos_x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))-this.precanvas.getBoundingClientRect().x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom)),l=this.pos_y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))-this.precanvas.getBoundingClientRect().y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom));this.ele_selected.setAttributeNS(null,"cx",o),this.ele_selected.setAttributeNS(null,"cy",l);const e=this.ele_selected.parentElement.classList[2].slice(9),c=this.ele_selected.parentElement.classList[1].slice(13),d=this.ele_selected.parentElement.classList[3],a=this.ele_selected.parentElement.classList[4];let r=Array.from(this.ele_selected.parentElement.children).indexOf(this.ele_selected)-1;if(this.reroute_fix_curvature){r-=this.ele_selected.parentElement.querySelectorAll(".main-path").length-1,r<0&&(r=0)}const h=e.slice(5),u=this.drawflow.drawflow[this.module].data[h].outputs[d].connections.findIndex((function(e,t){return e.node===c&&e.output===a}));this.drawflow.drawflow[this.module].data[h].outputs[d].connections[u].points[r]={pos_x:o,pos_y:l};const p=this.ele_selected.parentElement.classList[2].slice(9);this.updateConnectionNodes(p)}"touchmove"===e.type&&(this.mouse_x=t,this.mouse_y=n),this.dispatch("mouseMove",{x:t,y:n})}dragEnd(e){if("touchend"===e.type)var t=this.mouse_x,n=this.mouse_y,i=document.elementFromPoint(t,n);else t=e.clientX,n=e.clientY,i=e.target;if(this.drag&&(this.pos_x_start==t&&this.pos_y_start==n||this.dispatch("nodeMoved",this.ele_selected.id.slice(5))),this.drag_point&&(this.ele_selected.classList.remove("selected"),this.pos_x_start==t&&this.pos_y_start==n||this.dispatch("rerouteMoved",this.ele_selected.parentElement.classList[2].slice(14))),this.editor_selected&&(this.canvas_x=this.canvas_x+-(this.pos_x-t),this.canvas_y=this.canvas_y+-(this.pos_y-n),this.editor_selected=!1),!0===this.connection)if("input"===i.classList[0]||this.force_first_input&&(null!=i.closest(".drawflow_content_node")||"drawflow-node"===i.classList[0])){if(!this.force_first_input||null==i.closest(".drawflow_content_node")&&"drawflow-node"!==i.classList[0])s=i.parentElement.parentElement.id,o=i.classList[1];else{if(null!=i.closest(".drawflow_content_node"))var s=i.closest(".drawflow_content_node").parentElement.id;else var s=i.id;if(0===Object.keys(this.getNodeFromId(s.slice(5)).inputs).length)var o=!1;else var o="input_1"}var l=this.ele_selected.parentElement.parentElement.id,c=this.ele_selected.classList[1];if(l!==s&&!1!==o){if(0===this.container.querySelectorAll(".connection.node_in_"+s+".node_out_"+l+"."+c+"."+o).length){this.connection_ele.classList.add("node_in_"+s),this.connection_ele.classList.add("node_out_"+l),this.connection_ele.classList.add(c),this.connection_ele.classList.add(o);var d=s.slice(5),a=l.slice(5);this.drawflow.drawflow[this.module].data[a].outputs[c].connections.push({node:d,output:o}),this.drawflow.drawflow[this.module].data[d].inputs[o].connections.push({node:a,input:c}),this.updateConnectionNodes("node-"+a),this.updateConnectionNodes("node-"+d),this.dispatch("connectionCreated",{output_id:a,input_id:d,output_class:c,input_class:o})}else this.dispatch("connectionCancel",!0),this.connection_ele.remove();this.connection_ele=null}else this.dispatch("connectionCancel",!0),this.connection_ele.remove(),this.connection_ele=null}else this.dispatch("connectionCancel",!0),this.connection_ele.remove(),this.connection_ele=null;this.drag=!1,this.drag_point=!1,this.connection=!1,this.ele_selected=null,this.editor_selected=!1,this.dispatch("mouseUp",e)}contextmenu(e){if(this.dispatch("contextmenu",e),e.preventDefault(),"fixed"===this.editor_mode||"view"===this.editor_mode)return!1;if(this.precanvas.getElementsByClassName("drawflow-delete").length&&this.precanvas.getElementsByClassName("drawflow-delete")[0].remove(),this.node_selected||this.connection_selected){var t=document.createElement("div");t.classList.add("drawflow-delete"),t.innerHTML="x",this.node_selected&&this.node_selected.appendChild(t),this.connection_selected&&this.connection_selected.parentElement.classList.length>1&&(t.style.top=e.clientY*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))-this.precanvas.getBoundingClientRect().y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))+"px",t.style.left=e.clientX*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))-this.precanvas.getBoundingClientRect().x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))+"px",this.precanvas.appendChild(t))}}contextmenuDel(){this.precanvas.getElementsByClassName("drawflow-delete").length&&this.precanvas.getElementsByClassName("drawflow-delete")[0].remove()}key(e){if(this.dispatch("keydown",e),"fixed"===this.editor_mode||"view"===this.editor_mode)return!1;("Delete"===e.key||"Backspace"===e.key&&e.metaKey)&&(null!=this.node_selected&&"INPUT"!==this.first_click.tagName&&"TEXTAREA"!==this.first_click.tagName&&!0!==this.first_click.hasAttribute("contenteditable")&&this.removeNodeId(this.node_selected.id),null!=this.connection_selected&&this.removeConnection())}zoom_enter(e,t){e.ctrlKey&&(e.preventDefault(),e.deltaY>0?this.zoom_out():this.zoom_in())}zoom_refresh(){this.dispatch("zoom",this.zoom),this.canvas_x=this.canvas_x/this.zoom_last_value*this.zoom,this.canvas_y=this.canvas_y/this.zoom_last_value*this.zoom,this.zoom_last_value=this.zoom,this.precanvas.style.transform="translate("+this.canvas_x+"px, "+this.canvas_y+"px) scale("+this.zoom+")"}zoom_in(){this.zoom<this.zoom_max&&(this.zoom+=this.zoom_value,this.zoom_refresh())}zoom_out(){this.zoom>this.zoom_min&&(this.zoom-=this.zoom_value,this.zoom_refresh())}zoom_reset(){1!=this.zoom&&(this.zoom=1,this.zoom_refresh())}createCurvature(e,t,n,i,s,o){var l=e,c=t,d=n,a=i,r=s;switch(o){case"open":if(e>=n)var h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*(-1*r);else h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*r;return" M "+l+" "+c+" C "+h+" "+c+" "+u+" "+a+" "+d+" "+a;case"close":if(e>=n)h=l+Math.abs(d-l)*(-1*r),u=d-Math.abs(d-l)*r;else h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*r;return" M "+l+" "+c+" C "+h+" "+c+" "+u+" "+a+" "+d+" "+a;case"other":if(e>=n)h=l+Math.abs(d-l)*(-1*r),u=d-Math.abs(d-l)*(-1*r);else h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*r;return" M "+l+" "+c+" C "+h+" "+c+" "+u+" "+a+" "+d+" "+a;default:return" M "+l+" "+c+" C "+(h=l+Math.abs(d-l)*r)+" "+c+" "+(u=d-Math.abs(d-l)*r)+" "+a+" "+d+" "+a}}drawConnection(e){var t=document.createElementNS("http://www.w3.org/2000/svg","svg");this.connection_ele=t;var n=document.createElementNS("http://www.w3.org/2000/svg","path");n.classList.add("main-path"),n.setAttributeNS(null,"d",""),t.classList.add("connection"),t.appendChild(n),this.precanvas.appendChild(t);var i=e.parentElement.parentElement.id.slice(5),s=e.classList[1];this.dispatch("connectionStart",{output_id:i,output_class:s})}updateConnection(e,t){const n=this.precanvas,i=this.zoom;let s=n.clientWidth/(n.clientWidth*i);s=s||0;let o=n.clientHeight/(n.clientHeight*i);o=o||0;var l=this.connection_ele.children[0],c=this.ele_selected.offsetWidth/2+(this.ele_selected.getBoundingClientRect().x-n.getBoundingClientRect().x)*s,d=this.ele_selected.offsetHeight/2+(this.ele_selected.getBoundingClientRect().y-n.getBoundingClientRect().y)*o,a=e*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))-this.precanvas.getBoundingClientRect().x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom)),r=t*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))-this.precanvas.getBoundingClientRect().y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom)),h=this.curvature,u=this.createCurvature(c,d,a,r,h,"openclose");l.setAttributeNS(null,"d",u)}addConnection(e,t,n,i){var s=this.getModuleFromNodeId(e);if(s===this.getModuleFromNodeId(t)){var o=this.getNodeFromId(e),l=!1;for(var c in o.outputs[n].connections){var d=o.outputs[n].connections[c];d.node==t&&d.output==i&&(l=!0)}if(!1===l){if(this.drawflow.drawflow[s].data[e].outputs[n].connections.push({node:t.toString(),output:i}),this.drawflow.drawflow[s].data[t].inputs[i].connections.push({node:e.toString(),input:n}),this.module===s){var a=document.createElementNS("http://www.w3.org/2000/svg","svg"),r=document.createElementNS("http://www.w3.org/2000/svg","path");r.classList.add("main-path"),r.setAttributeNS(null,"d",""),a.classList.add("connection"),a.classList.add("node_in_node-"+t),a.classList.add("node_out_node-"+e),a.classList.add(n),a.classList.add(i),a.appendChild(r),this.precanvas.appendChild(a),this.updateConnectionNodes("node-"+e),this.updateConnectionNodes("node-"+t)}this.dispatch("connectionCreated",{output_id:e,input_id:t,output_class:n,input_class:i})}}}updateConnectionNodes(e){const t="node_in_"+e,n="node_out_"+e;this.line_path;const i=this.container,s=this.precanvas,o=this.curvature,l=this.createCurvature,c=this.reroute_curvature,d=this.reroute_curvature_start_end,a=this.reroute_fix_curvature,r=this.reroute_width,h=this.zoom;let u=s.clientWidth/(s.clientWidth*h);u=u||0;let p=s.clientHeight/(s.clientHeight*h);p=p||0;const f=i.querySelectorAll("."+n);Object.keys(f).map((function(t,n){if(null===f[t].querySelector(".point")){var m=i.querySelector("#"+e),g=f[t].classList[1].replace("node_in_",""),_=i.querySelector("#"+g).querySelectorAll("."+f[t].classList[4])[0],w=_.offsetWidth/2+(_.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,v=_.offsetHeight/2+(_.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,y=m.querySelectorAll("."+f[t].classList[3])[0],C=y.offsetWidth/2+(y.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,x=y.offsetHeight/2+(y.getBoundingClientRect().y-s.getBoundingClientRect().y)*p;const n=l(C,x,w,v,o,"openclose");f[t].children[0].setAttributeNS(null,"d",n)}else{const n=f[t].querySelectorAll(".point");let o="";const m=[];n.forEach((t,a)=>{if(0===a&&n.length-1==0){var f=i.querySelector("#"+e),g=((x=t).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,_=(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,w=(L=f.querySelectorAll("."+t.parentElement.classList[3])[0]).offsetWidth/2+(L.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,v=L.offsetHeight/2+(L.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,y=l(w,v,g,_,d,"open");o+=y,m.push(y);f=t;var C=t.parentElement.classList[1].replace("node_in_",""),x=(E=i.querySelector("#"+C)).querySelectorAll("."+t.parentElement.classList[4])[0];g=(R=E.querySelectorAll("."+t.parentElement.classList[4])[0]).offsetWidth/2+(R.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,_=R.offsetHeight/2+(R.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,w=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,v=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,y=l(w,v,g,_,d,"close");o+=y,m.push(y)}else if(0===a){var L;f=i.querySelector("#"+e),g=((x=t).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,_=(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,w=(L=f.querySelectorAll("."+t.parentElement.classList[3])[0]).offsetWidth/2+(L.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,v=L.offsetHeight/2+(L.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,y=l(w,v,g,_,d,"open");o+=y,m.push(y);f=t,g=((x=n[a+1]).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,_=(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,w=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,v=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,y=l(w,v,g,_,c,"other");o+=y,m.push(y)}else if(a===n.length-1){var E,R;f=t,C=t.parentElement.classList[1].replace("node_in_",""),x=(E=i.querySelector("#"+C)).querySelectorAll("."+t.parentElement.classList[4])[0],g=(R=E.querySelectorAll("."+t.parentElement.classList[4])[0]).offsetWidth/2+(R.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,_=R.offsetHeight/2+(R.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,w=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*(s.clientWidth/(s.clientWidth*h))+r,v=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*(s.clientHeight/(s.clientHeight*h))+r,y=l(w,v,g,_,d,"close");o+=y,m.push(y)}else{f=t,g=((x=n[a+1]).getBoundingClientRect().x-s.getBoundingClientRect().x)*(s.clientWidth/(s.clientWidth*h))+r,_=(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*(s.clientHeight/(s.clientHeight*h))+r,w=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*(s.clientWidth/(s.clientWidth*h))+r,v=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*(s.clientHeight/(s.clientHeight*h))+r,y=l(w,v,g,_,c,"other");o+=y,m.push(y)}}),a?m.forEach((e,n)=>{f[t].children[n].setAttributeNS(null,"d",e)}):f[t].children[0].setAttributeNS(null,"d",o)}}));const m=i.querySelectorAll("."+t);Object.keys(m).map((function(t,n){if(null===m[t].querySelector(".point")){var h=i.querySelector("#"+e),f=m[t].classList[2].replace("node_out_",""),g=i.querySelector("#"+f).querySelectorAll("."+m[t].classList[3])[0],_=g.offsetWidth/2+(g.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,w=g.offsetHeight/2+(g.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,v=(h=h.querySelectorAll("."+m[t].classList[4])[0]).offsetWidth/2+(h.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,y=h.offsetHeight/2+(h.getBoundingClientRect().y-s.getBoundingClientRect().y)*p;const n=l(_,w,v,y,o,"openclose");m[t].children[0].setAttributeNS(null,"d",n)}else{const n=m[t].querySelectorAll(".point");let o="";const h=[];n.forEach((t,a)=>{if(0===a&&n.length-1==0){var f=i.querySelector("#"+e),m=((C=t).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,g=(C.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,_=(E=f.querySelectorAll("."+t.parentElement.classList[4])[0]).offsetWidth/2+(E.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,w=E.offsetHeight/2+(E.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,v=l(m,g,_,w,d,"close");o+=v,h.push(v);f=t;var y=t.parentElement.classList[2].replace("node_out_",""),C=(L=i.querySelector("#"+y)).querySelectorAll("."+t.parentElement.classList[3])[0];m=(x=L.querySelectorAll("."+t.parentElement.classList[3])[0]).offsetWidth/2+(x.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,g=x.offsetHeight/2+(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,_=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,w=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,v=l(m,g,_,w,d,"open");o+=v,h.push(v)}else if(0===a){var x;f=t,y=t.parentElement.classList[2].replace("node_out_",""),C=(L=i.querySelector("#"+y)).querySelectorAll("."+t.parentElement.classList[3])[0],m=(x=L.querySelectorAll("."+t.parentElement.classList[3])[0]).offsetWidth/2+(x.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,g=x.offsetHeight/2+(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,_=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,w=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,v=l(m,g,_,w,d,"open");o+=v,h.push(v);f=t,_=((C=n[a+1]).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,w=(C.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,m=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,g=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,v=l(m,g,_,w,c,"other");o+=v,h.push(v)}else if(a===n.length-1){var L,E;f=t,y=t.parentElement.classList[1].replace("node_in_",""),C=(L=i.querySelector("#"+y)).querySelectorAll("."+t.parentElement.classList[4])[0],_=(E=L.querySelectorAll("."+t.parentElement.classList[4])[0]).offsetWidth/2+(E.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,w=E.offsetHeight/2+(E.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,m=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,g=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,v=l(m,g,_,w,d,"close");o+=v,h.push(v)}else{f=t,_=((C=n[a+1]).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,w=(C.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,m=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,g=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,v=l(m,g,_,w,c,"other");o+=v,h.push(v)}}),a?h.forEach((e,n)=>{m[t].children[n].setAttributeNS(null,"d",e)}):m[t].children[0].setAttributeNS(null,"d",o)}}))}dblclick(e){null!=this.connection_selected&&this.reroute&&this.createReroutePoint(this.connection_selected),"point"===e.target.classList[0]&&this.removeReroutePoint(e.target)}createReroutePoint(e){this.connection_selected.classList.remove("selected");const t=this.connection_selected.parentElement.classList[2].slice(9),n=this.connection_selected.parentElement.classList[1].slice(13),i=this.connection_selected.parentElement.classList[3],s=this.connection_selected.parentElement.classList[4];this.connection_selected=null;const o=document.createElementNS("http://www.w3.org/2000/svg","circle");o.classList.add("point");var l=this.pos_x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))-this.precanvas.getBoundingClientRect().x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom)),c=this.pos_y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))-this.precanvas.getBoundingClientRect().y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom));o.setAttributeNS(null,"cx",l),o.setAttributeNS(null,"cy",c),o.setAttributeNS(null,"r",this.reroute_width);let d=0;if(this.reroute_fix_curvature){const t=e.parentElement.querySelectorAll(".main-path").length;var a=document.createElementNS("http://www.w3.org/2000/svg","path");if(a.classList.add("main-path"),a.setAttributeNS(null,"d",""),e.parentElement.insertBefore(a,e.parentElement.children[t]),1===t)e.parentElement.appendChild(o);else{const n=Array.from(e.parentElement.children).indexOf(e);d=n,e.parentElement.insertBefore(o,e.parentElement.children[n+t+1])}}else e.parentElement.appendChild(o);const r=t.slice(5),h=this.drawflow.drawflow[this.module].data[r].outputs[i].connections.findIndex((function(e,t){return e.node===n&&e.output===s}));void 0===this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points&&(this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points=[]),this.reroute_fix_curvature?(d>0||this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points!==[]?this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points.splice(d,0,{pos_x:l,pos_y:c}):this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points.push({pos_x:l,pos_y:c}),e.parentElement.querySelectorAll(".main-path").forEach((e,t)=>{e.classList.remove("selected")})):this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points.push({pos_x:l,pos_y:c}),this.dispatch("addReroute",r),this.updateConnectionNodes(t)}removeReroutePoint(e){const t=e.parentElement.classList[2].slice(9),n=e.parentElement.classList[1].slice(13),i=e.parentElement.classList[3],s=e.parentElement.classList[4];let o=Array.from(e.parentElement.children).indexOf(e);const l=t.slice(5),c=this.drawflow.drawflow[this.module].data[l].outputs[i].connections.findIndex((function(e,t){return e.node===n&&e.output===s}));if(this.reroute_fix_curvature){const t=e.parentElement.querySelectorAll(".main-path").length;e.parentElement.children[t-1].remove(),o-=t,o<0&&(o=0)}else o--;this.drawflow.drawflow[this.module].data[l].outputs[i].connections[c].points.splice(o,1),e.remove(),this.dispatch("removeReroute",l),this.updateConnectionNodes(t)}registerNode(e,t,n=null,i=null){this.noderegister[e]={html:t,props:n,options:i}}getNodeFromId(e){var t=this.getModuleFromNodeId(e);return JSON.parse(JSON.stringify(this.drawflow.drawflow[t].data[e]))}getNodesFromName(e){var t=[];const n=this.drawflow.drawflow;return Object.keys(n).map((function(i,s){for(var o in n[i].data)n[i].data[o].name==e&&t.push(n[i].data[o].id)})),t}addNode(e,t,n,i,s,o,l,c,d=!1){if(this.useuuid)var a=this.getUuid();else a=this.nodeId;const r=document.createElement("div");r.classList.add("parent-node");const h=document.createElement("div");h.innerHTML="",h.setAttribute("id","node-"+a),h.classList.add("drawflow-node"),""!=o&&h.classList.add(...o.split(" "));const u=document.createElement("div");u.classList.add("inputs");const p=document.createElement("div");p.classList.add("outputs");const f={};for(var m=0;m<t;m++){const e=document.createElement("div");e.classList.add("input"),e.classList.add("input_"+(m+1)),f["input_"+(m+1)]={connections:[]},u.appendChild(e)}const g={};for(m=0;m<n;m++){const e=document.createElement("div");e.classList.add("output"),e.classList.add("output_"+(m+1)),g["output_"+(m+1)]={connections:[]},p.appendChild(e)}const _=document.createElement("div");if(_.classList.add("drawflow_content_node"),!1===d)_.innerHTML=c;else if(!0===d)_.appendChild(this.noderegister[c].html.cloneNode(!0));else if(3===parseInt(this.render.version)){let e=this.render.h(this.noderegister[c].html,this.noderegister[c].props,this.noderegister[c].options);e.appContext=this.parent,this.render.render(e,_)}else{let e=new this.render({parent:this.parent,render:e=>e(this.noderegister[c].html,{props:this.noderegister[c].props}),...this.noderegister[c].options}).$mount();_.appendChild(e.$el)}Object.entries(l).forEach((function(e,t){if("object"==typeof e[1])!function e(t,n,i){if(null===t)t=l[n];else t=t[n];null!==t&&Object.entries(t).forEach((function(n,s){if("object"==typeof n[1])e(t,n[0],i+"-"+n[0]);else for(var o=_.querySelectorAll("[df-"+i+"-"+n[0]+"]"),l=0;l<o.length;l++)o[l].value=n[1],o[l].isContentEditable&&(o[l].innerText=n[1])}))}(null,e[0],e[0]);else for(var n=_.querySelectorAll("[df-"+e[0]+"]"),i=0;i<n.length;i++)n[i].value=e[1],n[i].isContentEditable&&(n[i].innerText=e[1])})),h.appendChild(u),h.appendChild(_),h.appendChild(p),h.style.top=s+"px",h.style.left=i+"px",r.appendChild(h),this.precanvas.appendChild(r);var w={id:a,name:e,data:l,class:o,html:c,typenode:d,inputs:f,outputs:g,pos_x:i,pos_y:s};return this.drawflow.drawflow[this.module].data[a]=w,this.dispatch("nodeCreated",a),this.useuuid||this.nodeId++,a}addNodeImport(e,t){const n=document.createElement("div");n.classList.add("parent-node");const i=document.createElement("div");i.innerHTML="",i.setAttribute("id","node-"+e.id),i.classList.add("drawflow-node"),""!=e.class&&i.classList.add(...e.class.split(" "));const s=document.createElement("div");s.classList.add("inputs");const o=document.createElement("div");o.classList.add("outputs"),Object.keys(e.inputs).map((function(n,i){const o=document.createElement("div");o.classList.add("input"),o.classList.add(n),s.appendChild(o),Object.keys(e.inputs[n].connections).map((function(i,s){var o=document.createElementNS("http://www.w3.org/2000/svg","svg"),l=document.createElementNS("http://www.w3.org/2000/svg","path");l.classList.add("main-path"),l.setAttributeNS(null,"d",""),o.classList.add("connection"),o.classList.add("node_in_node-"+e.id),o.classList.add("node_out_node-"+e.inputs[n].connections[i].node),o.classList.add(e.inputs[n].connections[i].input),o.classList.add(n),o.appendChild(l),t.appendChild(o)}))}));for(var l=0;l<Object.keys(e.outputs).length;l++){const e=document.createElement("div");e.classList.add("output"),e.classList.add("output_"+(l+1)),o.appendChild(e)}const c=document.createElement("div");if(c.classList.add("drawflow_content_node"),!1===e.typenode)c.innerHTML=e.html;else if(!0===e.typenode)c.appendChild(this.noderegister[e.html].html.cloneNode(!0));else if(3===parseInt(this.render.version)){let t=this.render.h(this.noderegister[e.html].html,this.noderegister[e.html].props,this.noderegister[e.html].options);t.appContext=this.parent,this.render.render(t,c)}else{let t=new this.render({parent:this.parent,render:t=>t(this.noderegister[e.html].html,{props:this.noderegister[e.html].props}),...this.noderegister[e.html].options}).$mount();c.appendChild(t.$el)}Object.entries(e.data).forEach((function(t,n){if("object"==typeof t[1])!function t(n,i,s){if(null===n)n=e.data[i];else n=n[i];null!==n&&Object.entries(n).forEach((function(e,i){if("object"==typeof e[1])t(n,e[0],s+"-"+e[0]);else for(var o=c.querySelectorAll("[df-"+s+"-"+e[0]+"]"),l=0;l<o.length;l++)o[l].value=e[1],o[l].isContentEditable&&(o[l].innerText=e[1])}))}(null,t[0],t[0]);else for(var i=c.querySelectorAll("[df-"+t[0]+"]"),s=0;s<i.length;s++)i[s].value=t[1],i[s].isContentEditable&&(i[s].innerText=t[1])})),i.appendChild(s),i.appendChild(c),i.appendChild(o),i.style.top=e.pos_y+"px",i.style.left=e.pos_x+"px",n.appendChild(i),this.precanvas.appendChild(n)}addRerouteImport(e){const t=this.reroute_width,n=this.reroute_fix_curvature,i=this.container;Object.keys(e.outputs).map((function(s,o){Object.keys(e.outputs[s].connections).map((function(o,l){const c=e.outputs[s].connections[o].points;void 0!==c&&c.forEach((l,d)=>{const a=e.outputs[s].connections[o].node,r=e.outputs[s].connections[o].output,h=i.querySelector(".connection.node_in_node-"+a+".node_out_node-"+e.id+"."+s+"."+r);if(n&&0===d)for(var u=0;u<c.length;u++){var p=document.createElementNS("http://www.w3.org/2000/svg","path");p.classList.add("main-path"),p.setAttributeNS(null,"d",""),h.appendChild(p)}const f=document.createElementNS("http://www.w3.org/2000/svg","circle");f.classList.add("point");var m=l.pos_x,g=l.pos_y;f.setAttributeNS(null,"cx",m),f.setAttributeNS(null,"cy",g),f.setAttributeNS(null,"r",t),h.appendChild(f)})}))}))}updateNodeValue(e){for(var t=e.target.attributes,n=0;n<t.length;n++)if(t[n].nodeName.startsWith("df-")){for(var i=t[n].nodeName.slice(3).split("-"),s=this.drawflow.drawflow[this.module].data[e.target.closest(".drawflow_content_node").parentElement.id.slice(5)].data,o=0;o<i.length-1;o+=1)null==s[i[o]]&&(s[i[o]]={}),s=s[i[o]];s[i[i.length-1]]=e.target.value,e.target.isContentEditable&&(s[i[i.length-1]]=e.target.innerText),this.dispatch("nodeDataChanged",e.target.closest(".drawflow_content_node").parentElement.id.slice(5))}}updateNodeDataFromId(e,t){var n=this.getModuleFromNodeId(e);if(this.drawflow.drawflow[n].data[e].data=t,this.module===n){const n=this.container.querySelector("#node-"+e);Object.entries(t).forEach((function(e,i){if("object"==typeof e[1])!function e(i,s,o){if(null===i)i=t[s];else i=i[s];null!==i&&Object.entries(i).forEach((function(t,s){if("object"==typeof t[1])e(i,t[0],o+"-"+t[0]);else for(var l=n.querySelectorAll("[df-"+o+"-"+t[0]+"]"),c=0;c<l.length;c++)l[c].value=t[1],l[c].isContentEditable&&(l[c].innerText=t[1])}))}(null,e[0],e[0]);else for(var s=n.querySelectorAll("[df-"+e[0]+"]"),o=0;o<s.length;o++)s[o].value=e[1],s[o].isContentEditable&&(s[o].innerText=e[1])}))}}addNodeInput(e){var t=this.getModuleFromNodeId(e);const n=this.getNodeFromId(e),i=Object.keys(n.inputs).length;if(this.module===t){const t=document.createElement("div");t.classList.add("input"),t.classList.add("input_"+(i+1)),this.container.querySelector("#node-"+e+" .inputs").appendChild(t),this.updateConnectionNodes("node-"+e)}this.drawflow.drawflow[t].data[e].inputs["input_"+(i+1)]={connections:[]}}addNodeOutput(e){var t=this.getModuleFromNodeId(e);const n=this.getNodeFromId(e),i=Object.keys(n.outputs).length;if(this.module===t){const t=document.createElement("div");t.classList.add("output"),t.classList.add("output_"+(i+1)),this.container.querySelector("#node-"+e+" .outputs").appendChild(t),this.updateConnectionNodes("node-"+e)}this.drawflow.drawflow[t].data[e].outputs["output_"+(i+1)]={connections:[]}}removeNodeInput(e,t){var n=this.getModuleFromNodeId(e);const i=this.getNodeFromId(e);this.module===n&&this.container.querySelector("#node-"+e+" .inputs .input."+t).remove();const s=[];Object.keys(i.inputs[t].connections).map((function(n,o){const l=i.inputs[t].connections[o].node,c=i.inputs[t].connections[o].input;s.push({id_output:l,id:e,output_class:c,input_class:t})})),s.forEach((e,t)=>{this.removeSingleConnection(e.id_output,e.id,e.output_class,e.input_class)}),delete this.drawflow.drawflow[n].data[e].inputs[t];const o=[],l=this.drawflow.drawflow[n].data[e].inputs;Object.keys(l).map((function(e,t){o.push(l[e])})),this.drawflow.drawflow[n].data[e].inputs={};const c=t.slice(6);let d=[];if(o.forEach((t,i)=>{t.connections.forEach((e,t)=>{d.push(e)}),this.drawflow.drawflow[n].data[e].inputs["input_"+(i+1)]=t}),d=new Set(d.map(e=>JSON.stringify(e))),d=Array.from(d).map(e=>JSON.parse(e)),this.module===n){this.container.querySelectorAll("#node-"+e+" .inputs .input").forEach((e,t)=>{const n=e.classList[1].slice(6);parseInt(c)<parseInt(n)&&(e.classList.remove("input_"+n),e.classList.add("input_"+(n-1)))})}d.forEach((t,i)=>{this.drawflow.drawflow[n].data[t.node].outputs[t.input].connections.forEach((i,s)=>{if(i.node==e){const o=i.output.slice(6);if(parseInt(c)<parseInt(o)){if(this.module===n){const n=this.container.querySelector(".connection.node_in_node-"+e+".node_out_node-"+t.node+"."+t.input+".input_"+o);n.classList.remove("input_"+o),n.classList.add("input_"+(o-1))}i.points?this.drawflow.drawflow[n].data[t.node].outputs[t.input].connections[s]={node:i.node,output:"input_"+(o-1),points:i.points}:this.drawflow.drawflow[n].data[t.node].outputs[t.input].connections[s]={node:i.node,output:"input_"+(o-1)}}}})}),this.updateConnectionNodes("node-"+e)}removeNodeOutput(e,t){var n=this.getModuleFromNodeId(e);const i=this.getNodeFromId(e);this.module===n&&this.container.querySelector("#node-"+e+" .outputs .output."+t).remove();const s=[];Object.keys(i.outputs[t].connections).map((function(n,o){const l=i.outputs[t].connections[o].node,c=i.outputs[t].connections[o].output;s.push({id:e,id_input:l,output_class:t,input_class:c})})),s.forEach((e,t)=>{this.removeSingleConnection(e.id,e.id_input,e.output_class,e.input_class)}),delete this.drawflow.drawflow[n].data[e].outputs[t];const o=[],l=this.drawflow.drawflow[n].data[e].outputs;Object.keys(l).map((function(e,t){o.push(l[e])})),this.drawflow.drawflow[n].data[e].outputs={};const c=t.slice(7);let d=[];if(o.forEach((t,i)=>{t.connections.forEach((e,t)=>{d.push({node:e.node,output:e.output})}),this.drawflow.drawflow[n].data[e].outputs["output_"+(i+1)]=t}),d=new Set(d.map(e=>JSON.stringify(e))),d=Array.from(d).map(e=>JSON.parse(e)),this.module===n){this.container.querySelectorAll("#node-"+e+" .outputs .output").forEach((e,t)=>{const n=e.classList[1].slice(7);parseInt(c)<parseInt(n)&&(e.classList.remove("output_"+n),e.classList.add("output_"+(n-1)))})}d.forEach((t,i)=>{this.drawflow.drawflow[n].data[t.node].inputs[t.output].connections.forEach((i,s)=>{if(i.node==e){const o=i.input.slice(7);if(parseInt(c)<parseInt(o)){if(this.module===n){const n=this.container.querySelector(".connection.node_in_node-"+t.node+".node_out_node-"+e+".output_"+o+"."+t.output);n.classList.remove("output_"+o),n.classList.remove(t.output),n.classList.add("output_"+(o-1)),n.classList.add(t.output)}i.points?this.drawflow.drawflow[n].data[t.node].inputs[t.output].connections[s]={node:i.node,input:"output_"+(o-1),points:i.points}:this.drawflow.drawflow[n].data[t.node].inputs[t.output].connections[s]={node:i.node,input:"output_"+(o-1)}}}})}),this.updateConnectionNodes("node-"+e)}removeNodeId(e){this.removeConnectionNodeId(e);var t=this.getModuleFromNodeId(e.slice(5));this.module===t&&this.container.querySelector("#"+e).remove(),delete this.drawflow.drawflow[t].data[e.slice(5)],this.dispatch("nodeRemoved",e.slice(5))}removeConnection(){if(null!=this.connection_selected){var e=this.connection_selected.parentElement.classList;this.connection_selected.parentElement.remove();var t=this.drawflow.drawflow[this.module].data[e[2].slice(14)].outputs[e[3]].connections.findIndex((function(t,n){return t.node===e[1].slice(13)&&t.output===e[4]}));this.drawflow.drawflow[this.module].data[e[2].slice(14)].outputs[e[3]].connections.splice(t,1);var n=this.drawflow.drawflow[this.module].data[e[1].slice(13)].inputs[e[4]].connections.findIndex((function(t,n){return t.node===e[2].slice(14)&&t.input===e[3]}));this.drawflow.drawflow[this.module].data[e[1].slice(13)].inputs[e[4]].connections.splice(n,1),this.dispatch("connectionRemoved",{output_id:e[2].slice(14),input_id:e[1].slice(13),output_class:e[3],input_class:e[4]}),this.connection_selected=null}}removeSingleConnection(e,t,n,i){var s=this.getModuleFromNodeId(e);if(s===this.getModuleFromNodeId(t)){if(this.drawflow.drawflow[s].data[e].outputs[n].connections.findIndex((function(e,n){return e.node==t&&e.output===i}))>-1){this.module===s&&this.container.querySelector(".connection.node_in_node-"+t+".node_out_node-"+e+"."+n+"."+i).remove();var o=this.drawflow.drawflow[s].data[e].outputs[n].connections.findIndex((function(e,n){return e.node==t&&e.output===i}));this.drawflow.drawflow[s].data[e].outputs[n].connections.splice(o,1);var l=this.drawflow.drawflow[s].data[t].inputs[i].connections.findIndex((function(t,i){return t.node==e&&t.input===n}));return this.drawflow.drawflow[s].data[t].inputs[i].connections.splice(l,1),this.dispatch("connectionRemoved",{output_id:e,input_id:t,output_class:n,input_class:i}),!0}return!1}return!1}removeConnectionNodeId(e){const t="node_in_"+e,n="node_out_"+e,i=this.container.querySelectorAll("."+n);for(var s=i.length-1;s>=0;s--){var o=i[s].classList,l=this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.findIndex((function(e,t){return e.node===o[2].slice(14)&&e.input===o[3]}));this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.splice(l,1);var c=this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.findIndex((function(e,t){return e.node===o[1].slice(13)&&e.output===o[4]}));this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.splice(c,1),i[s].remove(),this.dispatch("connectionRemoved",{output_id:o[2].slice(14),input_id:o[1].slice(13),output_class:o[3],input_class:o[4]})}const d=this.container.querySelectorAll("."+t);for(s=d.length-1;s>=0;s--){o=d[s].classList,c=this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.findIndex((function(e,t){return e.node===o[1].slice(13)&&e.output===o[4]}));this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.splice(c,1);l=this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.findIndex((function(e,t){return e.node===o[2].slice(14)&&e.input===o[3]}));this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.splice(l,1),d[s].remove(),this.dispatch("connectionRemoved",{output_id:o[2].slice(14),input_id:o[1].slice(13),output_class:o[3],input_class:o[4]})}}getModuleFromNodeId(e){var t;const n=this.drawflow.drawflow;return Object.keys(n).map((function(i,s){Object.keys(n[i].data).map((function(n,s){n==e&&(t=i)}))})),t}addModule(e){this.drawflow.drawflow[e]={data:{}},this.dispatch("moduleCreated",e)}changeModule(e){this.dispatch("moduleChanged",e),this.module=e,this.precanvas.innerHTML="",this.canvas_x=0,this.canvas_y=0,this.pos_x=0,this.pos_y=0,this.mouse_x=0,this.mouse_y=0,this.zoom=1,this.zoom_last_value=1,this.precanvas.style.transform="",this.import(this.drawflow,!1)}removeModule(e){this.module===e&&this.changeModule("Home"),delete this.drawflow.drawflow[e],this.dispatch("moduleRemoved",e)}clearModuleSelected(){this.precanvas.innerHTML="",this.drawflow.drawflow[this.module]={data:{}}}clear(){this.precanvas.innerHTML="",this.drawflow={drawflow:{Home:{data:{}}}}}export(){const e=JSON.parse(JSON.stringify(this.drawflow));return this.dispatch("export",e),e}import(e,t=!0){this.clear(),this.drawflow=JSON.parse(JSON.stringify(e)),this.load(),t&&this.dispatch("import","import")}on(e,t){return"function"!=typeof t?(console.error("The listener callback must be a function, the given type is "+typeof t),!1):"string"!=typeof e?(console.error("The event name must be a string, the given type is "+typeof e),!1):(void 0===this.events[e]&&(this.events[e]={listeners:[]}),void this.events[e].listeners.push(t))}removeListener(e,t){if(!this.events[e])return!1;const n=this.events[e].listeners,i=n.indexOf(t);i>-1&&n.splice(i,1)}dispatch(e,t){if(void 0===this.events[e])return!1;this.events[e].listeners.forEach(e=>{e(t)})}getUuid(){for(var e=[],t=0;t<36;t++)e[t]="0123456789abcdef".substr(Math.floor(16*Math.random()),1);return e[14]="4",e[19]="0123456789abcdef".substr(3&e[19]|8,1),e[8]=e[13]=e[18]=e[23]="-",e.join("")}}}]).default}));
|
package/dist/config.d.ts
CHANGED
|
@@ -59,6 +59,15 @@ export declare const BUDGET: {
|
|
|
59
59
|
summarization: undefined;
|
|
60
60
|
reflection: undefined;
|
|
61
61
|
};
|
|
62
|
+
export declare const MEMORY_JANITOR: {
|
|
63
|
+
consolidatedExpireDays: number;
|
|
64
|
+
consolidatedSalienceFloor: number;
|
|
65
|
+
softDeleteGraceDays: number;
|
|
66
|
+
auxRetentionDays: number;
|
|
67
|
+
extractionsMaxRows: number;
|
|
68
|
+
vacuumIntervalDays: number;
|
|
69
|
+
vacuumIdleSeconds: number;
|
|
70
|
+
};
|
|
62
71
|
export declare const TASK_BUDGET_TOKENS: {
|
|
63
72
|
heartbeat: number | undefined;
|
|
64
73
|
cronT1: number | undefined;
|
|
@@ -159,6 +168,8 @@ export declare const VAULT_MIGRATIONS_STATE: string;
|
|
|
159
168
|
export declare const PLANS_DIR: string;
|
|
160
169
|
export declare const ADVISOR_LOG_PATH: string;
|
|
161
170
|
export declare const REMOTE_ACCESS_CONFIG: string;
|
|
171
|
+
/** Persistent session store for the dashboard /auth flow (mode 0600 enforced on write). */
|
|
172
|
+
export declare const SESSIONS_FILE: string;
|
|
162
173
|
export declare const STAGING_DIR: string;
|
|
163
174
|
export declare const ALLOW_SOURCE_EDITS: boolean;
|
|
164
175
|
export declare const ADVISOR_RULES_LOADER: 'off' | 'shadow' | 'primary';
|
package/dist/config.js
CHANGED
|
@@ -195,6 +195,20 @@ export const BUDGET = {
|
|
|
195
195
|
summarization: undefined,
|
|
196
196
|
reflection: undefined,
|
|
197
197
|
};
|
|
198
|
+
// ── Memory janitor (bounded-growth maintenance) ─────────────────────
|
|
199
|
+
// Two-phase delete: consolidated chunks with low salience and no recent
|
|
200
|
+
// access get soft-deleted, then physically deleted after a grace period.
|
|
201
|
+
// Aux tables (recall_traces, access_log, outcomes) cap at a rolling window.
|
|
202
|
+
// VACUUM runs at most once per N days, only when daemon is idle.
|
|
203
|
+
export const MEMORY_JANITOR = {
|
|
204
|
+
consolidatedExpireDays: getEnvOrJsonNumber('MEMORY_CONSOLIDATED_EXPIRE_DAYS', undefined, 60),
|
|
205
|
+
consolidatedSalienceFloor: getEnvOrJsonNumber('MEMORY_CONSOLIDATED_SALIENCE_FLOOR', undefined, 0.2),
|
|
206
|
+
softDeleteGraceDays: getEnvOrJsonNumber('MEMORY_SOFT_DELETE_GRACE_DAYS', undefined, 14),
|
|
207
|
+
auxRetentionDays: getEnvOrJsonNumber('MEMORY_AUX_RETENTION_DAYS', undefined, 30),
|
|
208
|
+
extractionsMaxRows: getEnvOrJsonNumber('MEMORY_EXTRACTIONS_MAX_ROWS', undefined, 50000),
|
|
209
|
+
vacuumIntervalDays: getEnvOrJsonNumber('MEMORY_VACUUM_INTERVAL_DAYS', undefined, 7),
|
|
210
|
+
vacuumIdleSeconds: getEnvOrJsonNumber('MEMORY_VACUUM_IDLE_SECONDS', undefined, 300),
|
|
211
|
+
};
|
|
198
212
|
// ── Task budget caps (tokens per query) ──────────────────────────────
|
|
199
213
|
// Passed to the Claude Agent SDK as `taskBudget: { total }`. The model is
|
|
200
214
|
// told its remaining token budget so it can pace tool use and wrap up
|
|
@@ -383,6 +397,8 @@ export const PLANS_DIR = path.join(BASE_DIR, 'plans');
|
|
|
383
397
|
export const ADVISOR_LOG_PATH = path.join(BASE_DIR, 'cron', 'advisor-decisions.jsonl');
|
|
384
398
|
// ── Remote Access ──────────────────────────────────────────────────
|
|
385
399
|
export const REMOTE_ACCESS_CONFIG = path.join(BASE_DIR, 'remote-access.json');
|
|
400
|
+
/** Persistent session store for the dashboard /auth flow (mode 0600 enforced on write). */
|
|
401
|
+
export const SESSIONS_FILE = path.join(BASE_DIR, '.sessions.json');
|
|
386
402
|
// ── Source Self-Edit Staging ─────────────────────────────────────────
|
|
387
403
|
export const STAGING_DIR = path.join(BASE_DIR, 'staging');
|
|
388
404
|
// Source self-editing is deprecated. The data-driven path (advisor rules,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builder dry-run.
|
|
3
|
+
*
|
|
4
|
+
* Walks a workflow's step DAG in topological order and produces a
|
|
5
|
+
* human-readable description of what each step *would* do, without
|
|
6
|
+
* executing anything. Crucial for long-running jobs (multi-hour
|
|
7
|
+
* outreach batches, brain ingestion runs) where the user wants to
|
|
8
|
+
* preview changes safely before scheduling a real run.
|
|
9
|
+
*/
|
|
10
|
+
import type { WorkflowDefinition, WorkflowStepKind } from '../../types.js';
|
|
11
|
+
import { validateWorkflow } from './validation.js';
|
|
12
|
+
export interface DryRunStep {
|
|
13
|
+
stepId: string;
|
|
14
|
+
kind: WorkflowStepKind;
|
|
15
|
+
wave: number;
|
|
16
|
+
description: string;
|
|
17
|
+
warnings: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface DryRunResult {
|
|
20
|
+
ok: boolean;
|
|
21
|
+
validationIssues: ReturnType<typeof validateWorkflow>['issues'];
|
|
22
|
+
steps: DryRunStep[];
|
|
23
|
+
estimatedTokens?: {
|
|
24
|
+
promptSteps: number;
|
|
25
|
+
perPromptEstimate: number;
|
|
26
|
+
total: number;
|
|
27
|
+
};
|
|
28
|
+
notes: string[];
|
|
29
|
+
}
|
|
30
|
+
export declare function dryRunWorkflow(wf: WorkflowDefinition): DryRunResult;
|
|
31
|
+
//# sourceMappingURL=dry-run.d.ts.map
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builder dry-run.
|
|
3
|
+
*
|
|
4
|
+
* Walks a workflow's step DAG in topological order and produces a
|
|
5
|
+
* human-readable description of what each step *would* do, without
|
|
6
|
+
* executing anything. Crucial for long-running jobs (multi-hour
|
|
7
|
+
* outreach batches, brain ingestion runs) where the user wants to
|
|
8
|
+
* preview changes safely before scheduling a real run.
|
|
9
|
+
*/
|
|
10
|
+
import { validateWorkflow } from './validation.js';
|
|
11
|
+
export function dryRunWorkflow(wf) {
|
|
12
|
+
const validation = validateWorkflow(wf);
|
|
13
|
+
const result = {
|
|
14
|
+
ok: validation.ok,
|
|
15
|
+
validationIssues: validation.issues,
|
|
16
|
+
steps: [],
|
|
17
|
+
notes: [],
|
|
18
|
+
};
|
|
19
|
+
if (!validation.ok) {
|
|
20
|
+
result.notes.push('Validation failed — fix errors before scheduling. Steps below are descriptive only.');
|
|
21
|
+
}
|
|
22
|
+
const waveOf = computeWaves(wf.steps);
|
|
23
|
+
let promptSteps = 0;
|
|
24
|
+
for (const step of wf.steps) {
|
|
25
|
+
const kind = step.kind ?? 'prompt';
|
|
26
|
+
if (kind === 'prompt')
|
|
27
|
+
promptSteps++;
|
|
28
|
+
result.steps.push({
|
|
29
|
+
stepId: step.id,
|
|
30
|
+
kind,
|
|
31
|
+
wave: waveOf[step.id] ?? 0,
|
|
32
|
+
description: describeStep(step),
|
|
33
|
+
warnings: stepWarnings(step),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (promptSteps > 0) {
|
|
37
|
+
const perPromptEstimate = 1500; // very rough heuristic; real cost depends on prior step outputs
|
|
38
|
+
result.estimatedTokens = {
|
|
39
|
+
promptSteps,
|
|
40
|
+
perPromptEstimate,
|
|
41
|
+
total: promptSteps * perPromptEstimate,
|
|
42
|
+
};
|
|
43
|
+
result.notes.push(`Cost estimate is rough — actual usage depends on prior step outputs and tool calls.`);
|
|
44
|
+
}
|
|
45
|
+
if (wf.trigger.schedule) {
|
|
46
|
+
result.notes.push(`Trigger: cron "${wf.trigger.schedule}". This describes one execution.`);
|
|
47
|
+
}
|
|
48
|
+
else if (wf.trigger.manual) {
|
|
49
|
+
result.notes.push('Trigger: manual. Workflow runs only when invoked directly.');
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
function describeStep(step) {
|
|
54
|
+
const kind = step.kind ?? 'prompt';
|
|
55
|
+
const deps = step.dependsOn.length ? ` (after: ${step.dependsOn.join(', ')})` : '';
|
|
56
|
+
switch (kind) {
|
|
57
|
+
case 'prompt':
|
|
58
|
+
return `Prompt step "${step.id}"${deps}: would send a prompt to the agent (model: ${step.model ?? 'default'}, maxTurns: ${step.maxTurns}). Prompt preview: ${truncate(step.prompt, 160)}`;
|
|
59
|
+
case 'mcp':
|
|
60
|
+
if (!step.mcp)
|
|
61
|
+
return `MCP step "${step.id}"${deps}: misconfigured (no mcp config)`;
|
|
62
|
+
return `MCP step "${step.id}"${deps}: would call ${step.mcp.server}.${step.mcp.tool}${step.mcp.inputs ? ` with inputs ${JSON.stringify(step.mcp.inputs)}` : ' (no inputs)'}`;
|
|
63
|
+
case 'channel':
|
|
64
|
+
if (!step.channel)
|
|
65
|
+
return `Channel step "${step.id}"${deps}: misconfigured`;
|
|
66
|
+
return `Channel step "${step.id}"${deps}: would send to ${step.channel.channel} → ${step.channel.target}. Content preview: ${truncate(step.channel.content, 120)}`;
|
|
67
|
+
case 'transform':
|
|
68
|
+
if (!step.transform)
|
|
69
|
+
return `Transform step "${step.id}"${deps}: misconfigured`;
|
|
70
|
+
return `Transform step "${step.id}"${deps}: would evaluate ${truncate(step.transform.expression, 160)}`;
|
|
71
|
+
case 'conditional':
|
|
72
|
+
if (!step.conditional)
|
|
73
|
+
return `Conditional step "${step.id}"${deps}: misconfigured`;
|
|
74
|
+
return `Conditional step "${step.id}"${deps}: branches on ${truncate(step.conditional.condition, 120)}. True → ${(step.conditional.trueNext ?? []).join(',') || '(none)'}, False → ${(step.conditional.falseNext ?? []).join(',') || '(none)'}`;
|
|
75
|
+
case 'loop':
|
|
76
|
+
if (!step.loop)
|
|
77
|
+
return `Loop step "${step.id}"${deps}: misconfigured`;
|
|
78
|
+
return `Loop step "${step.id}"${deps}: iterates over ${truncate(step.loop.items, 80)}, body: ${step.loop.bodyStepIds.join(', ')}`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function stepWarnings(step) {
|
|
82
|
+
const warnings = [];
|
|
83
|
+
const kind = step.kind ?? 'prompt';
|
|
84
|
+
if (kind === 'channel' && step.channel) {
|
|
85
|
+
if (step.channel.channel === 'email' && !step.channel.target.includes('@')) {
|
|
86
|
+
warnings.push('Email target does not look like an email address');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (kind === 'mcp' && step.mcp) {
|
|
90
|
+
if (/(create|delete|update|push|send|post|drop)/i.test(step.mcp.tool)) {
|
|
91
|
+
warnings.push('Looks like a write/destructive MCP tool — confirm before running for real');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (kind === 'prompt' && step.prompt && step.prompt.length > 5000) {
|
|
95
|
+
warnings.push('Prompt is very long — may exceed reasonable cost per run');
|
|
96
|
+
}
|
|
97
|
+
if (kind === 'prompt' && step.maxTurns > 60) {
|
|
98
|
+
warnings.push('maxTurns is high; this step may run for many minutes');
|
|
99
|
+
}
|
|
100
|
+
return warnings;
|
|
101
|
+
}
|
|
102
|
+
function truncate(s, n) {
|
|
103
|
+
if (!s)
|
|
104
|
+
return '';
|
|
105
|
+
if (s.length <= n)
|
|
106
|
+
return s;
|
|
107
|
+
return s.slice(0, n) + '…';
|
|
108
|
+
}
|
|
109
|
+
/** Topological wave numbers — same logic as serializer's, kept local to avoid circular import. */
|
|
110
|
+
function computeWaves(steps) {
|
|
111
|
+
const wave = {};
|
|
112
|
+
const ids = new Set(steps.map(s => s.id));
|
|
113
|
+
const remaining = new Set(steps.map(s => s.id));
|
|
114
|
+
let current = 0;
|
|
115
|
+
const maxIter = steps.length + 1;
|
|
116
|
+
for (let iter = 0; iter < maxIter && remaining.size > 0; iter++) {
|
|
117
|
+
const ready = [];
|
|
118
|
+
for (const s of steps) {
|
|
119
|
+
if (!remaining.has(s.id))
|
|
120
|
+
continue;
|
|
121
|
+
const depsResolved = s.dependsOn.every(d => !ids.has(d) || (wave[d] != null && wave[d] < current + 1));
|
|
122
|
+
if (depsResolved)
|
|
123
|
+
ready.push(s.id);
|
|
124
|
+
}
|
|
125
|
+
if (ready.length === 0) {
|
|
126
|
+
for (const id of remaining)
|
|
127
|
+
wave[id] = current;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
for (const id of ready) {
|
|
131
|
+
wave[id] = current;
|
|
132
|
+
remaining.delete(id);
|
|
133
|
+
}
|
|
134
|
+
current++;
|
|
135
|
+
}
|
|
136
|
+
return wave;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=dry-run.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builder event bus.
|
|
3
|
+
*
|
|
4
|
+
* Decouples MCP tool handlers (which mutate workflows) from the dashboard
|
|
5
|
+
* WebSocket server (which streams updates to open builder tabs). Tools
|
|
6
|
+
* call `emitBuilderEvent(...)` after a successful write; the WS server
|
|
7
|
+
* subscribes and forwards to clients in the matching workflow room.
|
|
8
|
+
*
|
|
9
|
+
* Test-side / runs (Phase 2+) will reuse the same bus to stream per-step
|
|
10
|
+
* status during long-running test/dry-run flows.
|
|
11
|
+
*/
|
|
12
|
+
export type BuilderEventType = 'workflow:created' | 'workflow:updated' | 'workflow:deleted' | 'workflow:renamed' | 'workflow:enabled-changed' | 'workflow:patched' | 'run:started' | 'run:step-status' | 'run:step-output' | 'run:completed' | 'run:cancelled' | 'run:error';
|
|
13
|
+
export interface BuilderEvent {
|
|
14
|
+
type: BuilderEventType;
|
|
15
|
+
workflowId: string;
|
|
16
|
+
runId?: string;
|
|
17
|
+
payload?: unknown;
|
|
18
|
+
ts: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function emitBuilderEvent(event: Omit<BuilderEvent, 'ts'>): void;
|
|
21
|
+
export declare function onBuilderEvent(workflowId: string, listener: (e: BuilderEvent) => void): () => void;
|
|
22
|
+
export declare function onAnyBuilderEvent(listener: (e: BuilderEvent) => void): () => void;
|
|
23
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builder event bus.
|
|
3
|
+
*
|
|
4
|
+
* Decouples MCP tool handlers (which mutate workflows) from the dashboard
|
|
5
|
+
* WebSocket server (which streams updates to open builder tabs). Tools
|
|
6
|
+
* call `emitBuilderEvent(...)` after a successful write; the WS server
|
|
7
|
+
* subscribes and forwards to clients in the matching workflow room.
|
|
8
|
+
*
|
|
9
|
+
* Test-side / runs (Phase 2+) will reuse the same bus to stream per-step
|
|
10
|
+
* status during long-running test/dry-run flows.
|
|
11
|
+
*/
|
|
12
|
+
import { EventEmitter } from 'node:events';
|
|
13
|
+
const bus = new EventEmitter();
|
|
14
|
+
bus.setMaxListeners(50); // allow many open builder tabs simultaneously
|
|
15
|
+
export function emitBuilderEvent(event) {
|
|
16
|
+
const full = { ...event, ts: new Date().toISOString() };
|
|
17
|
+
bus.emit(event.workflowId, full);
|
|
18
|
+
bus.emit('*', full);
|
|
19
|
+
}
|
|
20
|
+
export function onBuilderEvent(workflowId, listener) {
|
|
21
|
+
bus.on(workflowId, listener);
|
|
22
|
+
return () => bus.off(workflowId, listener);
|
|
23
|
+
}
|
|
24
|
+
export function onAnyBuilderEvent(listener) {
|
|
25
|
+
bus.on('*', listener);
|
|
26
|
+
return () => bus.off('*', listener);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP invoke handler for the Builder runner.
|
|
3
|
+
*
|
|
4
|
+
* Spawns and pools MCP clients keyed by server name, then routes
|
|
5
|
+
* `runner.executeMcpStep` calls through `client.callTool(...)`.
|
|
6
|
+
*
|
|
7
|
+
* Designed to be wired into the daemon at startup via
|
|
8
|
+
* `runner.registerMcpInvokeHandler(...)`. When this module is loaded
|
|
9
|
+
* but the registration call hasn't happened yet, the runner falls back
|
|
10
|
+
* to its mock-stub behavior.
|
|
11
|
+
*
|
|
12
|
+
* Pooling is per-process: each server gets one stdio client that lives
|
|
13
|
+
* until the daemon shuts down. Idle clients are torn down after
|
|
14
|
+
* IDLE_TIMEOUT_MS to free resources, then re-spawned on demand.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Wire the handler into the runner. Idempotent — safe to call from any
|
|
18
|
+
* daemon entry path.
|
|
19
|
+
*/
|
|
20
|
+
export declare function installBuilderMcpHandler(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Tear down all pooled clients. Called from daemon graceful shutdown.
|
|
23
|
+
*/
|
|
24
|
+
export declare function shutdownBuilderMcpHandler(): Promise<void>;
|
|
25
|
+
//# sourceMappingURL=mcp-invoke.d.ts.map
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP invoke handler for the Builder runner.
|
|
3
|
+
*
|
|
4
|
+
* Spawns and pools MCP clients keyed by server name, then routes
|
|
5
|
+
* `runner.executeMcpStep` calls through `client.callTool(...)`.
|
|
6
|
+
*
|
|
7
|
+
* Designed to be wired into the daemon at startup via
|
|
8
|
+
* `runner.registerMcpInvokeHandler(...)`. When this module is loaded
|
|
9
|
+
* but the registration call hasn't happened yet, the runner falls back
|
|
10
|
+
* to its mock-stub behavior.
|
|
11
|
+
*
|
|
12
|
+
* Pooling is per-process: each server gets one stdio client that lives
|
|
13
|
+
* until the daemon shuts down. Idle clients are torn down after
|
|
14
|
+
* IDLE_TIMEOUT_MS to free resources, then re-spawned on demand.
|
|
15
|
+
*/
|
|
16
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
17
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
18
|
+
import { discoverMcpServers } from '../../agent/mcp-bridge.js';
|
|
19
|
+
import { logger } from '../../tools/shared.js';
|
|
20
|
+
import { registerMcpInvokeHandler } from './runner.js';
|
|
21
|
+
const PER_CALL_TIMEOUT_MS = 30_000;
|
|
22
|
+
const IDLE_TIMEOUT_MS = 5 * 60_000;
|
|
23
|
+
const pool = new Map();
|
|
24
|
+
async function getOrSpawnClient(name) {
|
|
25
|
+
const existing = pool.get(name);
|
|
26
|
+
if (existing && !existing.closing) {
|
|
27
|
+
existing.lastUsedAt = Date.now();
|
|
28
|
+
rescheduleIdleTimer(existing);
|
|
29
|
+
return existing;
|
|
30
|
+
}
|
|
31
|
+
const servers = discoverMcpServers();
|
|
32
|
+
const cfg = servers.find(s => s.name === name);
|
|
33
|
+
if (!cfg || !cfg.enabled)
|
|
34
|
+
return null;
|
|
35
|
+
if (cfg.type !== 'stdio' || !cfg.command) {
|
|
36
|
+
// HTTP/SSE servers aren't pooled here — fall back to mock for now.
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
let transport = null;
|
|
40
|
+
let client = null;
|
|
41
|
+
try {
|
|
42
|
+
transport = new StdioClientTransport({
|
|
43
|
+
command: cfg.command,
|
|
44
|
+
args: cfg.args ?? [],
|
|
45
|
+
env: { ...process.env, ...(cfg.env ?? {}) },
|
|
46
|
+
stderr: 'ignore',
|
|
47
|
+
});
|
|
48
|
+
client = new Client({ name: 'clementine-builder-runner', version: '1.0.0' }, { capabilities: {} });
|
|
49
|
+
await client.connect(transport);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
logger.warn({ err, server: name }, 'Builder MCP client spawn failed');
|
|
53
|
+
try {
|
|
54
|
+
await client?.close();
|
|
55
|
+
}
|
|
56
|
+
catch { /* */ }
|
|
57
|
+
try {
|
|
58
|
+
await transport?.close();
|
|
59
|
+
}
|
|
60
|
+
catch { /* */ }
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const pooled = {
|
|
64
|
+
name,
|
|
65
|
+
client,
|
|
66
|
+
transport,
|
|
67
|
+
lastUsedAt: Date.now(),
|
|
68
|
+
closing: false,
|
|
69
|
+
};
|
|
70
|
+
rescheduleIdleTimer(pooled);
|
|
71
|
+
pool.set(name, pooled);
|
|
72
|
+
return pooled;
|
|
73
|
+
}
|
|
74
|
+
function rescheduleIdleTimer(p) {
|
|
75
|
+
if (p.idleTimer)
|
|
76
|
+
clearTimeout(p.idleTimer);
|
|
77
|
+
p.idleTimer = setTimeout(() => { void closeClient(p.name); }, IDLE_TIMEOUT_MS);
|
|
78
|
+
}
|
|
79
|
+
async function closeClient(name) {
|
|
80
|
+
const p = pool.get(name);
|
|
81
|
+
if (!p)
|
|
82
|
+
return;
|
|
83
|
+
p.closing = true;
|
|
84
|
+
pool.delete(name);
|
|
85
|
+
if (p.idleTimer)
|
|
86
|
+
clearTimeout(p.idleTimer);
|
|
87
|
+
try {
|
|
88
|
+
await p.client.close();
|
|
89
|
+
}
|
|
90
|
+
catch { /* */ }
|
|
91
|
+
try {
|
|
92
|
+
await p.transport.close();
|
|
93
|
+
}
|
|
94
|
+
catch { /* */ }
|
|
95
|
+
}
|
|
96
|
+
const handler = async ({ server, tool, inputs, signal }) => {
|
|
97
|
+
if (signal.aborted)
|
|
98
|
+
throw Object.assign(new Error('Aborted'), { name: 'AbortError' });
|
|
99
|
+
const pooled = await getOrSpawnClient(server);
|
|
100
|
+
if (!pooled) {
|
|
101
|
+
return {
|
|
102
|
+
_builderMock: true,
|
|
103
|
+
reason: `MCP server "${server}" not available (not configured, disabled, or non-stdio transport).`,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const work = pooled.client.callTool({ name: tool, arguments: inputs });
|
|
107
|
+
const timeout = new Promise((_, reject) => setTimeout(() => reject(Object.assign(new Error(`MCP tool ${server}.${tool} timed out`), { name: 'TimeoutError' })), PER_CALL_TIMEOUT_MS));
|
|
108
|
+
const onAbort = new Promise((_, reject) => signal.addEventListener('abort', () => reject(Object.assign(new Error('Aborted'), { name: 'AbortError' })), { once: true }));
|
|
109
|
+
try {
|
|
110
|
+
const result = await Promise.race([work, timeout, onAbort]);
|
|
111
|
+
pooled.lastUsedAt = Date.now();
|
|
112
|
+
rescheduleIdleTimer(pooled);
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
// If the connection died, drop it from the pool so the next call respawns.
|
|
117
|
+
const e = err;
|
|
118
|
+
if (e.code === 'ERR_PIPE_CLOSED' || /closed|killed|EPIPE/.test(e.message ?? '')) {
|
|
119
|
+
void closeClient(server);
|
|
120
|
+
}
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
let _registered = false;
|
|
125
|
+
/**
|
|
126
|
+
* Wire the handler into the runner. Idempotent — safe to call from any
|
|
127
|
+
* daemon entry path.
|
|
128
|
+
*/
|
|
129
|
+
export function installBuilderMcpHandler() {
|
|
130
|
+
if (_registered)
|
|
131
|
+
return;
|
|
132
|
+
registerMcpInvokeHandler(handler);
|
|
133
|
+
_registered = true;
|
|
134
|
+
logger.info({}, 'Builder MCP invoke handler installed');
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Tear down all pooled clients. Called from daemon graceful shutdown.
|
|
138
|
+
*/
|
|
139
|
+
export async function shutdownBuilderMcpHandler() {
|
|
140
|
+
const names = [...pool.keys()];
|
|
141
|
+
await Promise.all(names.map(n => closeClient(n)));
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=mcp-invoke.js.map
|