@synergenius/flow-weaver 0.4.1 → 0.4.3
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 +48 -40
- package/dist/diagram/geometry.js +22 -12
- package/dist/diagram/html-viewer.js +27 -16
- package/dist/diagram/renderer.js +4 -2
- package/dist/diagram/types.d.ts +2 -0
- package/package.json +3 -3
package/dist/cli/flow-weaver.mjs
CHANGED
|
@@ -59388,20 +59388,6 @@ function assignUnpositionedNodes(layers, diagramNodes, explicitPositions) {
|
|
|
59388
59388
|
}
|
|
59389
59389
|
}
|
|
59390
59390
|
}
|
|
59391
|
-
function resolveHorizontalOverlaps(diagramNodes) {
|
|
59392
|
-
const nodes = [...diagramNodes.values()].sort((a, b) => a.x - b.x);
|
|
59393
|
-
for (let i = 1; i < nodes.length; i++) {
|
|
59394
|
-
const prev = nodes[i - 1];
|
|
59395
|
-
const curr = nodes[i];
|
|
59396
|
-
const prevRightExtent = maxPortLabelExtent(prev.outputs);
|
|
59397
|
-
const currLeftExtent = maxPortLabelExtent(curr.inputs);
|
|
59398
|
-
const minGap = Math.max(prevRightExtent + LABEL_CLEARANCE + currLeftExtent, MIN_EDGE_GAP);
|
|
59399
|
-
const actualGap = curr.x - (prev.x + prev.width);
|
|
59400
|
-
if (actualGap < minGap) {
|
|
59401
|
-
curr.x = prev.x + prev.width + minGap;
|
|
59402
|
-
}
|
|
59403
|
-
}
|
|
59404
|
-
}
|
|
59405
59391
|
function buildDiagramGraph(ast, options = {}) {
|
|
59406
59392
|
const themeName = options.theme ?? "dark";
|
|
59407
59393
|
const nodeTypeMap = /* @__PURE__ */ new Map();
|
|
@@ -59510,7 +59496,6 @@ function buildDiagramGraph(ast, options = {}) {
|
|
|
59510
59496
|
node.y = pos.y;
|
|
59511
59497
|
}
|
|
59512
59498
|
}
|
|
59513
|
-
resolveHorizontalOverlaps(diagramNodes);
|
|
59514
59499
|
} else if (nonePositioned) {
|
|
59515
59500
|
const { layers } = layoutWorkflow(ast);
|
|
59516
59501
|
assignLayerCoordinates(layers, diagramNodes);
|
|
@@ -59713,6 +59698,8 @@ function buildDiagramGraph(ast, options = {}) {
|
|
|
59713
59698
|
}
|
|
59714
59699
|
}
|
|
59715
59700
|
}
|
|
59701
|
+
let originX = 0;
|
|
59702
|
+
let originY = 0;
|
|
59716
59703
|
let normalizedMaxY = maxY - minY + padding * 2;
|
|
59717
59704
|
let normalizedMaxX = maxX - minX + padding * 2;
|
|
59718
59705
|
const allConns = [...connections];
|
|
@@ -59723,11 +59710,15 @@ function buildDiagramGraph(ast, options = {}) {
|
|
|
59723
59710
|
const extent = pathExtent(conn.path);
|
|
59724
59711
|
if (extent.maxY + padding > normalizedMaxY) normalizedMaxY = extent.maxY + padding;
|
|
59725
59712
|
if (extent.maxX + padding > normalizedMaxX) normalizedMaxX = extent.maxX + padding;
|
|
59713
|
+
if (extent.minY - padding < originY) originY = extent.minY - padding;
|
|
59714
|
+
if (extent.minX - padding < originX) originX = extent.minX - padding;
|
|
59726
59715
|
}
|
|
59716
|
+
normalizedMaxX -= originX;
|
|
59717
|
+
normalizedMaxY -= originY;
|
|
59727
59718
|
return {
|
|
59728
59719
|
nodes,
|
|
59729
59720
|
connections,
|
|
59730
|
-
bounds: { width: normalizedMaxX, height: normalizedMaxY },
|
|
59721
|
+
bounds: { width: normalizedMaxX, height: normalizedMaxY, originX, originY },
|
|
59731
59722
|
workflowName: ast.name
|
|
59732
59723
|
};
|
|
59733
59724
|
}
|
|
@@ -59765,15 +59756,19 @@ function resolveDefaultIcon(nt) {
|
|
|
59765
59756
|
return "code";
|
|
59766
59757
|
}
|
|
59767
59758
|
function pathExtent(path38) {
|
|
59768
|
-
let
|
|
59769
|
-
let maxY = -Infinity;
|
|
59759
|
+
let minX = Infinity, minY = Infinity;
|
|
59760
|
+
let maxX = -Infinity, maxY = -Infinity;
|
|
59770
59761
|
const pattern = /(-?[\d.]+),(-?[\d.]+)/g;
|
|
59771
59762
|
let m;
|
|
59772
59763
|
while ((m = pattern.exec(path38)) !== null) {
|
|
59773
|
-
|
|
59774
|
-
|
|
59764
|
+
const x = parseFloat(m[1]);
|
|
59765
|
+
const y = parseFloat(m[2]);
|
|
59766
|
+
minX = Math.min(minX, x);
|
|
59767
|
+
minY = Math.min(minY, y);
|
|
59768
|
+
maxX = Math.max(maxX, x);
|
|
59769
|
+
maxY = Math.max(maxY, y);
|
|
59775
59770
|
}
|
|
59776
|
-
return { maxX, maxY };
|
|
59771
|
+
return { minX, minY, maxX, maxY };
|
|
59777
59772
|
}
|
|
59778
59773
|
function maxPortLabelExtent(ports) {
|
|
59779
59774
|
if (ports.length === 0) return 0;
|
|
@@ -59804,7 +59799,9 @@ function renderSVG(graph, options = {}) {
|
|
|
59804
59799
|
const themeName = options.theme ?? "dark";
|
|
59805
59800
|
const theme = getTheme(themeName);
|
|
59806
59801
|
const showPortLabels = options.showPortLabels ?? true;
|
|
59807
|
-
let { width: vbWidth, height: vbHeight } = graph.bounds;
|
|
59802
|
+
let { width: vbWidth, height: vbHeight, originX: vbX, originY: vbY } = graph.bounds;
|
|
59803
|
+
vbX = vbX ?? 0;
|
|
59804
|
+
vbY = vbY ?? 0;
|
|
59808
59805
|
vbWidth = Math.max(vbWidth, 200);
|
|
59809
59806
|
vbHeight = Math.max(vbHeight, 100);
|
|
59810
59807
|
const svgWidth = options.width || vbWidth;
|
|
@@ -59812,7 +59809,7 @@ function renderSVG(graph, options = {}) {
|
|
|
59812
59809
|
const allConnections = collectAllConnections(graph);
|
|
59813
59810
|
const parts2 = [];
|
|
59814
59811
|
parts2.push(
|
|
59815
|
-
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="
|
|
59812
|
+
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="${vbX} ${vbY} ${vbWidth} ${vbHeight}" width="${svgWidth}" height="${svgHeight}">`
|
|
59816
59813
|
);
|
|
59817
59814
|
parts2.push(`<style>`);
|
|
59818
59815
|
parts2.push(` text { font-family: Montserrat, 'Segoe UI', Roboto, sans-serif; }`);
|
|
@@ -60065,7 +60062,7 @@ body {
|
|
|
60065
60062
|
body.node-active .connections path.dimmed { opacity: 0.15; }
|
|
60066
60063
|
|
|
60067
60064
|
/* Node hover glow */
|
|
60068
|
-
.nodes
|
|
60065
|
+
.nodes g[data-node-id]:hover > rect:first-of-type { filter: brightness(1.08); }
|
|
60069
60066
|
|
|
60070
60067
|
/* Zoom controls */
|
|
60071
60068
|
#controls {
|
|
@@ -60260,27 +60257,38 @@ body.node-active .connections path.dimmed { opacity: 0.15; }
|
|
|
60260
60257
|
|
|
60261
60258
|
// ---- Port label visibility via JS (since CSS sibling selectors can't reach .labels group) ----
|
|
60262
60259
|
var labelEls = content.querySelectorAll('.labels g[data-port-label]');
|
|
60263
|
-
var nodeEls = content.querySelectorAll('.nodes
|
|
60260
|
+
var nodeEls = content.querySelectorAll('.nodes g[data-node-id]');
|
|
60261
|
+
|
|
60262
|
+
function showLabelsFor(id) {
|
|
60263
|
+
labelEls.forEach(function(lbl) {
|
|
60264
|
+
var portId = lbl.getAttribute('data-port-label') || '';
|
|
60265
|
+
if (portId.indexOf(id + '.') === 0) {
|
|
60266
|
+
lbl.style.opacity = '1';
|
|
60267
|
+
lbl.style.pointerEvents = 'auto';
|
|
60268
|
+
}
|
|
60269
|
+
});
|
|
60270
|
+
}
|
|
60271
|
+
function hideLabelsFor(id) {
|
|
60272
|
+
labelEls.forEach(function(lbl) {
|
|
60273
|
+
var portId = lbl.getAttribute('data-port-label') || '';
|
|
60274
|
+
if (portId.indexOf(id + '.') === 0) {
|
|
60275
|
+
lbl.style.opacity = '0';
|
|
60276
|
+
lbl.style.pointerEvents = 'none';
|
|
60277
|
+
}
|
|
60278
|
+
});
|
|
60279
|
+
}
|
|
60264
60280
|
|
|
60265
60281
|
nodeEls.forEach(function(nodeG) {
|
|
60266
60282
|
var nodeId = nodeG.getAttribute('data-node-id');
|
|
60283
|
+
var parentNodeG = nodeG.parentElement ? nodeG.parentElement.closest('g[data-node-id]') : null;
|
|
60284
|
+
var parentId = parentNodeG ? parentNodeG.getAttribute('data-node-id') : null;
|
|
60267
60285
|
nodeG.addEventListener('mouseenter', function() {
|
|
60268
|
-
|
|
60269
|
-
|
|
60270
|
-
if (portId.indexOf(nodeId + '.') === 0) {
|
|
60271
|
-
lbl.style.opacity = '1';
|
|
60272
|
-
lbl.style.pointerEvents = 'auto';
|
|
60273
|
-
}
|
|
60274
|
-
});
|
|
60286
|
+
if (parentId) hideLabelsFor(parentId);
|
|
60287
|
+
showLabelsFor(nodeId);
|
|
60275
60288
|
});
|
|
60276
60289
|
nodeG.addEventListener('mouseleave', function() {
|
|
60277
|
-
|
|
60278
|
-
|
|
60279
|
-
if (portId.indexOf(nodeId + '.') === 0) {
|
|
60280
|
-
lbl.style.opacity = '0';
|
|
60281
|
-
lbl.style.pointerEvents = 'none';
|
|
60282
|
-
}
|
|
60283
|
-
});
|
|
60290
|
+
hideLabelsFor(nodeId);
|
|
60291
|
+
if (parentId) showLabelsFor(parentId);
|
|
60284
60292
|
});
|
|
60285
60293
|
});
|
|
60286
60294
|
|
|
@@ -94412,7 +94420,7 @@ function displayInstalledPackage(pkg) {
|
|
|
94412
94420
|
}
|
|
94413
94421
|
|
|
94414
94422
|
// src/cli/index.ts
|
|
94415
|
-
var version2 = true ? "0.4.
|
|
94423
|
+
var version2 = true ? "0.4.3" : "0.0.0-dev";
|
|
94416
94424
|
var program2 = new Command();
|
|
94417
94425
|
program2.name("flow-weaver").description("Flow Weaver Annotations - Compile and validate workflow files").version(version2, "-v, --version", "Output the current version");
|
|
94418
94426
|
program2.configureOutput({
|
package/dist/diagram/geometry.js
CHANGED
|
@@ -744,7 +744,7 @@ export function buildDiagramGraph(ast, options = {}) {
|
|
|
744
744
|
const allPositioned = [...diagramNodes.keys()].every(id => explicitPositions.has(id));
|
|
745
745
|
const nonePositioned = ![...diagramNodes.keys()].some(id => explicitPositions.has(id));
|
|
746
746
|
if (allPositioned) {
|
|
747
|
-
// All nodes have explicit positions — apply them
|
|
747
|
+
// All nodes have explicit positions — apply them as-is
|
|
748
748
|
for (const [id, pos] of explicitPositions) {
|
|
749
749
|
const node = diagramNodes.get(id);
|
|
750
750
|
if (node) {
|
|
@@ -752,9 +752,6 @@ export function buildDiagramGraph(ast, options = {}) {
|
|
|
752
752
|
node.y = pos.y;
|
|
753
753
|
}
|
|
754
754
|
}
|
|
755
|
-
// Resolve horizontal overlaps: scope nodes may be wider than the
|
|
756
|
-
// original positions anticipated, so push downstream nodes apart.
|
|
757
|
-
resolveHorizontalOverlaps(diagramNodes);
|
|
758
755
|
}
|
|
759
756
|
else if (nonePositioned) {
|
|
760
757
|
// No positions — full auto-layout (original behavior)
|
|
@@ -982,7 +979,9 @@ export function buildDiagramGraph(ast, options = {}) {
|
|
|
982
979
|
}
|
|
983
980
|
}
|
|
984
981
|
}
|
|
985
|
-
// Extend bounds to include connection paths (
|
|
982
|
+
// Extend bounds to include connection paths (routes can go outside node area)
|
|
983
|
+
let originX = 0;
|
|
984
|
+
let originY = 0;
|
|
986
985
|
let normalizedMaxY = (maxY - minY) + padding * 2;
|
|
987
986
|
let normalizedMaxX = (maxX - minX) + padding * 2;
|
|
988
987
|
const allConns = [...connections];
|
|
@@ -996,11 +995,18 @@ export function buildDiagramGraph(ast, options = {}) {
|
|
|
996
995
|
normalizedMaxY = extent.maxY + padding;
|
|
997
996
|
if (extent.maxX + padding > normalizedMaxX)
|
|
998
997
|
normalizedMaxX = extent.maxX + padding;
|
|
998
|
+
if (extent.minY - padding < originY)
|
|
999
|
+
originY = extent.minY - padding;
|
|
1000
|
+
if (extent.minX - padding < originX)
|
|
1001
|
+
originX = extent.minX - padding;
|
|
999
1002
|
}
|
|
1003
|
+
// Expand dimensions to cover the shifted origin
|
|
1004
|
+
normalizedMaxX -= originX;
|
|
1005
|
+
normalizedMaxY -= originY;
|
|
1000
1006
|
return {
|
|
1001
1007
|
nodes,
|
|
1002
1008
|
connections,
|
|
1003
|
-
bounds: { width: normalizedMaxX, height: normalizedMaxY },
|
|
1009
|
+
bounds: { width: normalizedMaxX, height: normalizedMaxY, originX, originY },
|
|
1004
1010
|
workflowName: ast.name,
|
|
1005
1011
|
};
|
|
1006
1012
|
}
|
|
@@ -1052,17 +1058,21 @@ function resolveDefaultIcon(nt) {
|
|
|
1052
1058
|
return 'flow';
|
|
1053
1059
|
return 'code';
|
|
1054
1060
|
}
|
|
1055
|
-
/** Extract max X/Y extent from an SVG path string (for bounds calculation) */
|
|
1061
|
+
/** Extract min/max X/Y extent from an SVG path string (for bounds calculation) */
|
|
1056
1062
|
function pathExtent(path) {
|
|
1057
|
-
let
|
|
1058
|
-
let maxY = -Infinity;
|
|
1063
|
+
let minX = Infinity, minY = Infinity;
|
|
1064
|
+
let maxX = -Infinity, maxY = -Infinity;
|
|
1059
1065
|
const pattern = /(-?[\d.]+),(-?[\d.]+)/g;
|
|
1060
1066
|
let m;
|
|
1061
1067
|
while ((m = pattern.exec(path)) !== null) {
|
|
1062
|
-
|
|
1063
|
-
|
|
1068
|
+
const x = parseFloat(m[1]);
|
|
1069
|
+
const y = parseFloat(m[2]);
|
|
1070
|
+
minX = Math.min(minX, x);
|
|
1071
|
+
minY = Math.min(minY, y);
|
|
1072
|
+
maxX = Math.max(maxX, x);
|
|
1073
|
+
maxY = Math.max(maxY, y);
|
|
1064
1074
|
}
|
|
1065
|
-
return { maxX, maxY };
|
|
1075
|
+
return { minX, minY, maxX, maxY };
|
|
1066
1076
|
}
|
|
1067
1077
|
/** Estimate the maximum port label badge extent beyond the node edge */
|
|
1068
1078
|
function maxPortLabelExtent(ports) {
|
|
@@ -73,7 +73,7 @@ body {
|
|
|
73
73
|
body.node-active .connections path.dimmed { opacity: 0.15; }
|
|
74
74
|
|
|
75
75
|
/* Node hover glow */
|
|
76
|
-
.nodes
|
|
76
|
+
.nodes g[data-node-id]:hover > rect:first-of-type { filter: brightness(1.08); }
|
|
77
77
|
|
|
78
78
|
/* Zoom controls */
|
|
79
79
|
#controls {
|
|
@@ -268,27 +268,38 @@ body.node-active .connections path.dimmed { opacity: 0.15; }
|
|
|
268
268
|
|
|
269
269
|
// ---- Port label visibility via JS (since CSS sibling selectors can't reach .labels group) ----
|
|
270
270
|
var labelEls = content.querySelectorAll('.labels g[data-port-label]');
|
|
271
|
-
var nodeEls = content.querySelectorAll('.nodes
|
|
271
|
+
var nodeEls = content.querySelectorAll('.nodes g[data-node-id]');
|
|
272
|
+
|
|
273
|
+
function showLabelsFor(id) {
|
|
274
|
+
labelEls.forEach(function(lbl) {
|
|
275
|
+
var portId = lbl.getAttribute('data-port-label') || '';
|
|
276
|
+
if (portId.indexOf(id + '.') === 0) {
|
|
277
|
+
lbl.style.opacity = '1';
|
|
278
|
+
lbl.style.pointerEvents = 'auto';
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
function hideLabelsFor(id) {
|
|
283
|
+
labelEls.forEach(function(lbl) {
|
|
284
|
+
var portId = lbl.getAttribute('data-port-label') || '';
|
|
285
|
+
if (portId.indexOf(id + '.') === 0) {
|
|
286
|
+
lbl.style.opacity = '0';
|
|
287
|
+
lbl.style.pointerEvents = 'none';
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
272
291
|
|
|
273
292
|
nodeEls.forEach(function(nodeG) {
|
|
274
293
|
var nodeId = nodeG.getAttribute('data-node-id');
|
|
294
|
+
var parentNodeG = nodeG.parentElement ? nodeG.parentElement.closest('g[data-node-id]') : null;
|
|
295
|
+
var parentId = parentNodeG ? parentNodeG.getAttribute('data-node-id') : null;
|
|
275
296
|
nodeG.addEventListener('mouseenter', function() {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if (portId.indexOf(nodeId + '.') === 0) {
|
|
279
|
-
lbl.style.opacity = '1';
|
|
280
|
-
lbl.style.pointerEvents = 'auto';
|
|
281
|
-
}
|
|
282
|
-
});
|
|
297
|
+
if (parentId) hideLabelsFor(parentId);
|
|
298
|
+
showLabelsFor(nodeId);
|
|
283
299
|
});
|
|
284
300
|
nodeG.addEventListener('mouseleave', function() {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
if (portId.indexOf(nodeId + '.') === 0) {
|
|
288
|
-
lbl.style.opacity = '0';
|
|
289
|
-
lbl.style.pointerEvents = 'none';
|
|
290
|
-
}
|
|
291
|
-
});
|
|
301
|
+
hideLabelsFor(nodeId);
|
|
302
|
+
if (parentId) showLabelsFor(parentId);
|
|
292
303
|
});
|
|
293
304
|
});
|
|
294
305
|
|
package/dist/diagram/renderer.js
CHANGED
|
@@ -17,7 +17,9 @@ export function renderSVG(graph, options = {}) {
|
|
|
17
17
|
const themeName = options.theme ?? 'dark';
|
|
18
18
|
const theme = getTheme(themeName);
|
|
19
19
|
const showPortLabels = options.showPortLabels ?? true;
|
|
20
|
-
let { width: vbWidth, height: vbHeight } = graph.bounds;
|
|
20
|
+
let { width: vbWidth, height: vbHeight, originX: vbX, originY: vbY } = graph.bounds;
|
|
21
|
+
vbX = vbX ?? 0;
|
|
22
|
+
vbY = vbY ?? 0;
|
|
21
23
|
// Ensure minimum bounds
|
|
22
24
|
vbWidth = Math.max(vbWidth, 200);
|
|
23
25
|
vbHeight = Math.max(vbHeight, 100);
|
|
@@ -27,7 +29,7 @@ export function renderSVG(graph, options = {}) {
|
|
|
27
29
|
const allConnections = collectAllConnections(graph);
|
|
28
30
|
const parts = [];
|
|
29
31
|
// SVG open
|
|
30
|
-
parts.push(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="
|
|
32
|
+
parts.push(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="${vbX} ${vbY} ${vbWidth} ${vbHeight}" width="${svgWidth}" height="${svgHeight}">`);
|
|
31
33
|
// Styles
|
|
32
34
|
parts.push(`<style>`);
|
|
33
35
|
parts.push(` text { font-family: Montserrat, 'Segoe UI', Roboto, sans-serif; }`);
|
package/dist/diagram/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synergenius/flow-weaver",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Deterministic workflow compiler for AI agents. Compiles to standalone TypeScript, no runtime dependencies.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -95,8 +95,8 @@
|
|
|
95
95
|
"typecheck": "tsc --noEmit -p tsconfig.build.json",
|
|
96
96
|
"docs": "typedoc && tsx scripts/generate-grammar-docs.ts",
|
|
97
97
|
"docs:serve": "npm run docs && npx http-server docs/api -c-1 -o",
|
|
98
|
-
"
|
|
99
|
-
"cli": "
|
|
98
|
+
"prepare": "npm run build",
|
|
99
|
+
"cli": "tsx src/cli/index.ts"
|
|
100
100
|
},
|
|
101
101
|
"keywords": [
|
|
102
102
|
"flow-weaver",
|