@synergenius/flow-weaver 0.27.5 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/generate-in-place.js +54 -0
- package/dist/api/generate.js +20 -2
- package/dist/api/query.d.ts +3 -1
- package/dist/api/query.js +25 -1
- package/dist/ast/types.d.ts +7 -1
- package/dist/built-in-nodes/generated-registry.d.ts +9 -0
- package/dist/built-in-nodes/generated-registry.js +299 -0
- package/dist/cli/commands/init-personas.js +8 -8
- package/dist/cli/commands/init.js +18 -12
- package/dist/cli/commands/run.js +6 -0
- package/dist/cli/flow-weaver.mjs +533 -74
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +1 -1
- package/dist/generator/scope-function-generator.js +69 -43
- package/dist/parser.js +56 -12
- package/package.json +4 -2
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.29.0";
|
|
2
2
|
//# sourceMappingURL=generated-version.d.ts.map
|
|
@@ -187,18 +187,35 @@ export function generateScopeFunctionClosure(scopeName, parentNodeId, parentNode
|
|
|
187
187
|
}
|
|
188
188
|
const safeChildId = toValidIdentifier(child.id);
|
|
189
189
|
const awaitPrefix = isAsync ? 'await ' : '';
|
|
190
|
+
const emitDebugHooks = !production;
|
|
191
|
+
// Indentation increases when debug hooks wrap the child block
|
|
192
|
+
let childIndent = ' ';
|
|
190
193
|
lines.push(``);
|
|
191
194
|
lines.push(` // Execute: ${child.id} (${child.nodeType})`);
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
195
|
+
// Debug controller: beforeNode hook for scoped children
|
|
196
|
+
// When enabled, wraps the child execution so breakpoints can pause on scoped nodes.
|
|
197
|
+
if (emitDebugHooks) {
|
|
198
|
+
const awaitHook = isAsync ? 'await ' : '';
|
|
199
|
+
// Hoist Idx declaration before the if block so it stays in scope after.
|
|
200
|
+
// Initialize to -1 so getVariable can still read checkpointed values when beforeNode skips.
|
|
201
|
+
lines.push(` let ${safeChildId}Idx: number = -1;`);
|
|
202
|
+
lines.push(` if (${awaitHook}__ctrl__.beforeNode('${child.id}', scopedCtx)) {`);
|
|
203
|
+
childIndent = ' ';
|
|
204
|
+
}
|
|
205
|
+
lines.push(`${childIndent}scopedCtx.checkAborted('${child.id}');`);
|
|
206
|
+
// Use assignment when debug hooks hoist the declaration, const otherwise
|
|
207
|
+
const idxDecl = emitDebugHooks ? '' : 'const ';
|
|
208
|
+
lines.push(`${childIndent}${idxDecl}${safeChildId}Idx = scopedCtx.addExecution('${child.id}');`);
|
|
209
|
+
lines.push(`${childIndent}if (typeof globalThis !== 'undefined') (globalThis as unknown as { __fw_current_node_id__?: string }).__fw_current_node_id__ = '${child.id}';`);
|
|
210
|
+
lines.push(`${childIndent}${awaitPrefix}scopedCtx.sendStatusChangedEvent({`);
|
|
211
|
+
lines.push(`${childIndent} nodeTypeName: '${child.nodeType}',`);
|
|
212
|
+
lines.push(`${childIndent} id: '${child.id}',`);
|
|
213
|
+
lines.push(`${childIndent} executionIndex: ${safeChildId}Idx,`);
|
|
214
|
+
lines.push(`${childIndent} status: 'RUNNING',`);
|
|
215
|
+
lines.push(`${childIndent}});`);
|
|
216
|
+
lines.push(`${childIndent}try {`);
|
|
217
|
+
// Inner indentation: inside try block (childIndent + 2 spaces for try body)
|
|
218
|
+
const tryIndent = `${childIndent} `;
|
|
202
219
|
// Pre-handle connections from parent scoped OUTPUT ports with correct index variables
|
|
203
220
|
const argLines = [];
|
|
204
221
|
const getCall = isAsync ? 'await scopedCtx.getVariable' : 'scopedCtx.getVariable';
|
|
@@ -218,9 +235,9 @@ export function generateScopeFunctionClosure(scopeName, parentNodeId, parentNode
|
|
|
218
235
|
const portType = targetPortDef
|
|
219
236
|
? mapToTypeScript(targetPortDef.dataType, targetPortDef.tsType)
|
|
220
237
|
: 'unknown';
|
|
221
|
-
argLines.push(
|
|
238
|
+
argLines.push(`${tryIndent}const ${varName} = ${getCall}({ id: '${parentNodeId}', portName: '${conn.from.port}', executionIndex: ${scopeParamIdxVar} }) as ${portType};`);
|
|
222
239
|
// Emit VARIABLE_SET for the child's INPUT port so breakpoints and inspection work
|
|
223
|
-
argLines.push(
|
|
240
|
+
argLines.push(`${tryIndent}${childSetCall}({ id: '${child.id}', portName: '${targetPort}', executionIndex: ${safeChildId}Idx, nodeTypeName: '${child.nodeType}' }, ${varName});`);
|
|
224
241
|
preHandledPorts.add(targetPort);
|
|
225
242
|
}
|
|
226
243
|
});
|
|
@@ -230,7 +247,7 @@ export function generateScopeFunctionClosure(scopeName, parentNodeId, parentNode
|
|
|
230
247
|
workflow: scopeWorkflow,
|
|
231
248
|
id: child.id,
|
|
232
249
|
lines: argLines,
|
|
233
|
-
indent:
|
|
250
|
+
indent: tryIndent,
|
|
234
251
|
getCall,
|
|
235
252
|
isAsync,
|
|
236
253
|
instanceParent: child.parent ? `${child.parent.id}.${child.parent.scope}` : undefined,
|
|
@@ -245,11 +262,11 @@ export function generateScopeFunctionClosure(scopeName, parentNodeId, parentNode
|
|
|
245
262
|
// Call the child node function
|
|
246
263
|
if (childNodeType.expression) {
|
|
247
264
|
// Expression nodes use original signature (positional args, no execute)
|
|
248
|
-
lines.push(
|
|
265
|
+
lines.push(`${tryIndent}const ${safeChildId}Result = ${awaitPrefix}${child.nodeType}(${args.join(', ')});`);
|
|
249
266
|
}
|
|
250
267
|
else {
|
|
251
268
|
// Regular node call with positional arguments
|
|
252
|
-
lines.push(
|
|
269
|
+
lines.push(`${tryIndent}const ${safeChildId}Result = ${awaitPrefix}${child.nodeType}(${args.join(', ')});`);
|
|
253
270
|
}
|
|
254
271
|
// Store outputs (including onSuccess/onFailure for debugging)
|
|
255
272
|
// Expression nodes don't return onSuccess/onFailure — hardcode them
|
|
@@ -258,48 +275,57 @@ export function generateScopeFunctionClosure(scopeName, parentNodeId, parentNode
|
|
|
258
275
|
const portDef = childNodeType.outputs[outPort];
|
|
259
276
|
if (portDef.failure || isFailurePort(outPort)) {
|
|
260
277
|
// Failure ports always false on success (expression nodes always succeed)
|
|
261
|
-
lines.push(
|
|
278
|
+
lines.push(`${tryIndent}${childSetCall}({ id: '${child.id}', portName: '${outPort}', executionIndex: ${safeChildId}Idx, nodeTypeName: '${child.nodeType}' }, false);`);
|
|
262
279
|
}
|
|
263
280
|
else if (portDef.isControlFlow || isSuccessPort(outPort)) {
|
|
264
281
|
// Success control flow ports always true (expression nodes always succeed)
|
|
265
|
-
lines.push(
|
|
282
|
+
lines.push(`${tryIndent}${childSetCall}({ id: '${child.id}', portName: '${outPort}', executionIndex: ${safeChildId}Idx, nodeTypeName: '${child.nodeType}' }, true);`);
|
|
266
283
|
}
|
|
267
284
|
else {
|
|
268
285
|
// Data outputs read from result object
|
|
269
|
-
lines.push(
|
|
286
|
+
lines.push(`${tryIndent}${childSetCall}({ id: '${child.id}', portName: '${outPort}', executionIndex: ${safeChildId}Idx, nodeTypeName: '${child.nodeType}' }, ${safeChildId}Result.${outPort});`);
|
|
270
287
|
}
|
|
271
288
|
});
|
|
272
289
|
}
|
|
273
290
|
else {
|
|
274
291
|
Object.keys(childNodeType.outputs || {}).forEach((outPort) => {
|
|
275
|
-
lines.push(
|
|
292
|
+
lines.push(`${tryIndent}${childSetCall}({ id: '${child.id}', portName: '${outPort}', executionIndex: ${safeChildId}Idx, nodeTypeName: '${child.nodeType}' }, ${safeChildId}Result.${outPort});`);
|
|
276
293
|
});
|
|
277
294
|
}
|
|
278
295
|
// Add SUCCEEDED status event
|
|
279
|
-
lines.push(
|
|
280
|
-
lines.push(
|
|
281
|
-
lines.push(
|
|
282
|
-
lines.push(
|
|
283
|
-
lines.push(
|
|
284
|
-
lines.push(
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
lines.push(
|
|
291
|
-
lines.push(
|
|
292
|
-
lines.push(`
|
|
293
|
-
lines.push(
|
|
294
|
-
lines.push(
|
|
295
|
-
lines.push(
|
|
296
|
-
lines.push(
|
|
297
|
-
lines.push(
|
|
298
|
-
lines.push(
|
|
299
|
-
lines.push(`
|
|
300
|
-
lines.push(
|
|
301
|
-
lines.push(
|
|
302
|
-
lines.push(
|
|
296
|
+
lines.push(`${tryIndent}${awaitPrefix}scopedCtx.sendStatusChangedEvent({`);
|
|
297
|
+
lines.push(`${tryIndent} nodeTypeName: '${child.nodeType}',`);
|
|
298
|
+
lines.push(`${tryIndent} id: '${child.id}',`);
|
|
299
|
+
lines.push(`${tryIndent} executionIndex: ${safeChildId}Idx,`);
|
|
300
|
+
lines.push(`${tryIndent} status: 'SUCCEEDED',`);
|
|
301
|
+
lines.push(`${tryIndent}});`);
|
|
302
|
+
// Debug controller: afterNode hook for scoped children
|
|
303
|
+
if (emitDebugHooks) {
|
|
304
|
+
const awaitHook = isAsync ? 'await ' : '';
|
|
305
|
+
lines.push(`${tryIndent}${awaitHook}__ctrl__.afterNode('${child.id}', scopedCtx);`);
|
|
306
|
+
}
|
|
307
|
+
lines.push(`${childIndent}} catch (error: unknown) {`);
|
|
308
|
+
lines.push(`${tryIndent}const isCancellation = CancellationError.isCancellationError(error);`);
|
|
309
|
+
lines.push(`${tryIndent}${awaitPrefix}scopedCtx.sendStatusChangedEvent({`);
|
|
310
|
+
lines.push(`${tryIndent} nodeTypeName: '${child.nodeType}',`);
|
|
311
|
+
lines.push(`${tryIndent} id: '${child.id}',`);
|
|
312
|
+
lines.push(`${tryIndent} executionIndex: ${safeChildId}Idx,`);
|
|
313
|
+
lines.push(`${tryIndent} status: isCancellation ? 'CANCELLED' : 'FAILED',`);
|
|
314
|
+
lines.push(`${tryIndent}});`);
|
|
315
|
+
lines.push(`${tryIndent}if (!isCancellation) {`);
|
|
316
|
+
lines.push(`${tryIndent} scopedCtx.sendLogErrorEvent({`);
|
|
317
|
+
lines.push(`${tryIndent} nodeTypeName: '${child.nodeType}',`);
|
|
318
|
+
lines.push(`${tryIndent} id: '${child.id}',`);
|
|
319
|
+
lines.push(`${tryIndent} executionIndex: ${safeChildId}Idx,`);
|
|
320
|
+
lines.push(`${tryIndent} error: error instanceof Error ? error.message : String(error),`);
|
|
321
|
+
lines.push(`${tryIndent} });`);
|
|
322
|
+
lines.push(`${tryIndent}}`);
|
|
323
|
+
lines.push(`${tryIndent}throw error;`);
|
|
324
|
+
lines.push(`${childIndent}}`);
|
|
325
|
+
// Close debug controller beforeNode if-block
|
|
326
|
+
if (emitDebugHooks) {
|
|
327
|
+
lines.push(` }`);
|
|
328
|
+
}
|
|
303
329
|
});
|
|
304
330
|
lines.push(``);
|
|
305
331
|
}
|
package/dist/parser.js
CHANGED
|
@@ -14,6 +14,7 @@ import { getPackageExports } from './npm-packages.js';
|
|
|
14
14
|
import { getSharedProject } from './shared-project.js';
|
|
15
15
|
import { LRUCache } from './utils/lru-cache.js';
|
|
16
16
|
import { COERCION_NODE_TYPES, COERCE_TYPE_MAP } from './built-in-nodes/coercion-types.js';
|
|
17
|
+
import { BUILT_IN_NODE_TYPES } from './built-in-nodes/generated-registry.js';
|
|
17
18
|
import { tagHandlerRegistry } from './parser/tag-registry.js';
|
|
18
19
|
/**
|
|
19
20
|
* Convert a TExternalNodeType to a TNodeTypeAST with sensible defaults.
|
|
@@ -233,8 +234,9 @@ export class AnnotationParser {
|
|
|
233
234
|
}
|
|
234
235
|
}
|
|
235
236
|
}
|
|
236
|
-
// Auto-infer node types from unannotated functions referenced by @node
|
|
237
|
-
|
|
237
|
+
// Auto-infer node types from unannotated functions referenced by @node,
|
|
238
|
+
// and lazily inject built-in nodes (delay, waitForEvent, etc.) when referenced
|
|
239
|
+
const inferredNodeTypes = this.inferNodeTypesFromUnannotated(sourceFile, nodeTypes, localNodeTypes, warnings);
|
|
238
240
|
nodeTypes.push(...inferredNodeTypes);
|
|
239
241
|
const workflows = this.extractWorkflows(sourceFile, nodeTypes, filePath, errors, warnings);
|
|
240
242
|
const patterns = this.extractPatterns(sourceFile, nodeTypes, filePath, errors, warnings);
|
|
@@ -282,8 +284,9 @@ export class AnnotationParser {
|
|
|
282
284
|
const workflowSignatures = this.extractWorkflowSignatures(sourceFile, virtualPath, warnings);
|
|
283
285
|
const sameFileWorkflowNodeTypes = workflowSignatures.map((wf) => this.workflowToNodeType(wf));
|
|
284
286
|
const nodeTypes = [...localNodeTypes, ...sameFileWorkflowNodeTypes];
|
|
285
|
-
// Auto-infer node types from unannotated functions referenced by @node
|
|
286
|
-
|
|
287
|
+
// Auto-infer node types from unannotated functions referenced by @node,
|
|
288
|
+
// and lazily inject built-in nodes (delay, waitForEvent, etc.) when referenced
|
|
289
|
+
const inferredNodeTypes = this.inferNodeTypesFromUnannotated(sourceFile, nodeTypes, localNodeTypes, warnings);
|
|
287
290
|
nodeTypes.push(...inferredNodeTypes);
|
|
288
291
|
// Note: imports not supported for virtual files - would need filesystem access
|
|
289
292
|
const workflows = this.extractWorkflows(sourceFile, nodeTypes, virtualPath, errors, warnings);
|
|
@@ -555,7 +558,7 @@ export class AnnotationParser {
|
|
|
555
558
|
}
|
|
556
559
|
else {
|
|
557
560
|
// npm package import - use .d.ts inference
|
|
558
|
-
return this.resolveNpmImportAnnotation(imp, currentDir);
|
|
561
|
+
return this.resolveNpmImportAnnotation(imp, currentDir, warnings);
|
|
559
562
|
}
|
|
560
563
|
}
|
|
561
564
|
/**
|
|
@@ -609,7 +612,7 @@ export class AnnotationParser {
|
|
|
609
612
|
/**
|
|
610
613
|
* Resolve an npm package @fwImport to a node type by reading .d.ts declarations.
|
|
611
614
|
*/
|
|
612
|
-
resolveNpmImportAnnotation(imp, currentDir) {
|
|
615
|
+
resolveNpmImportAnnotation(imp, currentDir, warnings) {
|
|
613
616
|
// Check cache (with mtime validation — same pattern as resolveNpmImports)
|
|
614
617
|
const cacheKey = `npm:${imp.importSource}`;
|
|
615
618
|
if (this.importCache.has(cacheKey)) {
|
|
@@ -637,6 +640,8 @@ export class AnnotationParser {
|
|
|
637
640
|
// Resolve .d.ts path
|
|
638
641
|
const dtsPath = resolvePackageTypesPath(imp.importSource, currentDir);
|
|
639
642
|
if (!dtsPath) {
|
|
643
|
+
warnings.push(`@fwImport: Package "${imp.importSource}" has no type declarations (.d.ts). ` +
|
|
644
|
+
`Install @types/${imp.importSource} or add a local wrapper with @flowWeaver nodeType annotations.`);
|
|
640
645
|
return this.createImportStub(imp);
|
|
641
646
|
}
|
|
642
647
|
try {
|
|
@@ -667,9 +672,12 @@ export class AnnotationParser {
|
|
|
667
672
|
if (found) {
|
|
668
673
|
return { ...found, name: imp.name, importSource: imp.importSource };
|
|
669
674
|
}
|
|
675
|
+
// Function not found in .d.ts
|
|
676
|
+
warnings.push(`@fwImport: Function "${imp.functionName}" not found in type declarations for "${imp.importSource}". ` +
|
|
677
|
+
`Available exports: ${allNodeTypes.map((nt) => nt.functionName).join(', ') || '(none)'}.`);
|
|
670
678
|
}
|
|
671
|
-
catch {
|
|
672
|
-
|
|
679
|
+
catch (err) {
|
|
680
|
+
warnings.push(`@fwImport: Failed to parse type declarations for "${imp.importSource}": ${err.message}. Node "${imp.name}" will use a generic stub.`);
|
|
673
681
|
}
|
|
674
682
|
return this.createImportStub(imp);
|
|
675
683
|
}
|
|
@@ -982,6 +990,22 @@ export class AnnotationParser {
|
|
|
982
990
|
// These are persisted in JSDoc so they survive file re-parsing
|
|
983
991
|
// Uses the same inference logic as TS imports for consistency
|
|
984
992
|
const importedNpmNodeTypes = (config.imports || []).map((imp) => this.resolveImportAnnotation(imp, filePath, warnings));
|
|
993
|
+
// Post-resolution check: warn when inferred node type has zero data ports
|
|
994
|
+
// (excluding control-flow ports). This usually means the .d.ts inference
|
|
995
|
+
// couldn't extract meaningful port info and a local wrapper is needed.
|
|
996
|
+
for (const nt of importedNpmNodeTypes) {
|
|
997
|
+
const dataInputs = Object.keys(nt.inputs).filter((p) => p !== 'execute');
|
|
998
|
+
const nonControlOutputs = Object.keys(nt.outputs).filter((p) => p !== 'onSuccess' && p !== 'onFailure');
|
|
999
|
+
// Stub fallback has only result: ANY — if that's all we have with zero
|
|
1000
|
+
// data inputs, inference likely failed
|
|
1001
|
+
const isStubOnly = nonControlOutputs.length === 1 &&
|
|
1002
|
+
nonControlOutputs[0] === 'result' &&
|
|
1003
|
+
nt.outputs.result?.dataType === 'ANY';
|
|
1004
|
+
if (dataInputs.length === 0 && isStubOnly) {
|
|
1005
|
+
warnings.push(`Could not infer ports for "${nt.functionName}" from "${nt.importSource}". ` +
|
|
1006
|
+
`Wrap it in a local function with @flowWeaver nodeType annotations instead.`);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
985
1009
|
// Combine available node types with imported npm types for validation
|
|
986
1010
|
const allAvailableNodeTypes = [...availableNodeTypes, ...importedNpmNodeTypes];
|
|
987
1011
|
// Convert instances to NodeInstanceAST
|
|
@@ -1350,7 +1374,7 @@ export class AnnotationParser {
|
|
|
1350
1374
|
* nodeType annotation, we infer an expression node type from its TypeScript
|
|
1351
1375
|
* signature. Phase 1: same-file functions only.
|
|
1352
1376
|
*/
|
|
1353
|
-
inferNodeTypesFromUnannotated(sourceFile, existingNodeTypes) {
|
|
1377
|
+
inferNodeTypesFromUnannotated(sourceFile, existingNodeTypes, localNodeTypes, warnings) {
|
|
1354
1378
|
const allFunctions = extractFunctionLikes(sourceFile);
|
|
1355
1379
|
// 1. Pre-scan workflows for @node references to collect referenced type names
|
|
1356
1380
|
const referencedTypes = new Set();
|
|
@@ -1376,17 +1400,33 @@ export class AnnotationParser {
|
|
|
1376
1400
|
}
|
|
1377
1401
|
if (unresolvedTypes.size === 0)
|
|
1378
1402
|
return [];
|
|
1379
|
-
// 3. Match unresolved types to unannotated functions in
|
|
1403
|
+
// 3. Match unresolved types to unannotated functions OR built-in nodes
|
|
1380
1404
|
const inferredNodeTypes = [];
|
|
1381
1405
|
const alreadyInferred = new Set();
|
|
1406
|
+
const builtInByName = new Map(BUILT_IN_NODE_TYPES.map((nt) => [nt.name, nt]));
|
|
1407
|
+
const annotatedNames = new Set(localNodeTypes.map((nt) => nt.functionName));
|
|
1382
1408
|
for (const unresolvedType of unresolvedTypes) {
|
|
1383
1409
|
if (alreadyInferred.has(unresolvedType))
|
|
1384
1410
|
continue;
|
|
1385
|
-
//
|
|
1411
|
+
// 3a. Check built-in nodes first
|
|
1412
|
+
const builtIn = builtInByName.get(unresolvedType);
|
|
1413
|
+
if (builtIn) {
|
|
1414
|
+
inferredNodeTypes.push(builtIn);
|
|
1415
|
+
alreadyInferred.add(unresolvedType);
|
|
1416
|
+
// Warn if a local unannotated function has the same name (it will be shadowed)
|
|
1417
|
+
if (!annotatedNames.has(unresolvedType)) {
|
|
1418
|
+
const shadowFn = allFunctions.find((fn) => fn.getName() === unresolvedType && !this.hasFlowWeaverAnnotation(fn));
|
|
1419
|
+
if (shadowFn) {
|
|
1420
|
+
warnings.push(`Function '${unresolvedType}' exists in this file but is not annotated with @flowWeaver nodeType. ` +
|
|
1421
|
+
`The built-in '${unresolvedType}' will be used instead. Add @flowWeaver nodeType to use your version.`);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
continue;
|
|
1425
|
+
}
|
|
1426
|
+
// 3b. Match unannotated local function
|
|
1386
1427
|
const matchedFn = allFunctions.find((fn) => {
|
|
1387
1428
|
if (fn.getName() !== unresolvedType)
|
|
1388
1429
|
return false;
|
|
1389
|
-
// Must NOT have a valid @flowWeaver annotation
|
|
1390
1430
|
return !this.hasFlowWeaverAnnotation(fn);
|
|
1391
1431
|
});
|
|
1392
1432
|
if (!matchedFn)
|
|
@@ -1653,6 +1693,10 @@ export class AnnotationParser {
|
|
|
1653
1693
|
for (const [inputName] of Object.entries(nextInputs)) {
|
|
1654
1694
|
if (isControlFlowPort(inputName))
|
|
1655
1695
|
continue;
|
|
1696
|
+
// Skip auto-wiring if a manual @connect already targets this input port
|
|
1697
|
+
const alreadyConnected = connections.some(c => c.to.node === nextId && c.to.port === inputName);
|
|
1698
|
+
if (alreadyConnected)
|
|
1699
|
+
continue;
|
|
1656
1700
|
// Walk backward through path steps to find nearest ancestor with same-name output
|
|
1657
1701
|
for (let j = i; j >= 0; j--) {
|
|
1658
1702
|
const ancestorId = steps[j].node;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synergenius/flow-weaver",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "Flow Weaver: deterministic TypeScript workflow compiler. Define workflows with JSDoc annotations, compile to standalone functions with zero runtime dependencies.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -113,7 +113,9 @@
|
|
|
113
113
|
"LICENSE"
|
|
114
114
|
],
|
|
115
115
|
"scripts": {
|
|
116
|
-
"prebuild": "tsx scripts/generate-version.ts",
|
|
116
|
+
"prebuild": "tsx scripts/generate-version.ts && tsx scripts/generate-built-in-registry.ts",
|
|
117
|
+
"generate:registry": "tsx scripts/generate-built-in-registry.ts",
|
|
118
|
+
"generate:registry:check": "tsx scripts/generate-built-in-registry.ts --check",
|
|
117
119
|
"build": "rimraf dist .tsbuildinfo && tsc -p tsconfig.build.json && npm run build:cli",
|
|
118
120
|
"postbuild": "npx tsx scripts/postbuild.ts && npm run generate:docs",
|
|
119
121
|
"generate:docs": "tsx scripts/generate-docs.ts",
|