@synergenius/flow-weaver 0.7.0 → 0.8.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/annotation-generator.js +7 -7
- package/dist/api/generate-in-place.js +25 -20
- package/dist/api/patterns.js +12 -15
- package/dist/built-in-nodes/wait-for-agent.js +4 -0
- package/dist/chevrotain-parser/node-parser.d.ts +4 -0
- package/dist/chevrotain-parser/node-parser.js +24 -1
- package/dist/chevrotain-parser/tokens.d.ts +1 -0
- package/dist/chevrotain-parser/tokens.js +5 -0
- package/dist/cli/flow-weaver.mjs +110 -111
- package/dist/cli/index.js +1 -1
- package/dist/cli/templates/workflows/aggregator.js +3 -6
- package/dist/cli/templates/workflows/ai-agent-durable.js +4 -8
- package/dist/cli/templates/workflows/ai-agent.js +3 -6
- package/dist/cli/templates/workflows/ai-chat.js +3 -6
- package/dist/cli/templates/workflows/ai-pipeline-durable.js +4 -8
- package/dist/cli/templates/workflows/ai-rag.js +2 -4
- package/dist/cli/templates/workflows/ai-react.js +3 -6
- package/dist/cli/templates/workflows/conditional.js +3 -6
- package/dist/cli/templates/workflows/error-handler.js +2 -4
- package/dist/cli/templates/workflows/foreach.js +3 -6
- package/dist/cli/templates/workflows/sequential.js +7 -8
- package/dist/cli/templates/workflows/webhook.js +3 -6
- package/dist/doc-metadata/extractors/annotations.js +9 -6
- package/dist/editor-completions/jsDocAnnotations.js +5 -3
- package/dist/jsdoc-parser.d.ts +2 -0
- package/dist/jsdoc-parser.js +6 -1
- package/dist/parser.js +4 -3
- package/docs/reference/built-in-nodes.md +8 -0
- package/docs/reference/concepts.md +8 -7
- package/docs/reference/debugging.md +4 -1
- package/docs/reference/iterative-development.md +2 -3
- package/docs/reference/jsdoc-grammar.md +8 -3
- package/docs/reference/patterns.md +2 -4
- package/docs/reference/tutorial.md +8 -14
- package/package.json +1 -1
|
@@ -281,12 +281,7 @@ export class AnnotationGenerator {
|
|
|
281
281
|
if (workflow.ui?.startNode?.x !== undefined && workflow.ui?.startNode?.y !== undefined) {
|
|
282
282
|
lines.push(` * @position Start ${Math.round(workflow.ui.startNode.x)} ${Math.round(workflow.ui.startNode.y)}`);
|
|
283
283
|
}
|
|
284
|
-
//
|
|
285
|
-
workflow.instances.forEach((instance) => {
|
|
286
|
-
if (instance.config?.x !== undefined && instance.config?.y !== undefined) {
|
|
287
|
-
lines.push(` * @position ${instance.id} ${Math.round(instance.config.x)} ${Math.round(instance.config.y)}`);
|
|
288
|
-
}
|
|
289
|
-
});
|
|
284
|
+
// Instance positions are now emitted as [position: x y] on @node lines
|
|
290
285
|
// Add Exit node position if present
|
|
291
286
|
if (workflow.ui?.exitNode?.x !== undefined && workflow.ui?.exitNode?.y !== undefined) {
|
|
292
287
|
lines.push(` * @position Exit ${Math.round(workflow.ui.exitNode.x)} ${Math.round(workflow.ui.exitNode.y)}`);
|
|
@@ -612,7 +607,12 @@ export function generateNodeInstanceTag(instance) {
|
|
|
612
607
|
if (instance.config?.width !== undefined && instance.config?.height !== undefined) {
|
|
613
608
|
sizeAttr = ` [size: ${Math.round(instance.config.width)} ${Math.round(instance.config.height)}]`;
|
|
614
609
|
}
|
|
615
|
-
|
|
610
|
+
// Generate [position: x y] attribute if present
|
|
611
|
+
let positionAttr = '';
|
|
612
|
+
if (instance.config?.x !== undefined && instance.config?.y !== undefined) {
|
|
613
|
+
positionAttr = ` [position: ${Math.round(instance.config.x)} ${Math.round(instance.config.y)}]`;
|
|
614
|
+
}
|
|
615
|
+
return ` * @node ${instance.id} ${instance.nodeType}${parent}${labelAttr}${portOrderAttr}${portLabelAttr}${exprAttr}${pullExecutionAttr}${minimizedAttr}${colorAttr}${iconAttr}${tagsAttr}${sizeAttr}${positionAttr}`;
|
|
616
616
|
}
|
|
617
617
|
export const annotationGenerator = new AnnotationGenerator();
|
|
618
618
|
//# sourceMappingURL=annotation-generator.js.map
|
|
@@ -1119,17 +1119,36 @@ function generateWorkflowJSDoc(ast, options = {}) {
|
|
|
1119
1119
|
}
|
|
1120
1120
|
lines.push(` * @fwImport ${npmType.name} ${actualFunctionName} from "${npmType.importSource}"`);
|
|
1121
1121
|
}
|
|
1122
|
-
//
|
|
1122
|
+
// Auto-position: compute default positions for nodes without explicit positions.
|
|
1123
|
+
// Must happen before instance tags are generated so [position:] can be emitted.
|
|
1124
|
+
const autoPositions = computeAutoPositions(ast);
|
|
1125
|
+
// Add node instances — skip synthetic MAP_ITERATOR instances, strip parent from macro children.
|
|
1126
|
+
// Merge auto-computed positions into instance config (without mutating the AST).
|
|
1123
1127
|
for (const instance of ast.instances) {
|
|
1124
1128
|
if (macroInstanceIds.has(instance.id))
|
|
1125
1129
|
continue;
|
|
1126
|
-
if
|
|
1130
|
+
// Merge auto-position into config if not already set
|
|
1131
|
+
let inst = instance;
|
|
1132
|
+
if (inst.config?.x === undefined || inst.config?.y === undefined) {
|
|
1133
|
+
const autoPos = autoPositions.get(inst.id);
|
|
1134
|
+
if (autoPos) {
|
|
1135
|
+
inst = {
|
|
1136
|
+
...inst,
|
|
1137
|
+
config: {
|
|
1138
|
+
...inst.config,
|
|
1139
|
+
x: inst.config?.x ?? autoPos.x,
|
|
1140
|
+
y: inst.config?.y ?? autoPos.y,
|
|
1141
|
+
},
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
if (macroChildIds.has(inst.id) && inst.parent) {
|
|
1127
1146
|
// Write child @node without parent scope — @map handles it
|
|
1128
|
-
const stripped = { ...
|
|
1147
|
+
const stripped = { ...inst, parent: undefined };
|
|
1129
1148
|
lines.push(generateNodeInstanceTag(stripped));
|
|
1130
1149
|
}
|
|
1131
1150
|
else {
|
|
1132
|
-
lines.push(generateNodeInstanceTag(
|
|
1151
|
+
lines.push(generateNodeInstanceTag(inst));
|
|
1133
1152
|
}
|
|
1134
1153
|
}
|
|
1135
1154
|
// Filter stale macros (e.g. paths whose connections were deleted)
|
|
@@ -1168,27 +1187,13 @@ function generateWorkflowJSDoc(ast, options = {}) {
|
|
|
1168
1187
|
}
|
|
1169
1188
|
}
|
|
1170
1189
|
}
|
|
1171
|
-
//
|
|
1172
|
-
// Uses a left-to-right layout with topological ordering when connections are available.
|
|
1173
|
-
const autoPositions = computeAutoPositions(ast);
|
|
1174
|
-
// Add positions - Start node
|
|
1190
|
+
// Add positions - Start node (virtual, standalone @position)
|
|
1175
1191
|
const startX = ast.ui?.startNode?.x ?? autoPositions.get('Start')?.x;
|
|
1176
1192
|
const startY = ast.ui?.startNode?.y ?? autoPositions.get('Start')?.y;
|
|
1177
1193
|
if (startX !== undefined && startY !== undefined) {
|
|
1178
1194
|
lines.push(` * @position Start ${Math.round(startX)} ${Math.round(startY)}`);
|
|
1179
1195
|
}
|
|
1180
|
-
// Add positions -
|
|
1181
|
-
for (const instance of ast.instances) {
|
|
1182
|
-
const explicitX = instance.config?.x;
|
|
1183
|
-
const explicitY = instance.config?.y;
|
|
1184
|
-
const autoPos = autoPositions.get(instance.id);
|
|
1185
|
-
const x = explicitX ?? autoPos?.x;
|
|
1186
|
-
const y = explicitY ?? autoPos?.y;
|
|
1187
|
-
if (x !== undefined && y !== undefined) {
|
|
1188
|
-
lines.push(` * @position ${instance.id} ${Math.round(x)} ${Math.round(y)}`);
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
// Add positions - Exit node
|
|
1196
|
+
// Add positions - Exit node (virtual, standalone @position)
|
|
1192
1197
|
const exitX = ast.ui?.exitNode?.x ?? autoPositions.get('Exit')?.x;
|
|
1193
1198
|
const exitY = ast.ui?.exitNode?.y ?? autoPositions.get('Exit')?.y;
|
|
1194
1199
|
if (exitX !== undefined && exitY !== undefined) {
|
package/dist/api/patterns.js
CHANGED
|
@@ -48,8 +48,13 @@ export function applyPattern(options) {
|
|
|
48
48
|
conflicts.push(nodeType.name);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
// ── Build @node declarations
|
|
52
|
-
const nodeDeclarations = pattern.instances.map((inst) =>
|
|
51
|
+
// ── Build @node declarations (with inline [position:] when present) ──
|
|
52
|
+
const nodeDeclarations = pattern.instances.map((inst) => {
|
|
53
|
+
const posAttr = inst.config?.x !== undefined && inst.config?.y !== undefined
|
|
54
|
+
? ` [position: ${inst.config.x} ${inst.config.y}]`
|
|
55
|
+
: '';
|
|
56
|
+
return ` * @node ${nodePrefix}${inst.id} ${inst.nodeType}${posAttr}`;
|
|
57
|
+
});
|
|
53
58
|
// ── Build @connect declarations + wiring instructions ───────────────
|
|
54
59
|
const connectDeclarations = [];
|
|
55
60
|
const wiringInstructions = [];
|
|
@@ -85,10 +90,6 @@ export function applyPattern(options) {
|
|
|
85
90
|
connectDeclarations.push(` * @connect ${fromNode}.${conn.from.port} -> ${toNode}.${conn.to.port}`);
|
|
86
91
|
}
|
|
87
92
|
}
|
|
88
|
-
// ── Build @position declarations ────────────────────────────────────
|
|
89
|
-
const positionDeclarations = pattern.instances
|
|
90
|
-
.filter((inst) => inst.config?.x !== undefined && inst.config?.y !== undefined)
|
|
91
|
-
.map((inst) => ` * @position ${nodePrefix}${inst.id} ${inst.config.x} ${inst.config.y}`);
|
|
92
93
|
// ── Generate node type functions (only non-conflicting) ─────────────
|
|
93
94
|
const nodeTypesAdded = [];
|
|
94
95
|
const nodeTypeFunctions = [];
|
|
@@ -103,7 +104,6 @@ export function applyPattern(options) {
|
|
|
103
104
|
`// --- Pattern: ${pattern.name} ${prefix ? `(prefix: ${prefix})` : ''} ---`,
|
|
104
105
|
...nodeDeclarations,
|
|
105
106
|
...connectDeclarations,
|
|
106
|
-
...positionDeclarations,
|
|
107
107
|
];
|
|
108
108
|
// ── Insert into target content ──────────────────────────────────────
|
|
109
109
|
const workflowMatch = targetContent.match(/\/\*\*[\s\S]*?@flowWeaver\s+workflow[\s\S]*?\*\//);
|
|
@@ -250,9 +250,12 @@ export function extractPattern(options) {
|
|
|
250
250
|
lines.push('/**');
|
|
251
251
|
lines.push(` * @flowWeaver pattern`);
|
|
252
252
|
lines.push(` * @name ${patternName}`);
|
|
253
|
-
// Node declarations
|
|
253
|
+
// Node declarations (with inline [position:] when present)
|
|
254
254
|
for (const inst of extractedInstances) {
|
|
255
|
-
|
|
255
|
+
const posAttr = inst.config?.x !== undefined && inst.config?.y !== undefined
|
|
256
|
+
? ` [position: ${inst.config.x} ${inst.config.y}]`
|
|
257
|
+
: '';
|
|
258
|
+
lines.push(` * @node ${inst.id} ${inst.nodeType}${posAttr}`);
|
|
256
259
|
}
|
|
257
260
|
// Internal connections
|
|
258
261
|
for (const conn of internalConnections) {
|
|
@@ -280,12 +283,6 @@ export function extractPattern(options) {
|
|
|
280
283
|
for (const port of [...new Set(outputPorts)]) {
|
|
281
284
|
lines.push(` * @port OUT.${port}`);
|
|
282
285
|
}
|
|
283
|
-
// Positions
|
|
284
|
-
for (const inst of extractedInstances) {
|
|
285
|
-
if (inst.config?.x !== undefined && inst.config?.y !== undefined) {
|
|
286
|
-
lines.push(` * @position ${inst.id} ${inst.config.x} ${inst.config.y}`);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
286
|
lines.push(' */');
|
|
290
287
|
lines.push('function patternPlaceholder() {}');
|
|
291
288
|
// Add node type functions
|
|
@@ -15,6 +15,10 @@ export async function waitForAgent(execute, agentId, context, prompt) {
|
|
|
15
15
|
if (mockResult !== undefined) {
|
|
16
16
|
return { onSuccess: true, onFailure: false, agentResult: mockResult };
|
|
17
17
|
}
|
|
18
|
+
// Mocks section exists but key not found — fail like waitForEvent/invokeWorkflow
|
|
19
|
+
if (mocks?.agents) {
|
|
20
|
+
return { onSuccess: false, onFailure: true, agentResult: {} };
|
|
21
|
+
}
|
|
18
22
|
// 2. Check agent channel (set by executor for pause/resume)
|
|
19
23
|
const channel = globalThis.__fw_agent_channel__;
|
|
20
24
|
if (channel) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Parser for @node declarations using Chevrotain.
|
|
5
5
|
*/
|
|
6
6
|
import { CstParser } from 'chevrotain';
|
|
7
|
-
import { JSDocLexer, NodeTag, Identifier, Dot, Integer, LabelPrefix, ExprPrefix, PortOrderPrefix, PortLabelPrefix, MinimizedKeyword, PullExecutionPrefix, SizePrefix, ColorPrefix, IconPrefix, TagsPrefix, StringLiteral, LBracket, RBracket, Comma, Equals, EventEq, CronEq, MatchEq, TimeoutEq, LimitEq, PeriodEq, allTokens, } from './tokens.js';
|
|
7
|
+
import { JSDocLexer, NodeTag, Identifier, Dot, Integer, LabelPrefix, ExprPrefix, PortOrderPrefix, PortLabelPrefix, MinimizedKeyword, PullExecutionPrefix, SizePrefix, PositionPrefix, ColorPrefix, IconPrefix, TagsPrefix, StringLiteral, LBracket, RBracket, Comma, Equals, EventEq, CronEq, MatchEq, TimeoutEq, LimitEq, PeriodEq, allTokens, } from './tokens.js';
|
|
8
8
|
// =============================================================================
|
|
9
9
|
// Parser Definition
|
|
10
10
|
// =============================================================================
|
|
@@ -48,6 +48,7 @@ class NodeParser extends CstParser {
|
|
|
48
48
|
{ ALT: () => this.SUBRULE(this.minimizedAttr) },
|
|
49
49
|
{ ALT: () => this.SUBRULE(this.pullExecutionAttr) },
|
|
50
50
|
{ ALT: () => this.SUBRULE(this.sizeAttr) },
|
|
51
|
+
{ ALT: () => this.SUBRULE(this.positionAttr) },
|
|
51
52
|
{ ALT: () => this.SUBRULE(this.colorAttr) },
|
|
52
53
|
{ ALT: () => this.SUBRULE(this.iconAttr) },
|
|
53
54
|
{ ALT: () => this.SUBRULE(this.tagsAttr) },
|
|
@@ -140,6 +141,12 @@ class NodeParser extends CstParser {
|
|
|
140
141
|
this.CONSUME(Integer, { LABEL: 'widthValue' });
|
|
141
142
|
this.CONSUME2(Integer, { LABEL: 'heightValue' });
|
|
142
143
|
});
|
|
144
|
+
// position: x y
|
|
145
|
+
positionAttr = this.RULE('positionAttr', () => {
|
|
146
|
+
this.CONSUME(PositionPrefix);
|
|
147
|
+
this.CONSUME(Integer, { LABEL: 'xValue' });
|
|
148
|
+
this.CONSUME2(Integer, { LABEL: 'yValue' });
|
|
149
|
+
});
|
|
143
150
|
// color: "value"
|
|
144
151
|
colorAttr = this.RULE('colorAttr', () => {
|
|
145
152
|
this.CONSUME(ColorPrefix);
|
|
@@ -192,6 +199,7 @@ class NodeVisitor extends BaseVisitor {
|
|
|
192
199
|
let minimized;
|
|
193
200
|
let pullExecution;
|
|
194
201
|
let size;
|
|
202
|
+
let position;
|
|
195
203
|
let color;
|
|
196
204
|
let icon;
|
|
197
205
|
let tags;
|
|
@@ -215,6 +223,8 @@ class NodeVisitor extends BaseVisitor {
|
|
|
215
223
|
pullExecution = attrs.pullExecution;
|
|
216
224
|
if (attrs.size)
|
|
217
225
|
size = attrs.size;
|
|
226
|
+
if (attrs.position)
|
|
227
|
+
position = attrs.position;
|
|
218
228
|
if (attrs.color)
|
|
219
229
|
color = attrs.color;
|
|
220
230
|
if (attrs.icon)
|
|
@@ -234,6 +244,7 @@ class NodeVisitor extends BaseVisitor {
|
|
|
234
244
|
...(minimized && { minimized }),
|
|
235
245
|
...(pullExecution && { pullExecution }),
|
|
236
246
|
...(size && { size }),
|
|
247
|
+
...(position && { position }),
|
|
237
248
|
...(color && { color }),
|
|
238
249
|
...(icon && { icon }),
|
|
239
250
|
...(tags && { tags }),
|
|
@@ -252,6 +263,7 @@ class NodeVisitor extends BaseVisitor {
|
|
|
252
263
|
let minimized;
|
|
253
264
|
let pullExecution;
|
|
254
265
|
let size;
|
|
266
|
+
let position;
|
|
255
267
|
let color;
|
|
256
268
|
let icon;
|
|
257
269
|
let tags;
|
|
@@ -291,6 +303,11 @@ class NodeVisitor extends BaseVisitor {
|
|
|
291
303
|
size = this.visit(attr);
|
|
292
304
|
}
|
|
293
305
|
}
|
|
306
|
+
if (ctx.positionAttr) {
|
|
307
|
+
for (const attr of ctx.positionAttr) {
|
|
308
|
+
position = this.visit(attr);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
294
311
|
if (ctx.colorAttr) {
|
|
295
312
|
for (const attr of ctx.colorAttr) {
|
|
296
313
|
color = this.visit(attr);
|
|
@@ -315,6 +332,7 @@ class NodeVisitor extends BaseVisitor {
|
|
|
315
332
|
minimized,
|
|
316
333
|
pullExecution,
|
|
317
334
|
size,
|
|
335
|
+
position,
|
|
318
336
|
color,
|
|
319
337
|
icon,
|
|
320
338
|
tags,
|
|
@@ -397,6 +415,11 @@ class NodeVisitor extends BaseVisitor {
|
|
|
397
415
|
const height = parseInt(ctx.heightValue[0].image, 10);
|
|
398
416
|
return { width, height };
|
|
399
417
|
}
|
|
418
|
+
positionAttr(ctx) {
|
|
419
|
+
const x = parseInt(ctx.xValue[0].image, 10);
|
|
420
|
+
const y = parseInt(ctx.yValue[0].image, 10);
|
|
421
|
+
return { x, y };
|
|
422
|
+
}
|
|
400
423
|
colorAttr(ctx) {
|
|
401
424
|
return this.unescapeString(ctx.colorValue[0].image);
|
|
402
425
|
}
|
|
@@ -44,6 +44,7 @@ export declare const MergeStrategyPrefix: import("chevrotain").TokenType;
|
|
|
44
44
|
export declare const PullExecutionPrefix: import("chevrotain").TokenType;
|
|
45
45
|
export declare const MinimizedKeyword: import("chevrotain").TokenType;
|
|
46
46
|
export declare const SizePrefix: import("chevrotain").TokenType;
|
|
47
|
+
export declare const PositionPrefix: import("chevrotain").TokenType;
|
|
47
48
|
export declare const ColorPrefix: import("chevrotain").TokenType;
|
|
48
49
|
export declare const IconPrefix: import("chevrotain").TokenType;
|
|
49
50
|
export declare const TagsPrefix: import("chevrotain").TokenType;
|
|
@@ -172,6 +172,10 @@ export const SizePrefix = createToken({
|
|
|
172
172
|
name: 'SizePrefix',
|
|
173
173
|
pattern: /size:/,
|
|
174
174
|
});
|
|
175
|
+
export const PositionPrefix = createToken({
|
|
176
|
+
name: 'PositionPrefix',
|
|
177
|
+
pattern: /position:/,
|
|
178
|
+
});
|
|
175
179
|
export const ColorPrefix = createToken({
|
|
176
180
|
name: 'ColorPrefix',
|
|
177
181
|
pattern: /color:/,
|
|
@@ -356,6 +360,7 @@ export const allTokens = [
|
|
|
356
360
|
MergeStrategyPrefix,
|
|
357
361
|
PullExecutionPrefix,
|
|
358
362
|
SizePrefix,
|
|
363
|
+
PositionPrefix,
|
|
359
364
|
ColorPrefix,
|
|
360
365
|
IconPrefix,
|
|
361
366
|
TagsPrefix,
|