@synergenius/flow-weaver 0.2.1 → 0.4.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/README.md +261 -200
- package/dist/annotation-generator.js +36 -0
- package/dist/api/generate-in-place.js +39 -0
- package/dist/api/generate.js +11 -1
- package/dist/api/manipulation/nodes.js +22 -0
- package/dist/ast/types.d.ts +27 -1
- package/dist/built-in-nodes/index.d.ts +1 -0
- package/dist/built-in-nodes/index.js +1 -0
- package/dist/built-in-nodes/invoke-workflow.js +12 -1
- package/dist/built-in-nodes/mock-types.d.ts +2 -0
- package/dist/built-in-nodes/wait-for-agent.d.ts +13 -0
- package/dist/built-in-nodes/wait-for-agent.js +26 -0
- package/dist/chevrotain-parser/fan-parser.d.ts +38 -0
- package/dist/chevrotain-parser/fan-parser.js +149 -0
- package/dist/chevrotain-parser/grammar-diagrams.d.ts +1 -0
- package/dist/chevrotain-parser/grammar-diagrams.js +3 -0
- package/dist/chevrotain-parser/index.d.ts +3 -1
- package/dist/chevrotain-parser/index.js +3 -1
- package/dist/chevrotain-parser/tokens.d.ts +2 -0
- package/dist/chevrotain-parser/tokens.js +10 -0
- package/dist/cli/commands/diagram.d.ts +2 -1
- package/dist/cli/commands/diagram.js +9 -6
- package/dist/cli/commands/docs.d.ts +11 -0
- package/dist/cli/commands/docs.js +77 -0
- package/dist/cli/commands/run.js +59 -1
- package/dist/cli/flow-weaver.mjs +2447 -594
- package/dist/cli/index.js +40 -2
- package/dist/diagram/geometry.d.ts +9 -4
- package/dist/diagram/geometry.js +262 -31
- package/dist/diagram/html-viewer.d.ts +12 -0
- package/dist/diagram/html-viewer.js +399 -0
- package/dist/diagram/index.d.ts +12 -0
- package/dist/diagram/index.js +22 -0
- package/dist/diagram/renderer.js +137 -116
- package/dist/diagram/types.d.ts +1 -0
- package/dist/doc-metadata/extractors/annotations.js +282 -1
- package/dist/doc-metadata/types.d.ts +6 -0
- package/dist/docs/index.d.ts +54 -0
- package/dist/docs/index.js +256 -0
- package/dist/generator/control-flow.d.ts +13 -0
- package/dist/generator/control-flow.js +74 -0
- package/dist/generator/inngest.js +23 -0
- package/dist/generator/unified.js +122 -2
- package/dist/jsdoc-parser.d.ts +24 -0
- package/dist/jsdoc-parser.js +41 -1
- package/dist/mcp/agent-channel.d.ts +35 -0
- package/dist/mcp/agent-channel.js +61 -0
- package/dist/mcp/run-registry.d.ts +29 -0
- package/dist/mcp/run-registry.js +24 -0
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/tools-diagram.d.ts +1 -1
- package/dist/mcp/tools-diagram.js +15 -7
- package/dist/mcp/tools-docs.d.ts +3 -0
- package/dist/mcp/tools-docs.js +62 -0
- package/dist/mcp/tools-editor.js +77 -3
- package/dist/mcp/tools-query.js +3 -1
- package/dist/mcp/workflow-executor.d.ts +28 -0
- package/dist/mcp/workflow-executor.js +66 -3
- package/dist/parser.d.ts +8 -0
- package/dist/parser.js +100 -0
- package/dist/runtime/ExecutionContext.d.ts +2 -0
- package/dist/runtime/ExecutionContext.js +2 -0
- package/dist/runtime/events.d.ts +1 -1
- package/dist/sugar-optimizer.js +28 -3
- package/dist/validator.d.ts +8 -0
- package/dist/validator.js +92 -0
- package/docs/reference/advanced-annotations.md +431 -0
- package/docs/reference/built-in-nodes.md +225 -0
- package/docs/reference/cli-reference.md +882 -0
- package/docs/reference/compilation.md +351 -0
- package/docs/reference/concepts.md +400 -0
- package/docs/reference/debugging.md +255 -0
- package/docs/reference/deployment.md +207 -0
- package/docs/reference/error-codes.md +686 -0
- package/docs/reference/export-interface.md +229 -0
- package/docs/reference/iterative-development.md +186 -0
- package/docs/reference/jsdoc-grammar.md +471 -0
- package/docs/reference/marketplace.md +205 -0
- package/docs/reference/node-conversion.md +308 -0
- package/docs/reference/patterns.md +161 -0
- package/docs/reference/scaffold.md +160 -0
- package/docs/reference/tutorial.md +519 -0
- package/package.json +10 -4
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Flow Weaver Tutorial
|
|
3
|
+
description: Step-by-step guide to building your first Flow Weaver workflow
|
|
4
|
+
keywords: [tutorial, first workflow, getting started, scaffold, compile, run, validate, beginner]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Overview
|
|
8
|
+
|
|
9
|
+
In this tutorial you will build a **data processing workflow** that takes raw records, validates them, enriches them with computed fields, and scores each record. The finished workflow chains three node types together in a linear pipeline:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Start -> validator -> enricher -> scorer -> Exit
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**What you will learn:**
|
|
16
|
+
|
|
17
|
+
- Scaffolding a workflow from a template
|
|
18
|
+
- Writing node type functions with `@flowWeaver nodeType` annotations
|
|
19
|
+
- Wiring nodes together with `@flowWeaver workflow`, `@node`, and `@connect`
|
|
20
|
+
- Validating, compiling, and running the generated code
|
|
21
|
+
- Debugging when things go wrong
|
|
22
|
+
|
|
23
|
+
# Step 1: Scaffold
|
|
24
|
+
|
|
25
|
+
Use the CLI to generate a starting point:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
flow-weaver create workflow sequential my-workflow.ts
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This creates `my-workflow.ts` with a linear pipeline skeleton. Preview before writing:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
flow-weaver create workflow sequential my-workflow.ts --preview
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Open the generated file. It contains a placeholder workflow function with a single node. You will replace and expand it in the following steps.
|
|
38
|
+
|
|
39
|
+
# Step 2: Define Node Types
|
|
40
|
+
|
|
41
|
+
Node types are plain TypeScript functions annotated with `@flowWeaver nodeType`. Each input is declared with `@input` and each output with `@output` in the JSDoc block. Inputs become **direct parameters** (not wrapped in an object).
|
|
42
|
+
|
|
43
|
+
Add the following three node type functions to `my-workflow.ts`:
|
|
44
|
+
|
|
45
|
+
## 2a. Validator
|
|
46
|
+
|
|
47
|
+
Checks that the incoming record has the required fields and that values are within acceptable ranges. Returns the validated record on success, or signals failure.
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
/**
|
|
51
|
+
* @flowWeaver nodeType
|
|
52
|
+
* @label Validate Record
|
|
53
|
+
* @input record - Raw record to validate
|
|
54
|
+
* @output validated - The validated record
|
|
55
|
+
*/
|
|
56
|
+
function validateRecord(
|
|
57
|
+
execute: boolean,
|
|
58
|
+
record: { name: string; age: number; email: string }
|
|
59
|
+
): {
|
|
60
|
+
onSuccess: boolean;
|
|
61
|
+
onFailure: boolean;
|
|
62
|
+
validated: { name: string; age: number; email: string } | null;
|
|
63
|
+
} {
|
|
64
|
+
if (!execute) return { onSuccess: false, onFailure: false, validated: null };
|
|
65
|
+
try {
|
|
66
|
+
if (!record.name || !record.email || record.age < 0 || record.age > 150) {
|
|
67
|
+
return { onSuccess: false, onFailure: true, validated: null };
|
|
68
|
+
}
|
|
69
|
+
return { onSuccess: true, onFailure: false, validated: record };
|
|
70
|
+
} catch {
|
|
71
|
+
return { onSuccess: false, onFailure: true, validated: null };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 2b. Enricher
|
|
77
|
+
|
|
78
|
+
Adds computed fields to the validated record: a normalized name and an age bracket.
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
/**
|
|
82
|
+
* @flowWeaver nodeType
|
|
83
|
+
* @label Enrich Record
|
|
84
|
+
* @input record - Validated record to enrich
|
|
85
|
+
* @output enriched - Record with added fields
|
|
86
|
+
*/
|
|
87
|
+
function enrichRecord(
|
|
88
|
+
execute: boolean,
|
|
89
|
+
record: { name: string; age: number; email: string }
|
|
90
|
+
): {
|
|
91
|
+
onSuccess: boolean;
|
|
92
|
+
onFailure: boolean;
|
|
93
|
+
enriched: {
|
|
94
|
+
name: string;
|
|
95
|
+
age: number;
|
|
96
|
+
email: string;
|
|
97
|
+
normalizedName: string;
|
|
98
|
+
ageBracket: string;
|
|
99
|
+
} | null;
|
|
100
|
+
} {
|
|
101
|
+
if (!execute) return { onSuccess: false, onFailure: false, enriched: null };
|
|
102
|
+
const normalizedName = record.name.trim().toLowerCase();
|
|
103
|
+
const ageBracket = record.age < 18 ? 'minor' : record.age < 65 ? 'adult' : 'senior';
|
|
104
|
+
return {
|
|
105
|
+
onSuccess: true,
|
|
106
|
+
onFailure: false,
|
|
107
|
+
enriched: { ...record, normalizedName, ageBracket },
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## 2c. Scorer
|
|
113
|
+
|
|
114
|
+
Assigns a simple numeric score based on the enriched record.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
/**
|
|
118
|
+
* @flowWeaver nodeType
|
|
119
|
+
* @label Score Record
|
|
120
|
+
* @input record - Enriched record to score
|
|
121
|
+
* @output score - Computed score
|
|
122
|
+
* @output summary - Human-readable summary
|
|
123
|
+
*/
|
|
124
|
+
function scoreRecord(
|
|
125
|
+
execute: boolean,
|
|
126
|
+
record: {
|
|
127
|
+
name: string;
|
|
128
|
+
age: number;
|
|
129
|
+
email: string;
|
|
130
|
+
normalizedName: string;
|
|
131
|
+
ageBracket: string;
|
|
132
|
+
}
|
|
133
|
+
): {
|
|
134
|
+
onSuccess: boolean;
|
|
135
|
+
onFailure: boolean;
|
|
136
|
+
score: number;
|
|
137
|
+
summary: string;
|
|
138
|
+
} {
|
|
139
|
+
if (!execute) return { onSuccess: false, onFailure: false, score: 0, summary: '' };
|
|
140
|
+
let score = 50;
|
|
141
|
+
if (record.email.endsWith('.edu')) score += 20;
|
|
142
|
+
if (record.ageBracket === 'adult') score += 10;
|
|
143
|
+
if (record.normalizedName.length > 3) score += 5;
|
|
144
|
+
const summary = `${record.name}: score ${score} (${record.ageBracket})`;
|
|
145
|
+
return { onSuccess: true, onFailure: false, score, summary };
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## 2d. Alternative: Import External Functions
|
|
150
|
+
|
|
151
|
+
Instead of writing custom node types, you can import existing functions from npm packages or local modules using `@fwImport`:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
/**
|
|
155
|
+
* @flowWeaver workflow
|
|
156
|
+
* @fwImport npm/validator/isEmail isEmail from "validator"
|
|
157
|
+
* @node emailCheck npm/validator/isEmail
|
|
158
|
+
* @connect Start.email -> emailCheck.str
|
|
159
|
+
*/
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
This is useful when:
|
|
163
|
+
|
|
164
|
+
- The function already exists and does what you need
|
|
165
|
+
- You want to use popular libraries (lodash, date-fns, etc.) directly
|
|
166
|
+
- You don't want to write wrapper boilerplate
|
|
167
|
+
|
|
168
|
+
Port types are inferred from TypeScript definitions. See `flow-weaver docs jsdoc-grammar` for full syntax.
|
|
169
|
+
|
|
170
|
+
After adding each function, validate to catch errors early:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
flow-weaver validate my-workflow.ts
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
# Step 3: Wire the Workflow
|
|
177
|
+
|
|
178
|
+
Below the node type functions, add the workflow export. The `@flowWeaver workflow` JSDoc block declares node instances with `@node`, connects ports with `@connect`, and defines positions with `@position`.
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
/**
|
|
182
|
+
* @flowWeaver workflow
|
|
183
|
+
* @description Validate, enrich, and score a data record
|
|
184
|
+
* @param record - Raw input record
|
|
185
|
+
* @returns score - Computed score
|
|
186
|
+
* @returns summary - Human-readable summary
|
|
187
|
+
* @node validator validateRecord
|
|
188
|
+
* @node enricher enrichRecord
|
|
189
|
+
* @node scorer scoreRecord
|
|
190
|
+
* @connect Start.record -> validator.record
|
|
191
|
+
* @connect validator.onSuccess -> enricher.execute
|
|
192
|
+
* @connect validator.validated -> enricher.record
|
|
193
|
+
* @connect enricher.onSuccess -> scorer.execute
|
|
194
|
+
* @connect enricher.enriched -> scorer.record
|
|
195
|
+
* @connect scorer.score -> Exit.score
|
|
196
|
+
* @connect scorer.summary -> Exit.summary
|
|
197
|
+
* @connect scorer.onSuccess -> Exit.onSuccess
|
|
198
|
+
* @connect scorer.onFailure -> Exit.onFailure
|
|
199
|
+
* @position validator -180 0
|
|
200
|
+
* @position enricher 0 0
|
|
201
|
+
* @position scorer 180 0
|
|
202
|
+
*/
|
|
203
|
+
export function processRecord(
|
|
204
|
+
execute: boolean,
|
|
205
|
+
params: { record: { name: string; age: number; email: string } }
|
|
206
|
+
): { onSuccess: boolean; onFailure: boolean; score: number; summary: string } {
|
|
207
|
+
throw new Error('Not implemented');
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Key points:
|
|
212
|
+
|
|
213
|
+
- `@node validator validateRecord` creates an instance named `validator` of node type `validateRecord`.
|
|
214
|
+
- `@connect validator.onSuccess -> enricher.execute` chains the success STEP port of the validator to the execute STEP port of the enricher, so the enricher only runs when validation passes.
|
|
215
|
+
- `Start` and `Exit` are reserved pseudo-nodes. `Start` ports come from `@param` tags, `Exit` ports come from `@returns` tags.
|
|
216
|
+
- The function body is a placeholder -- the compiler generates the real execution code.
|
|
217
|
+
|
|
218
|
+
# Step 4: Validate
|
|
219
|
+
|
|
220
|
+
Run the validator to check for annotation errors, missing connections, and type mismatches:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
flow-weaver validate my-workflow.ts
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
If everything is correct you will see a success message. If there are issues, the output describes each problem. Common things to check:
|
|
227
|
+
|
|
228
|
+
- Every `@input` has a corresponding function parameter
|
|
229
|
+
- Every `@output` appears in the return type
|
|
230
|
+
- Port names in `@connect` match the declared `@input` / `@output` names exactly (case-sensitive)
|
|
231
|
+
- STEP ports (`execute`, `onSuccess`, `onFailure`) only connect to other STEP ports
|
|
232
|
+
|
|
233
|
+
For machine-readable output (useful in CI):
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
flow-weaver validate my-workflow.ts --json
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
# Step 5: Compile
|
|
240
|
+
|
|
241
|
+
Generate the executable code:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
flow-weaver compile my-workflow.ts
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
This compiles the workflow in-place, modifying the source file directly. The compiled file contains:
|
|
248
|
+
|
|
249
|
+
- A runtime execution context class
|
|
250
|
+
- Your node type functions (copied verbatim)
|
|
251
|
+
- The `processRecord` export function wired with real execution logic
|
|
252
|
+
|
|
253
|
+
The generated function has the same signature as your placeholder, so existing imports continue to work.
|
|
254
|
+
|
|
255
|
+
For production builds (no debug events):
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
flow-weaver compile my-workflow.ts --production
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
# Step 6: Run
|
|
262
|
+
|
|
263
|
+
Import and call the generated function from any TypeScript or JavaScript file:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { processRecord } from './my-workflow';
|
|
267
|
+
|
|
268
|
+
const result = processRecord(true, {
|
|
269
|
+
record: { name: 'Alice Smith', age: 30, email: 'alice@university.edu' },
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
console.log(result);
|
|
273
|
+
// {
|
|
274
|
+
// onSuccess: true,
|
|
275
|
+
// onFailure: false,
|
|
276
|
+
// score: 85,
|
|
277
|
+
// summary: "Alice Smith: score 85 (adult)"
|
|
278
|
+
// }
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
The first argument (`execute: boolean`) controls whether the workflow actually runs. Pass `true` for normal execution.
|
|
282
|
+
|
|
283
|
+
Test edge cases:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
// Invalid record -- validator will fail, enricher and scorer won't run
|
|
287
|
+
const bad = processRecord(true, {
|
|
288
|
+
record: { name: '', age: -5, email: '' },
|
|
289
|
+
});
|
|
290
|
+
console.log(bad.onSuccess); // false
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
# Step 7: Debug
|
|
294
|
+
|
|
295
|
+
When the workflow does not behave as expected, use these techniques:
|
|
296
|
+
|
|
297
|
+
## Verbose validation
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
flow-weaver validate my-workflow.ts --verbose
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Shows detailed information about parsed annotations, port types, and connection resolution.
|
|
304
|
+
|
|
305
|
+
## Inspect generated code
|
|
306
|
+
|
|
307
|
+
Open the compiled source file and read the execution logic. Each node call is visible in sequence, making it straightforward to trace how data flows between ports.
|
|
308
|
+
|
|
309
|
+
## Describe the workflow structure
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
flow-weaver describe my-workflow.ts
|
|
313
|
+
flow-weaver describe my-workflow.ts --format mermaid
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Outputs the workflow graph as JSON or as a Mermaid diagram for visual inspection.
|
|
317
|
+
|
|
318
|
+
## WebSocket runtime debugger
|
|
319
|
+
|
|
320
|
+
For runtime debugging, compile without the `--production` flag and set the debug environment variable:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
FLOW_WEAVER_DEBUG=ws://localhost:9000 node my-workflow.generated.js
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Debug events (`STATUS_CHANGED`, `VARIABLE_SET`, `WORKFLOW_COMPLETED`) are sent over WebSocket so you can observe execution in real time.
|
|
327
|
+
|
|
328
|
+
## Common issues
|
|
329
|
+
|
|
330
|
+
| Symptom | Likely cause |
|
|
331
|
+
| ----------------------------- | ------------------------------------------------- |
|
|
332
|
+
| Output is `null` or `0` | Exit port not connected, or upstream node failed |
|
|
333
|
+
| Node never executes | Missing `@connect` to its `execute` STEP port |
|
|
334
|
+
| Validation error on port name | Typo in `@connect` -- names are case-sensitive |
|
|
335
|
+
| `onSuccess` is always `false` | Check the `if (!execute)` guard and failure paths |
|
|
336
|
+
|
|
337
|
+
# Complete Example
|
|
338
|
+
|
|
339
|
+
Here is the full `my-workflow.ts` with all pieces together:
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
// =============================================================================
|
|
343
|
+
// Node Types
|
|
344
|
+
// =============================================================================
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* @flowWeaver nodeType
|
|
348
|
+
* @label Validate Record
|
|
349
|
+
* @input record - Raw record to validate
|
|
350
|
+
* @output validated - The validated record
|
|
351
|
+
*/
|
|
352
|
+
function validateRecord(
|
|
353
|
+
execute: boolean,
|
|
354
|
+
record: { name: string; age: number; email: string }
|
|
355
|
+
): {
|
|
356
|
+
onSuccess: boolean;
|
|
357
|
+
onFailure: boolean;
|
|
358
|
+
validated: { name: string; age: number; email: string } | null;
|
|
359
|
+
} {
|
|
360
|
+
if (!execute) return { onSuccess: false, onFailure: false, validated: null };
|
|
361
|
+
try {
|
|
362
|
+
if (!record.name || !record.email || record.age < 0 || record.age > 150) {
|
|
363
|
+
return { onSuccess: false, onFailure: true, validated: null };
|
|
364
|
+
}
|
|
365
|
+
return { onSuccess: true, onFailure: false, validated: record };
|
|
366
|
+
} catch {
|
|
367
|
+
return { onSuccess: false, onFailure: true, validated: null };
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* @flowWeaver nodeType
|
|
373
|
+
* @label Enrich Record
|
|
374
|
+
* @input record - Validated record to enrich
|
|
375
|
+
* @output enriched - Record with added fields
|
|
376
|
+
*/
|
|
377
|
+
function enrichRecord(
|
|
378
|
+
execute: boolean,
|
|
379
|
+
record: { name: string; age: number; email: string }
|
|
380
|
+
): {
|
|
381
|
+
onSuccess: boolean;
|
|
382
|
+
onFailure: boolean;
|
|
383
|
+
enriched: {
|
|
384
|
+
name: string;
|
|
385
|
+
age: number;
|
|
386
|
+
email: string;
|
|
387
|
+
normalizedName: string;
|
|
388
|
+
ageBracket: string;
|
|
389
|
+
} | null;
|
|
390
|
+
} {
|
|
391
|
+
if (!execute) return { onSuccess: false, onFailure: false, enriched: null };
|
|
392
|
+
const normalizedName = record.name.trim().toLowerCase();
|
|
393
|
+
const ageBracket = record.age < 18 ? 'minor' : record.age < 65 ? 'adult' : 'senior';
|
|
394
|
+
return {
|
|
395
|
+
onSuccess: true,
|
|
396
|
+
onFailure: false,
|
|
397
|
+
enriched: { ...record, normalizedName, ageBracket },
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* @flowWeaver nodeType
|
|
403
|
+
* @label Score Record
|
|
404
|
+
* @input record - Enriched record to score
|
|
405
|
+
* @output score - Computed score
|
|
406
|
+
* @output summary - Human-readable summary
|
|
407
|
+
*/
|
|
408
|
+
function scoreRecord(
|
|
409
|
+
execute: boolean,
|
|
410
|
+
record: {
|
|
411
|
+
name: string;
|
|
412
|
+
age: number;
|
|
413
|
+
email: string;
|
|
414
|
+
normalizedName: string;
|
|
415
|
+
ageBracket: string;
|
|
416
|
+
}
|
|
417
|
+
): {
|
|
418
|
+
onSuccess: boolean;
|
|
419
|
+
onFailure: boolean;
|
|
420
|
+
score: number;
|
|
421
|
+
summary: string;
|
|
422
|
+
} {
|
|
423
|
+
if (!execute) return { onSuccess: false, onFailure: false, score: 0, summary: '' };
|
|
424
|
+
let score = 50;
|
|
425
|
+
if (record.email.endsWith('.edu')) score += 20;
|
|
426
|
+
if (record.ageBracket === 'adult') score += 10;
|
|
427
|
+
if (record.normalizedName.length > 3) score += 5;
|
|
428
|
+
const summary = `${record.name}: score ${score} (${record.ageBracket})`;
|
|
429
|
+
return { onSuccess: true, onFailure: false, score, summary };
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// =============================================================================
|
|
433
|
+
// Workflow
|
|
434
|
+
// =============================================================================
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* @flowWeaver workflow
|
|
438
|
+
* @description Validate, enrich, and score a data record
|
|
439
|
+
* @param record - Raw input record
|
|
440
|
+
* @returns score - Computed score
|
|
441
|
+
* @returns summary - Human-readable summary
|
|
442
|
+
* @node validator validateRecord
|
|
443
|
+
* @node enricher enrichRecord
|
|
444
|
+
* @node scorer scoreRecord
|
|
445
|
+
* @connect Start.record -> validator.record
|
|
446
|
+
* @connect validator.onSuccess -> enricher.execute
|
|
447
|
+
* @connect validator.validated -> enricher.record
|
|
448
|
+
* @connect enricher.onSuccess -> scorer.execute
|
|
449
|
+
* @connect enricher.enriched -> scorer.record
|
|
450
|
+
* @connect scorer.score -> Exit.score
|
|
451
|
+
* @connect scorer.summary -> Exit.summary
|
|
452
|
+
* @connect scorer.onSuccess -> Exit.onSuccess
|
|
453
|
+
* @connect scorer.onFailure -> Exit.onFailure
|
|
454
|
+
* @position validator -180 0
|
|
455
|
+
* @position enricher 0 0
|
|
456
|
+
* @position scorer 180 0
|
|
457
|
+
*/
|
|
458
|
+
export function processRecord(
|
|
459
|
+
execute: boolean,
|
|
460
|
+
params: { record: { name: string; age: number; email: string } }
|
|
461
|
+
): { onSuccess: boolean; onFailure: boolean; score: number; summary: string } {
|
|
462
|
+
throw new Error('Not implemented');
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
## Running the complete example
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
# Validate
|
|
470
|
+
flow-weaver validate my-workflow.ts
|
|
471
|
+
|
|
472
|
+
# Compile
|
|
473
|
+
flow-weaver compile my-workflow.ts
|
|
474
|
+
|
|
475
|
+
# Run (from another file or a script)
|
|
476
|
+
npx ts-node -e "
|
|
477
|
+
const { processRecord } = require('./my-workflow.generated');
|
|
478
|
+
const result = processRecord(true, {
|
|
479
|
+
record: { name: 'Alice Smith', age: 30, email: 'alice@university.edu' }
|
|
480
|
+
});
|
|
481
|
+
console.log(JSON.stringify(result, null, 2));
|
|
482
|
+
"
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
# Alternative: Dev Mode
|
|
486
|
+
|
|
487
|
+
Instead of running validate, compile, and run separately, use `flow-weaver dev` to do all three in a single watch loop:
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
flow-weaver dev my-workflow.ts --params '{"record": {"name": "Alice", "age": 30, "email": "alice@edu.com"}}'
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
This watches for file changes, recompiles, and re-runs automatically.
|
|
494
|
+
|
|
495
|
+
# Generate a Diagram
|
|
496
|
+
|
|
497
|
+
Visualize your workflow as an SVG diagram:
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
flow-weaver diagram my-workflow.ts -o my-workflow.svg
|
|
501
|
+
flow-weaver diagram my-workflow.ts --theme light -o my-workflow.svg
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
# Next Steps
|
|
505
|
+
|
|
506
|
+
Now that you have a working workflow, explore these topics to go further:
|
|
507
|
+
|
|
508
|
+
- **CLI Reference** (`flow-weaver docs cli-reference`) -- Complete reference for all CLI commands and flags
|
|
509
|
+
- **Advanced Annotations** (`flow-weaver docs advanced-annotations`) -- Pull execution, merge strategies, auto-connect, path/map sugar
|
|
510
|
+
- **Compilation** (`flow-weaver docs compilation`) -- TypeScript and Inngest compilation targets, production mode, serve handlers
|
|
511
|
+
- **Deployment** (`flow-weaver docs deployment`) -- Export to Lambda, Vercel, Cloudflare, Inngest; HTTP serve mode
|
|
512
|
+
- **Built-in Nodes** (`flow-weaver docs built-in-nodes`) -- delay, waitForEvent, invokeWorkflow nodes and the mock system for testing
|
|
513
|
+
- **Marketplace** (`flow-weaver docs marketplace`) -- Install and publish reusable node type packages
|
|
514
|
+
- **Patterns** (`flow-weaver docs patterns`) -- Extract reusable workflow fragments and apply them across projects
|
|
515
|
+
- **Scoped ports and forEach** (`flow-weaver docs export-interface`) -- Iterate over arrays using scoped ports and callback parameters
|
|
516
|
+
- **Expression nodes** (`flow-weaver docs node-conversion`) -- Write pure functions without `execute`/`onSuccess`/`onFailure` boilerplate
|
|
517
|
+
- **Scaffolding templates** (`flow-weaver docs scaffold`) -- Generate workflows from templates like `sequential`, `foreach`, `conditional`, and more
|
|
518
|
+
- **Debugging** (`flow-weaver docs debugging`) -- WebSocket debugger, validation diagnostics, and error resolution
|
|
519
|
+
- **JSDoc grammar** (`flow-weaver docs jsdoc-grammar`) -- Full annotation syntax reference including metadata brackets, scope clauses, and positioning
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synergenius/flow-weaver",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Deterministic workflow compiler for AI agents. Compiles to standalone TypeScript, no runtime dependencies.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"postbuild": "npx tsx scripts/postbuild.ts && npm run generate:docs",
|
|
48
48
|
"generate:docs": "tsx scripts/generate-docs.ts",
|
|
49
49
|
"generate:docs:check": "tsx scripts/generate-docs.ts --check",
|
|
50
|
+
"release": "tsx scripts/release.ts",
|
|
50
51
|
"build:cli": "npx tsx scripts/build-cli.ts",
|
|
51
52
|
"watch": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental",
|
|
52
53
|
"test": "vitest run",
|
|
@@ -64,9 +65,14 @@
|
|
|
64
65
|
"keywords": [
|
|
65
66
|
"flow-weaver",
|
|
66
67
|
"workflow",
|
|
68
|
+
"ai-agent",
|
|
69
|
+
"llm",
|
|
70
|
+
"mcp",
|
|
71
|
+
"deterministic",
|
|
67
72
|
"typescript",
|
|
68
|
-
"
|
|
69
|
-
"
|
|
73
|
+
"compiler",
|
|
74
|
+
"inngest",
|
|
75
|
+
"serverless"
|
|
70
76
|
],
|
|
71
77
|
"author": "Ricardo José Horta Morais",
|
|
72
78
|
"license": "SEE LICENSE IN LICENSE",
|