@synergenius/flow-weaver 0.17.15 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/flow-weaver.mjs +819 -301
- package/dist/cli/index.js +9 -2
- package/dist/cli/pack-commands.d.ts +13 -0
- package/dist/cli/pack-commands.js +75 -0
- package/dist/diagram/geometry.js +101 -11
- package/dist/diagram/html-viewer.js +377 -39
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +1 -1
- package/dist/marketplace/index.d.ts +1 -1
- package/dist/marketplace/types.d.ts +30 -0
- package/dist/mcp/pack-tools.d.ts +9 -0
- package/dist/mcp/pack-tools.js +36 -0
- package/dist/mcp/server.js +2 -0
- package/package.json +1 -1
|
@@ -553,7 +553,10 @@ path[data-source].port-hover { opacity: 1; }
|
|
|
553
553
|
portConnections[tgt].push(src);
|
|
554
554
|
});
|
|
555
555
|
|
|
556
|
-
// ---- Connection path computation (from geometry.ts) ----
|
|
556
|
+
// ---- Connection path computation (bezier from geometry.ts + orthogonal router) ----
|
|
557
|
+
var TRACK_SPACING = 15, EDGE_OFFSET = 5, MAX_CANDIDATES = 5;
|
|
558
|
+
var MIN_SEG_LEN = 3, JOG_THRESHOLD = 10, ORTHO_THRESHOLD = 300;
|
|
559
|
+
|
|
557
560
|
function quadCurveControl(ax, ay, bx, by, ux, uy) {
|
|
558
561
|
var dn = Math.abs(ay - by);
|
|
559
562
|
return [bx + (ux * dn) / Math.abs(uy), ay];
|
|
@@ -583,18 +586,326 @@ path[data-source].port-hover { opacity: 1; }
|
|
|
583
586
|
' L ' + hx + ',' + hy;
|
|
584
587
|
}
|
|
585
588
|
|
|
586
|
-
// ----
|
|
589
|
+
// ---- Orthogonal router (ported from orthogonal-router.ts) ----
|
|
590
|
+
function createAllocator() {
|
|
591
|
+
var claims = [], vclaims = [];
|
|
592
|
+
function isOcc(xn, xx, y) {
|
|
593
|
+
for (var i = 0; i < claims.length; i++) {
|
|
594
|
+
var c = claims[i];
|
|
595
|
+
if (c.xn < xx && c.xx > xn && Math.abs(c.y - y) < TRACK_SPACING) return true;
|
|
596
|
+
}
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
function isOccV(yn, yx, x) {
|
|
600
|
+
for (var i = 0; i < vclaims.length; i++) {
|
|
601
|
+
var c = vclaims[i];
|
|
602
|
+
if (c.yn < yx && c.yx > yn && Math.abs(c.x - x) < TRACK_SPACING) return true;
|
|
603
|
+
}
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
function blockedByNode(xn, xx, y, boxes) {
|
|
607
|
+
for (var i = 0; i < boxes.length; i++) {
|
|
608
|
+
var b = boxes[i]; if (xn < b.r && xx > b.l && y >= b.t && y <= b.b) return true;
|
|
609
|
+
}
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
function blockedByNodeV(yn, yx, x, boxes) {
|
|
613
|
+
for (var i = 0; i < boxes.length; i++) {
|
|
614
|
+
var b = boxes[i]; if (x >= b.l && x <= b.r && yn < b.b && yx > b.t) return true;
|
|
615
|
+
}
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
function countHCross(xn, xx, y) {
|
|
619
|
+
var n = 0;
|
|
620
|
+
for (var i = 0; i < vclaims.length; i++) {
|
|
621
|
+
var c = vclaims[i]; if (c.x > xn && c.x < xx && y >= c.yn && y <= c.yx) n++;
|
|
622
|
+
}
|
|
623
|
+
return n;
|
|
624
|
+
}
|
|
625
|
+
function countVCross(yn, yx, x) {
|
|
626
|
+
var n = 0;
|
|
627
|
+
for (var i = 0; i < claims.length; i++) {
|
|
628
|
+
var c = claims[i]; if (c.y > yn && c.y < yx && x >= c.xn && x <= c.xx) n++;
|
|
629
|
+
}
|
|
630
|
+
return n;
|
|
631
|
+
}
|
|
632
|
+
return {
|
|
633
|
+
findFreeY: function(xn, xx, cy, nb) {
|
|
634
|
+
var free = function(y) { return !isOcc(xn, xx, y) && (!nb || !blockedByNode(xn, xx, y, nb)); };
|
|
635
|
+
if (free(cy)) return cy;
|
|
636
|
+
var cands = [];
|
|
637
|
+
for (var off = TRACK_SPACING; off < 800 && cands.length < MAX_CANDIDATES * 2; off += TRACK_SPACING) {
|
|
638
|
+
if (free(cy - off)) cands.push({ y: cy - off, d: off });
|
|
639
|
+
if (free(cy + off)) cands.push({ y: cy + off, d: off });
|
|
640
|
+
}
|
|
641
|
+
if (!cands.length) return cy;
|
|
642
|
+
var best = cands[0].y, bc = countHCross(xn, xx, cands[0].y), bd = cands[0].d;
|
|
643
|
+
for (var i = 1; i < cands.length; i++) {
|
|
644
|
+
var cr = countHCross(xn, xx, cands[i].y);
|
|
645
|
+
if (cr < bc || (cr === bc && cands[i].d < bd)) { best = cands[i].y; bc = cr; bd = cands[i].d; }
|
|
646
|
+
}
|
|
647
|
+
return best;
|
|
648
|
+
},
|
|
649
|
+
findFreeX: function(yn, yx, cx, nb) {
|
|
650
|
+
var free = function(x) { return !isOccV(yn, yx, x) && (!nb || !blockedByNodeV(yn, yx, x, nb)); };
|
|
651
|
+
if (free(cx)) return cx;
|
|
652
|
+
var cands = [];
|
|
653
|
+
for (var off = TRACK_SPACING; off < 800 && cands.length < MAX_CANDIDATES * 2; off += TRACK_SPACING) {
|
|
654
|
+
if (free(cx - off)) cands.push({ x: cx - off, d: off });
|
|
655
|
+
if (free(cx + off)) cands.push({ x: cx + off, d: off });
|
|
656
|
+
}
|
|
657
|
+
if (!cands.length) return cx;
|
|
658
|
+
var best = cands[0].x, bc = countVCross(yn, yx, cands[0].x), bd = cands[0].d;
|
|
659
|
+
for (var i = 1; i < cands.length; i++) {
|
|
660
|
+
var cr = countVCross(yn, yx, cands[i].x);
|
|
661
|
+
if (cr < bc || (cr === bc && cands[i].d < bd)) { best = cands[i].x; bc = cr; bd = cands[i].d; }
|
|
662
|
+
}
|
|
663
|
+
return best;
|
|
664
|
+
},
|
|
665
|
+
claim: function(xn, xx, y) { claims.push({ xn: xn, xx: xx, y: y }); },
|
|
666
|
+
claimV: function(yn, yx, x) { vclaims.push({ yn: yn, yx: yx, x: x }); }
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
function inflateBox(b, pad) { return { l: b.x - pad, r: b.x + b.w + pad, t: b.y - pad, b: b.y + b.h + pad }; }
|
|
671
|
+
function segOvlp(xn, xx, y, bx) { return xn < bx.r && xx > bx.l && y >= bx.t && y <= bx.b; }
|
|
672
|
+
function vSegClear(x, yn, yx, boxes) {
|
|
673
|
+
for (var i = 0; i < boxes.length; i++) { var b = boxes[i]; if (x >= b.l && x <= b.r && yn < b.b && yx > b.t) return false; }
|
|
674
|
+
return true;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function findClearY(xn, xx, cy, boxes) {
|
|
678
|
+
var blocked = function(y) { for (var i = 0; i < boxes.length; i++) if (segOvlp(xn, xx, y, boxes[i])) return true; return false; };
|
|
679
|
+
if (!blocked(cy)) return cy;
|
|
680
|
+
var edges = [];
|
|
681
|
+
for (var i = 0; i < boxes.length; i++) { var b = boxes[i]; if (xn < b.r && xx > b.l) { edges.push(b.t); edges.push(b.b); } }
|
|
682
|
+
if (!edges.length) return cy;
|
|
683
|
+
edges.sort(function(a, b) { return a - b; });
|
|
684
|
+
var best = cy, bd = Infinity;
|
|
685
|
+
for (var i = 0; i < edges.length; i++) {
|
|
686
|
+
var vals = [edges[i] - EDGE_OFFSET, edges[i] + EDGE_OFFSET];
|
|
687
|
+
for (var j = 0; j < 2; j++) { if (!blocked(vals[j])) { var d = Math.abs(vals[j] - cy); if (d < bd) { bd = d; best = vals[j]; } } }
|
|
688
|
+
}
|
|
689
|
+
if (bd === Infinity) {
|
|
690
|
+
var mn = Math.min.apply(null, edges) - EDGE_OFFSET * 2, mx = Math.max.apply(null, edges) + EDGE_OFFSET * 2;
|
|
691
|
+
best = Math.abs(mn - cy) <= Math.abs(mx - cy) ? mn : mx;
|
|
692
|
+
if (blocked(best)) { for (var off = TRACK_SPACING; off < 800; off += TRACK_SPACING) { if (!blocked(best - off)) { best -= off; break; } if (!blocked(best + off)) { best += off; break; } } }
|
|
693
|
+
}
|
|
694
|
+
return best;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function findClearX(yn, yx, cx, boxes) {
|
|
698
|
+
var blocked = function(x) { for (var i = 0; i < boxes.length; i++) { var b = boxes[i]; if (x >= b.l && x <= b.r && yn < b.b && yx > b.t) return true; } return false; };
|
|
699
|
+
if (!blocked(cx)) return cx;
|
|
700
|
+
var edges = [];
|
|
701
|
+
for (var i = 0; i < boxes.length; i++) { var b = boxes[i]; if (yn < b.b && yx > b.t) { edges.push(b.l); edges.push(b.r); } }
|
|
702
|
+
if (!edges.length) return cx;
|
|
703
|
+
edges.sort(function(a, b) { return a - b; });
|
|
704
|
+
var best = cx, bd = Infinity;
|
|
705
|
+
for (var i = 0; i < edges.length; i++) {
|
|
706
|
+
var vals = [edges[i] - EDGE_OFFSET, edges[i] + EDGE_OFFSET];
|
|
707
|
+
for (var j = 0; j < 2; j++) { if (!blocked(vals[j])) { var d = Math.abs(vals[j] - cx); if (d < bd) { bd = d; best = vals[j]; } } }
|
|
708
|
+
}
|
|
709
|
+
if (bd === Infinity) {
|
|
710
|
+
var mn = Math.min.apply(null, edges) - EDGE_OFFSET * 2, mx = Math.max.apply(null, edges) + EDGE_OFFSET * 2;
|
|
711
|
+
best = Math.abs(mn - cx) <= Math.abs(mx - cx) ? mn : mx;
|
|
712
|
+
if (blocked(best)) { for (var off = TRACK_SPACING; off < 800; off += TRACK_SPACING) { if (!blocked(best - off)) { best -= off; break; } if (!blocked(best + off)) { best += off; break; } } }
|
|
713
|
+
}
|
|
714
|
+
return best;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
function simplifyWaypoints(pts) {
|
|
718
|
+
if (pts.length <= 2) return pts;
|
|
719
|
+
var jogFound = true;
|
|
720
|
+
while (jogFound) {
|
|
721
|
+
jogFound = false;
|
|
722
|
+
for (var i = 0; i < pts.length - 3; i++) {
|
|
723
|
+
var a = pts[i], b = pts[i+1], c = pts[i+2], d = pts[i+3];
|
|
724
|
+
var jogH = Math.abs(b[1] - c[1]);
|
|
725
|
+
if (Math.abs(a[1] - b[1]) < 0.5 && Math.abs(b[0] - c[0]) < 0.5 && Math.abs(c[1] - d[1]) < 0.5 && jogH > 0.5 && jogH < JOG_THRESHOLD) {
|
|
726
|
+
var mid = (b[1] + c[1]) / 2, snap = Math.abs(a[1] - mid) <= Math.abs(d[1] - mid) ? a[1] : d[1];
|
|
727
|
+
pts = pts.slice(); pts[i+1] = [b[0], snap]; pts[i+2] = [c[0], snap]; jogFound = true; break;
|
|
728
|
+
}
|
|
729
|
+
var jogW = Math.abs(b[0] - c[0]);
|
|
730
|
+
if (Math.abs(a[0] - b[0]) < 0.5 && Math.abs(b[1] - c[1]) < 0.5 && Math.abs(c[0] - d[0]) < 0.5 && jogW > 0.5 && jogW < JOG_THRESHOLD) {
|
|
731
|
+
var mid = (b[0] + c[0]) / 2, snap = Math.abs(a[0] - mid) <= Math.abs(d[0] - mid) ? a[0] : d[0];
|
|
732
|
+
pts = pts.slice(); pts[i+1] = [snap, b[1]]; pts[i+2] = [snap, c[1]]; jogFound = true; break;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
var res = [pts[0]];
|
|
737
|
+
for (var i = 1; i < pts.length - 1; i++) {
|
|
738
|
+
var prev = res[res.length - 1], cur = pts[i], next = pts[i+1];
|
|
739
|
+
if (Math.abs(prev[0] - cur[0]) + Math.abs(prev[1] - cur[1]) < MIN_SEG_LEN) continue;
|
|
740
|
+
var sameX = Math.abs(prev[0] - cur[0]) < 0.01 && Math.abs(cur[0] - next[0]) < 0.01;
|
|
741
|
+
var sameY = Math.abs(prev[1] - cur[1]) < 0.01 && Math.abs(cur[1] - next[1]) < 0.01;
|
|
742
|
+
if (!sameX && !sameY) res.push(cur);
|
|
743
|
+
}
|
|
744
|
+
res.push(pts[pts.length - 1]);
|
|
745
|
+
return res;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
function waypointsToPath(wp, cr) {
|
|
749
|
+
if (wp.length < 2) return '';
|
|
750
|
+
if (wp.length === 2) return 'M ' + wp[0][0] + ',' + wp[0][1] + ' L ' + wp[1][0] + ',' + wp[1][1];
|
|
751
|
+
var radii = [];
|
|
752
|
+
for (var i = 0; i < wp.length; i++) radii[i] = 0;
|
|
753
|
+
for (var i = 1; i < wp.length - 1; i++) {
|
|
754
|
+
var p = wp[i-1], c = wp[i], n = wp[i+1];
|
|
755
|
+
var lp = Math.sqrt((p[0]-c[0])*(p[0]-c[0]) + (p[1]-c[1])*(p[1]-c[1]));
|
|
756
|
+
var ln = Math.sqrt((n[0]-c[0])*(n[0]-c[0]) + (n[1]-c[1])*(n[1]-c[1]));
|
|
757
|
+
radii[i] = (lp < 0.01 || ln < 0.01) ? 0 : Math.min(cr, lp / 2, ln / 2);
|
|
758
|
+
}
|
|
759
|
+
for (var i = 1; i < wp.length - 2; i++) {
|
|
760
|
+
var c = wp[i], n = wp[i+1];
|
|
761
|
+
var sl = Math.sqrt((n[0]-c[0])*(n[0]-c[0]) + (n[1]-c[1])*(n[1]-c[1]));
|
|
762
|
+
var tot = radii[i] + radii[i+1];
|
|
763
|
+
if (tot > sl && tot > 0) { var sc = sl / tot; radii[i] *= sc; radii[i+1] *= sc; }
|
|
764
|
+
}
|
|
765
|
+
var path = 'M ' + wp[0][0] + ',' + wp[0][1];
|
|
766
|
+
for (var i = 1; i < wp.length - 1; i++) {
|
|
767
|
+
var p = wp[i-1], c = wp[i], n = wp[i+1], r = radii[i];
|
|
768
|
+
if (r < 2) { path += ' L ' + c[0] + ',' + c[1]; continue; }
|
|
769
|
+
var dpx = p[0]-c[0], dpy = p[1]-c[1], dnx = n[0]-c[0], dny = n[1]-c[1];
|
|
770
|
+
var lp = Math.sqrt(dpx*dpx + dpy*dpy), ln = Math.sqrt(dnx*dnx + dny*dny);
|
|
771
|
+
var upx = dpx/lp, upy = dpy/lp, unx = dnx/ln, uny = dny/ln;
|
|
772
|
+
var asx = c[0] + upx*r, asy = c[1] + upy*r, aex = c[0] + unx*r, aey = c[1] + uny*r;
|
|
773
|
+
var cross = dpx*dny - dpy*dnx, sweep = cross > 0 ? 0 : 1;
|
|
774
|
+
path += ' L ' + asx + ',' + asy + ' A ' + r + ' ' + r + ' 0 0 ' + sweep + ' ' + aex + ',' + aey;
|
|
775
|
+
}
|
|
776
|
+
path += ' L ' + wp[wp.length-1][0] + ',' + wp[wp.length-1][1];
|
|
777
|
+
return path;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
function computeWaypoints(from, to, nboxes, srcId, tgtId, pad, exitStub, entryStub, alloc) {
|
|
781
|
+
var isSelf = srcId === tgtId;
|
|
782
|
+
var iboxes = [];
|
|
783
|
+
for (var i = 0; i < nboxes.length; i++) {
|
|
784
|
+
var b = nboxes[i];
|
|
785
|
+
if (isSelf || (b.id !== srcId && b.id !== tgtId)) iboxes.push(inflateBox(b, pad));
|
|
786
|
+
}
|
|
787
|
+
var se = [from[0] + exitStub, from[1]], sn = [to[0] - entryStub, to[1]];
|
|
788
|
+
var xn = Math.min(se[0], sn[0]), xx = Math.max(se[0], sn[0]);
|
|
789
|
+
|
|
790
|
+
if (!isSelf && to[0] > from[0]) {
|
|
791
|
+
var cy = (from[1] + to[1]) / 2;
|
|
792
|
+
var intBoxes = [];
|
|
793
|
+
for (var i = 0; i < iboxes.length; i++) { var b = iboxes[i]; if (b.l < xx && b.r > xn) intBoxes.push(b); }
|
|
794
|
+
if (intBoxes.length >= 2) {
|
|
795
|
+
var ct = Infinity, cb = -Infinity;
|
|
796
|
+
for (var i = 0; i < intBoxes.length; i++) { ct = Math.min(ct, intBoxes[i].t); cb = Math.max(cb, intBoxes[i].b); }
|
|
797
|
+
if (cy > ct && cy < cb) { cy = (cy - ct <= cb - cy) ? ct - pad : cb + pad; }
|
|
798
|
+
}
|
|
799
|
+
var clearY = findClearY(xn, xx, cy, iboxes);
|
|
800
|
+
if (Math.abs(from[1] - to[1]) < JOG_THRESHOLD && Math.abs(clearY - from[1]) < JOG_THRESHOLD) return null;
|
|
801
|
+
|
|
802
|
+
var midX = (se[0] + sn[0]) / 2, ymn = Math.min(from[1], to[1]), ymx = Math.max(from[1], to[1]);
|
|
803
|
+
var cmx = findClearX(ymn, ymx, midX, iboxes);
|
|
804
|
+
var fmx = alloc.findFreeX(ymn, ymx, cmx, iboxes);
|
|
805
|
+
if (ymx - ymn >= JOG_THRESHOLD && fmx > se[0] && fmx < sn[0] &&
|
|
806
|
+
vSegClear(fmx, ymn, ymx, iboxes) &&
|
|
807
|
+
alloc.findFreeY(from[0], fmx, from[1], iboxes) === from[1] &&
|
|
808
|
+
alloc.findFreeY(fmx, to[0], to[1], iboxes) === to[1]) {
|
|
809
|
+
alloc.claim(from[0], fmx, from[1]); alloc.claim(fmx, to[0], to[1]); alloc.claimV(ymn, ymx, fmx);
|
|
810
|
+
return simplifyWaypoints([from, [fmx, from[1]], [fmx, to[1]], to]);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
clearY = alloc.findFreeY(xn, xx, clearY, iboxes);
|
|
814
|
+
if (Math.abs(clearY - from[1]) < JOG_THRESHOLD && !iboxes.some(function(b) { return segOvlp(xn, xx, from[1], b); })) clearY = from[1];
|
|
815
|
+
else if (Math.abs(clearY - to[1]) < JOG_THRESHOLD && !iboxes.some(function(b) { return segOvlp(xn, xx, to[1], b); })) clearY = to[1];
|
|
816
|
+
alloc.claim(xn, xx, clearY);
|
|
817
|
+
|
|
818
|
+
var eymn = Math.min(from[1], clearY), eymx = Math.max(from[1], clearY);
|
|
819
|
+
var exX = findClearX(eymn, eymx, se[0], iboxes); exX = alloc.findFreeX(eymn, eymx, exX, iboxes);
|
|
820
|
+
if (exX < from[0]) { exX = se[0]; if (!vSegClear(exX, eymn, eymx, iboxes)) { exX = findClearX(eymn, eymx, se[0] + TRACK_SPACING, iboxes); exX = alloc.findFreeX(eymn, eymx, exX, iboxes); } }
|
|
821
|
+
alloc.claimV(eymn, eymx, exX);
|
|
822
|
+
|
|
823
|
+
var nymn = Math.min(to[1], clearY), nymx = Math.max(to[1], clearY);
|
|
824
|
+
var nxX = findClearX(nymn, nymx, sn[0], iboxes); nxX = alloc.findFreeX(nymn, nymx, nxX, iboxes);
|
|
825
|
+
if (nxX > to[0]) { nxX = sn[0]; if (!vSegClear(nxX, nymn, nymx, iboxes)) { nxX = findClearX(nymn, nymx, sn[0] - TRACK_SPACING, iboxes); nxX = alloc.findFreeX(nymn, nymx, nxX, iboxes); } }
|
|
826
|
+
alloc.claimV(nymn, nymx, nxX);
|
|
827
|
+
|
|
828
|
+
return simplifyWaypoints([from, [exX, from[1]], [exX, clearY], [nxX, clearY], [nxX, to[1]], to]);
|
|
829
|
+
} else {
|
|
830
|
+
var srcBox = null, tgtBox = null;
|
|
831
|
+
for (var i = 0; i < nboxes.length; i++) { if (nboxes[i].id === srcId) srcBox = nboxes[i]; if (nboxes[i].id === tgtId) tgtBox = nboxes[i]; }
|
|
832
|
+
var corBoxes = []; for (var i = 0; i < iboxes.length; i++) { var b = iboxes[i]; if (b.l < xx && b.r > xn) corBoxes.push(b); }
|
|
833
|
+
var bots = corBoxes.map(function(b) { return b.b; }), tops = corBoxes.map(function(b) { return b.t; });
|
|
834
|
+
if (srcBox) { bots.push(srcBox.y + srcBox.h + pad); tops.push(srcBox.y - pad); }
|
|
835
|
+
if (tgtBox) { bots.push(tgtBox.y + tgtBox.h + pad); tops.push(tgtBox.y - pad); }
|
|
836
|
+
var maxBot = Math.max.apply(null, bots.concat([from[1] + 50, to[1] + 50]));
|
|
837
|
+
var minTop = Math.min.apply(null, tops.concat([from[1] - 50, to[1] - 50]));
|
|
838
|
+
var avgY = (from[1] + to[1]) / 2;
|
|
839
|
+
var escBelow = maxBot + pad, escAbove = minTop - pad;
|
|
840
|
+
var escY = Math.abs(escAbove - avgY) <= Math.abs(escBelow - avgY) ? escAbove : escBelow;
|
|
841
|
+
escY = findClearY(xn, xx, escY, iboxes); escY = alloc.findFreeY(xn, xx, escY, iboxes); alloc.claim(xn, xx, escY);
|
|
842
|
+
|
|
843
|
+
var bymn = Math.min(from[1], escY), bymx = Math.max(from[1], escY);
|
|
844
|
+
var bexX = findClearX(bymn, bymx, se[0], iboxes); bexX = alloc.findFreeX(bymn, bymx, bexX, iboxes); alloc.claimV(bymn, bymx, bexX);
|
|
845
|
+
|
|
846
|
+
var bnmn = Math.min(to[1], escY), bnmx = Math.max(to[1], escY);
|
|
847
|
+
var bnxX = findClearX(bnmn, bnmx, sn[0], iboxes); bnxX = alloc.findFreeX(bnmn, bnmx, bnxX, iboxes); alloc.claimV(bnmn, bnmx, bnxX);
|
|
848
|
+
|
|
849
|
+
return simplifyWaypoints([from, [bexX, from[1]], [bexX, escY], [bnxX, escY], [bnxX, to[1]], to]);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
function calcOrthogonalPath(from, to, nboxes, srcId, tgtId, fromIdx, toIdx, alloc) {
|
|
854
|
+
var pad = 15, stubLen = 20, stubSpc = 12, maxStub = 80, cr = 10;
|
|
855
|
+
var exitStub = Math.min(stubLen + fromIdx * stubSpc, maxStub);
|
|
856
|
+
var entryStub = Math.min(stubLen + toIdx * stubSpc, maxStub);
|
|
857
|
+
try {
|
|
858
|
+
var wp = computeWaypoints(from, to, nboxes, srcId, tgtId, pad, exitStub, entryStub, alloc);
|
|
859
|
+
if (!wp) return null;
|
|
860
|
+
var p = waypointsToPath(wp, cr);
|
|
861
|
+
return (p && p.length >= 5) ? p : null;
|
|
862
|
+
} catch (e) { return null; }
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// ---- Port position + node box + connection path indexes ----
|
|
587
866
|
var portPositions = {};
|
|
588
867
|
content.querySelectorAll('[data-port-id]').forEach(function(el) {
|
|
589
868
|
var id = el.getAttribute('data-port-id');
|
|
590
869
|
portPositions[id] = { cx: parseFloat(el.getAttribute('cx')), cy: parseFloat(el.getAttribute('cy')) };
|
|
591
870
|
});
|
|
592
871
|
|
|
872
|
+
// Extract node bounding boxes from SVG rect elements
|
|
873
|
+
var nodeBoxMap = {};
|
|
874
|
+
content.querySelectorAll('.nodes [data-node-id]').forEach(function(g) {
|
|
875
|
+
var nid = g.getAttribute('data-node-id');
|
|
876
|
+
var rect = g.querySelector(':scope > rect');
|
|
877
|
+
if (!rect) return;
|
|
878
|
+
nodeBoxMap[nid] = {
|
|
879
|
+
id: nid,
|
|
880
|
+
x: parseFloat(rect.getAttribute('x')),
|
|
881
|
+
y: parseFloat(rect.getAttribute('y')),
|
|
882
|
+
w: parseFloat(rect.getAttribute('width')),
|
|
883
|
+
h: parseFloat(rect.getAttribute('height'))
|
|
884
|
+
};
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
// Build port-to-node mapping and compute port indices within each node
|
|
888
|
+
var portNodeMap = {};
|
|
889
|
+
var portIndexMap = {};
|
|
890
|
+
content.querySelectorAll('[data-port-id]').forEach(function(el) {
|
|
891
|
+
var id = el.getAttribute('data-port-id');
|
|
892
|
+
var dir = el.getAttribute('data-direction');
|
|
893
|
+
var parts = id.split('.');
|
|
894
|
+
var nodeId = parts[0];
|
|
895
|
+
portNodeMap[id] = nodeId;
|
|
896
|
+
if (!portIndexMap[nodeId]) portIndexMap[nodeId] = { input: [], output: [] };
|
|
897
|
+
portIndexMap[nodeId][dir].push(id);
|
|
898
|
+
});
|
|
899
|
+
|
|
593
900
|
var nodeOffsets = {};
|
|
594
901
|
var connIndex = [];
|
|
595
902
|
content.querySelectorAll('path[data-source]').forEach(function(p) {
|
|
596
903
|
var src = p.getAttribute('data-source'), tgt = p.getAttribute('data-target');
|
|
597
|
-
|
|
904
|
+
var srcNode = src.split('.')[0], tgtNode = tgt.split('.')[0];
|
|
905
|
+
var srcIdx = portIndexMap[srcNode] ? portIndexMap[srcNode].output.indexOf(src) : 0;
|
|
906
|
+
var tgtIdx = portIndexMap[tgtNode] ? portIndexMap[tgtNode].input.indexOf(tgt) : 0;
|
|
907
|
+
connIndex.push({ el: p, src: src, tgt: tgt, srcNode: srcNode, tgtNode: tgtNode,
|
|
908
|
+
scopeOf: p.getAttribute('data-scope') || null, srcIdx: Math.max(0, srcIdx), tgtIdx: Math.max(0, tgtIdx) });
|
|
598
909
|
});
|
|
599
910
|
|
|
600
911
|
// Snapshot of original port positions for reset
|
|
@@ -602,6 +913,47 @@ path[data-source].port-hover { opacity: 1; }
|
|
|
602
913
|
for (var pid in portPositions) {
|
|
603
914
|
origPortPositions[pid] = { cx: portPositions[pid].cx, cy: portPositions[pid].cy };
|
|
604
915
|
}
|
|
916
|
+
var origNodeBoxMap = {};
|
|
917
|
+
for (var nid in nodeBoxMap) {
|
|
918
|
+
var b = nodeBoxMap[nid];
|
|
919
|
+
origNodeBoxMap[nid] = { id: b.id, x: b.x, y: b.y, w: b.w, h: b.h };
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// ---- Recalculate all connection paths using orthogonal + bezier routing ----
|
|
923
|
+
function recalcAllPaths() {
|
|
924
|
+
var boxes = [];
|
|
925
|
+
for (var nid in nodeBoxMap) boxes.push(nodeBoxMap[nid]);
|
|
926
|
+
var sorted = connIndex.slice().sort(function(a, b) {
|
|
927
|
+
var spa = portPositions[a.src] && portPositions[a.tgt] ? Math.abs(portPositions[a.tgt].cx - portPositions[a.src].cx) : 0;
|
|
928
|
+
var spb = portPositions[b.src] && portPositions[b.tgt] ? Math.abs(portPositions[b.tgt].cx - portPositions[b.src].cx) : 0;
|
|
929
|
+
if (Math.abs(spa - spb) > 1) return spa - spb;
|
|
930
|
+
var sxa = portPositions[a.src] ? portPositions[a.src].cx : 0, sxb = portPositions[b.src] ? portPositions[b.src].cx : 0;
|
|
931
|
+
if (Math.abs(sxa - sxb) > 1) return sxa - sxb;
|
|
932
|
+
var sya = portPositions[a.src] ? portPositions[a.src].cy : 0, syb = portPositions[b.src] ? portPositions[b.src].cy : 0;
|
|
933
|
+
return sya - syb;
|
|
934
|
+
});
|
|
935
|
+
var alloc = createAllocator();
|
|
936
|
+
for (var i = 0; i < sorted.length; i++) {
|
|
937
|
+
var c = sorted[i];
|
|
938
|
+
var sp = portPositions[c.src], tp = portPositions[c.tgt];
|
|
939
|
+
if (!sp || !tp) continue;
|
|
940
|
+
var sx = sp.cx, sy = sp.cy, tx = tp.cx, ty = tp.cy;
|
|
941
|
+
// For scope connections, use parent-local coords
|
|
942
|
+
if (c.scopeOf) {
|
|
943
|
+
var pOff = nodeOffsets[c.scopeOf] || { dx: 0, dy: 0 };
|
|
944
|
+
sx -= pOff.dx; sy -= pOff.dy; tx -= pOff.dx; ty -= pOff.dy;
|
|
945
|
+
}
|
|
946
|
+
var ddx = tx - sx, ddy = ty - sy, dist = Math.sqrt(ddx * ddx + ddy * ddy);
|
|
947
|
+
var path;
|
|
948
|
+
if (dist > ORTHO_THRESHOLD) {
|
|
949
|
+
path = calcOrthogonalPath([sx, sy], [tx, ty], boxes, c.srcNode, c.tgtNode, c.srcIdx, c.tgtIdx, alloc);
|
|
950
|
+
if (!path) path = computeConnectionPath(sx, sy, tx, ty);
|
|
951
|
+
} else {
|
|
952
|
+
path = computeConnectionPath(sx, sy, tx, ty);
|
|
953
|
+
}
|
|
954
|
+
c.el.setAttribute('d', path);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
605
957
|
|
|
606
958
|
function resetLayout() {
|
|
607
959
|
for (var nid in nodeOffsets) {
|
|
@@ -621,10 +973,11 @@ path[data-source].port-hover { opacity: 1; }
|
|
|
621
973
|
for (var pid in origPortPositions) {
|
|
622
974
|
portPositions[pid] = { cx: origPortPositions[pid].cx, cy: origPortPositions[pid].cy };
|
|
623
975
|
}
|
|
624
|
-
|
|
625
|
-
var
|
|
626
|
-
|
|
627
|
-
}
|
|
976
|
+
for (var nid in origNodeBoxMap) {
|
|
977
|
+
var b = origNodeBoxMap[nid];
|
|
978
|
+
nodeBoxMap[nid] = { id: b.id, x: b.x, y: b.y, w: b.w, h: b.h };
|
|
979
|
+
}
|
|
980
|
+
recalcAllPaths();
|
|
628
981
|
fitToView();
|
|
629
982
|
}
|
|
630
983
|
document.getElementById('btn-reset').addEventListener('click', resetLayout);
|
|
@@ -694,39 +1047,24 @@ path[data-source].port-hover { opacity: 1; }
|
|
|
694
1047
|
});
|
|
695
1048
|
}
|
|
696
1049
|
|
|
697
|
-
//
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
if (
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
}
|
|
1050
|
+
// Update node box positions for orthogonal routing
|
|
1051
|
+
if (nodeBoxMap[nodeId]) {
|
|
1052
|
+
var nb = origNodeBoxMap[nodeId];
|
|
1053
|
+
if (nb) nodeBoxMap[nodeId] = { id: nb.id, x: nb.x + off.dx, y: nb.y + off.dy, w: nb.w, h: nb.h };
|
|
1054
|
+
}
|
|
1055
|
+
if (nodeG) {
|
|
1056
|
+
var children = nodeG.querySelectorAll(':scope > g[data-node-id]');
|
|
1057
|
+
children.forEach(function(childG) {
|
|
1058
|
+
var childId = childG.getAttribute('data-node-id');
|
|
1059
|
+
var cnb = origNodeBoxMap[childId];
|
|
1060
|
+
if (cnb && nodeOffsets[childId]) {
|
|
1061
|
+
nodeBoxMap[childId] = { id: cnb.id, x: cnb.x + nodeOffsets[childId].dx, y: cnb.y + nodeOffsets[childId].dy, w: cnb.w, h: cnb.h };
|
|
710
1062
|
}
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
if (c.srcNode === childId || c.tgtNode === childId) {
|
|
717
|
-
var sp = portPositions[c.src], tp = portPositions[c.tgt];
|
|
718
|
-
if (sp && tp) {
|
|
719
|
-
if (c.scopeOf) {
|
|
720
|
-
var pOff = nodeOffsets[c.scopeOf] || { dx: 0, dy: 0 };
|
|
721
|
-
c.el.setAttribute('d', computeConnectionPath(sp.cx - pOff.dx, sp.cy - pOff.dy, tp.cx - pOff.dx, tp.cy - pOff.dy));
|
|
722
|
-
} else {
|
|
723
|
-
c.el.setAttribute('d', computeConnectionPath(sp.cx, sp.cy, tp.cx, tp.cy));
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
});
|
|
728
|
-
}
|
|
729
|
-
});
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// Recalculate all connection paths with orthogonal routing
|
|
1067
|
+
recalcAllPaths();
|
|
730
1068
|
}
|
|
731
1069
|
|
|
732
1070
|
var allLabelIds = Object.keys(labelMap);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.19.1";
|
|
2
2
|
//# sourceMappingURL=generated-version.d.ts.map
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Flow Weaver Marketplace — discover, install, and publish reusable
|
|
5
5
|
* node types, workflows, and patterns via npm.
|
|
6
6
|
*/
|
|
7
|
-
export type { TMarketplaceManifest, TManifestNodeType, TManifestWorkflow, TManifestPattern, TManifestExportTarget, TManifestPort, TValidationIssue, TValidationSeverity, TPackageValidationResult, TMarketplacePackageInfo, TInstalledPackage, TMarketInitConfig, TManifestTagHandler, TManifestValidationRuleSet, TManifestDocTopic, TManifestInitContribution, } from './types.js';
|
|
7
|
+
export type { TMarketplaceManifest, TManifestNodeType, TManifestWorkflow, TManifestPattern, TManifestExportTarget, TManifestPort, TValidationIssue, TValidationSeverity, TPackageValidationResult, TMarketplacePackageInfo, TInstalledPackage, TMarketInitConfig, TManifestTagHandler, TManifestValidationRuleSet, TManifestDocTopic, TManifestInitContribution, TManifestCliCommand, TManifestMcpTool, } from './types.js';
|
|
8
8
|
export { generateManifest, writeManifest, readManifest, type GenerateManifestOptions, type GenerateManifestResult, } from './manifest.js';
|
|
9
9
|
export { validatePackage } from './validator.js';
|
|
10
10
|
export { searchPackages, listInstalledPackages, getInstalledPackageManifest, discoverTagHandlers, discoverValidationRuleSets, discoverDocTopics, discoverInitContributions, type SearchOptions, type TDiscoveredTagHandler, type TDiscoveredValidationRuleSet, type TDiscoveredDocTopic, type TDiscoveredInitContribution, } from './registry.js';
|
|
@@ -36,6 +36,14 @@ export type TMarketplaceManifest = {
|
|
|
36
36
|
docs?: TManifestDocTopic[];
|
|
37
37
|
/** Init contributions: use cases and templates (v2) */
|
|
38
38
|
initContributions?: TManifestInitContribution;
|
|
39
|
+
/** CLI entrypoint module for pack-contributed commands */
|
|
40
|
+
cliEntrypoint?: string;
|
|
41
|
+
/** CLI commands contributed by this pack */
|
|
42
|
+
cliCommands?: TManifestCliCommand[];
|
|
43
|
+
/** MCP entrypoint module for pack-contributed tools */
|
|
44
|
+
mcpEntrypoint?: string;
|
|
45
|
+
/** MCP tools contributed by this pack */
|
|
46
|
+
mcpTools?: TManifestMcpTool[];
|
|
39
47
|
/** External dependency information */
|
|
40
48
|
dependencies?: {
|
|
41
49
|
/** Flow Weaver peer dependency constraints */
|
|
@@ -225,6 +233,28 @@ export type TManifestInitContribution = {
|
|
|
225
233
|
/** Template IDs this pack provides (must match IDs in the template registry) */
|
|
226
234
|
templates?: string[];
|
|
227
235
|
};
|
|
236
|
+
/** A CLI command contributed by a pack. Registered under the pack namespace. */
|
|
237
|
+
export type TManifestCliCommand = {
|
|
238
|
+
/** Command name (e.g., "run", "history") */
|
|
239
|
+
name: string;
|
|
240
|
+
/** Human-readable description */
|
|
241
|
+
description: string;
|
|
242
|
+
/** Usage string for positional args (e.g., "<file>", "[id]") */
|
|
243
|
+
usage?: string;
|
|
244
|
+
/** Command options */
|
|
245
|
+
options?: Array<{
|
|
246
|
+
flags: string;
|
|
247
|
+
description: string;
|
|
248
|
+
default?: string | number | boolean;
|
|
249
|
+
}>;
|
|
250
|
+
};
|
|
251
|
+
/** An MCP tool contributed by a pack. */
|
|
252
|
+
export type TManifestMcpTool = {
|
|
253
|
+
/** Tool name (e.g., "fw_weaver_run") */
|
|
254
|
+
name: string;
|
|
255
|
+
/** Human-readable description */
|
|
256
|
+
description: string;
|
|
257
|
+
};
|
|
228
258
|
export type TMarketInitConfig = {
|
|
229
259
|
/** Package name (e.g., flowweaver-pack-openai) */
|
|
230
260
|
name: string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registers MCP tools contributed by installed marketplace packs.
|
|
3
|
+
*
|
|
4
|
+
* Scans for packs with mcpEntrypoint in their manifest. For each,
|
|
5
|
+
* imports the entrypoint and calls its registerMcpTools(mcp) function.
|
|
6
|
+
*/
|
|
7
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
export declare function registerPackMcpTools(mcp: McpServer): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=pack-tools.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registers MCP tools contributed by installed marketplace packs.
|
|
3
|
+
*
|
|
4
|
+
* Scans for packs with mcpEntrypoint in their manifest. For each,
|
|
5
|
+
* imports the entrypoint and calls its registerMcpTools(mcp) function.
|
|
6
|
+
*/
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { listInstalledPackages } from '../marketplace/registry.js';
|
|
9
|
+
export async function registerPackMcpTools(mcp) {
|
|
10
|
+
const projectDir = process.cwd();
|
|
11
|
+
let packages;
|
|
12
|
+
try {
|
|
13
|
+
packages = await listInstalledPackages(projectDir);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
for (const pkg of packages) {
|
|
19
|
+
const manifest = pkg.manifest;
|
|
20
|
+
if (!manifest.mcpEntrypoint || !manifest.mcpTools?.length)
|
|
21
|
+
continue;
|
|
22
|
+
const entrypointPath = path.join(pkg.path, manifest.mcpEntrypoint);
|
|
23
|
+
try {
|
|
24
|
+
const mod = await import(entrypointPath);
|
|
25
|
+
if (typeof mod.registerMcpTools === 'function') {
|
|
26
|
+
await mod.registerMcpTools(mcp);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
31
|
+
// Log to stderr so it doesn't interfere with MCP JSON-RPC on stdout
|
|
32
|
+
process.stderr.write(`[mcp] Failed to load pack tools from ${pkg.name}: ${msg}\n`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=pack-tools.js.map
|
package/dist/mcp/server.js
CHANGED
|
@@ -18,6 +18,7 @@ import { registerDebugTools } from './tools-debug.js';
|
|
|
18
18
|
import { registerContextTools } from './tools-context.js';
|
|
19
19
|
import { registerResources } from './resources.js';
|
|
20
20
|
import { registerPrompts } from './prompts.js';
|
|
21
|
+
import { registerPackMcpTools } from './pack-tools.js';
|
|
21
22
|
function parseEventFilterFromEnv() {
|
|
22
23
|
const filter = {};
|
|
23
24
|
const include = process.env.FW_EVENT_INCLUDE;
|
|
@@ -82,6 +83,7 @@ export async function startMcpServer(options) {
|
|
|
82
83
|
registerContextTools(mcp);
|
|
83
84
|
registerResources(mcp, connection, buffer);
|
|
84
85
|
registerPrompts(mcp);
|
|
86
|
+
await registerPackMcpTools(mcp);
|
|
85
87
|
// Connect transport (only in stdio MCP mode)
|
|
86
88
|
if (!options._testDeps && options.stdio) {
|
|
87
89
|
const transport = new StdioServerTransport();
|
package/package.json
CHANGED