@synergenius/flow-weaver 0.21.17 → 0.21.18

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.
@@ -9671,7 +9671,7 @@ var VERSION;
9671
9671
  var init_generated_version = __esm({
9672
9672
  "src/generated-version.ts"() {
9673
9673
  "use strict";
9674
- VERSION = "0.21.17";
9674
+ VERSION = "0.21.18";
9675
9675
  }
9676
9676
  });
9677
9677
 
@@ -39494,6 +39494,45 @@ Add '@param ${fromPort}' to the workflow JSDoc and include it in the params obje
39494
39494
  }
39495
39495
  }
39496
39496
  }
39497
+ const parentOf = /* @__PURE__ */ new Map();
39498
+ for (const inst of workflow.instances) {
39499
+ parentOf.set(inst.id, inst.parent ?? void 0);
39500
+ }
39501
+ const scopedParentIds = /* @__PURE__ */ new Set();
39502
+ for (const inst of workflow.instances) {
39503
+ const nt = instanceMap.get(inst.id);
39504
+ if (!nt) continue;
39505
+ const hasScopedPorts = [
39506
+ ...Object.values(nt.inputs ?? {}),
39507
+ ...Object.values(nt.outputs ?? {})
39508
+ ].some((p) => p.scope);
39509
+ if (hasScopedPorts) scopedParentIds.add(inst.id);
39510
+ }
39511
+ for (const conn of workflow.connections) {
39512
+ if (conn.from.scope || conn.to.scope) continue;
39513
+ const fromParent = parentOf.get(conn.from.node);
39514
+ const toParent = parentOf.get(conn.to.node);
39515
+ if (!parentOf.has(conn.from.node) || !parentOf.has(conn.to.node)) continue;
39516
+ if (!fromParent && !toParent) continue;
39517
+ const fromInScopedParent = fromParent && scopedParentIds.has(fromParent.id);
39518
+ const toInScopedParent = toParent && scopedParentIds.has(toParent.id);
39519
+ if (!fromInScopedParent && !toInScopedParent) continue;
39520
+ const fromIsParentOfTo = toParent && toParent.id === conn.from.node;
39521
+ const toIsParentOfFrom = fromParent && fromParent.id === conn.to.node;
39522
+ if (fromIsParentOfTo || toIsParentOfFrom) continue;
39523
+ const sameScope = fromParent && toParent && fromParent.id === toParent.id && fromParent.scope === toParent.scope;
39524
+ if (!sameScope) {
39525
+ const fromCtx = fromParent ? `${fromParent.id}.${fromParent.scope}` : "root";
39526
+ const toCtx = toParent ? `${toParent.id}.${toParent.scope}` : "root";
39527
+ this.errors.push({
39528
+ type: "error",
39529
+ code: "CROSS_SCOPE_CONNECTION",
39530
+ message: `Connection from "${conn.from.node}.${conn.from.port}" (in ${fromCtx}) to "${conn.to.node}.${conn.to.port}" (in ${toCtx}) crosses scope boundaries. Nodes in different scopes cannot connect directly.`,
39531
+ connection: conn,
39532
+ location: this.getConnectionLocation(conn)
39533
+ });
39534
+ }
39535
+ }
39497
39536
  }
39498
39537
  // ── H: Duplicate instance IDs ──────────────────────────────────────────
39499
39538
  validateDuplicateInstanceIds(workflow) {
@@ -93231,7 +93270,7 @@ function displayInstalledPackage(pkg) {
93231
93270
  // src/cli/index.ts
93232
93271
  init_logger();
93233
93272
  init_error_utils();
93234
- var version2 = true ? "0.21.17" : "0.0.0-dev";
93273
+ var version2 = true ? "0.21.18" : "0.0.0-dev";
93235
93274
  var program2 = new Command();
93236
93275
  program2.name("fw").description("Flow Weaver Annotations - Compile and validate workflow files").option("-v, --version", "Output the current version").option("--no-color", "Disable colors").option("--color", "Force colors").on("option:version", () => {
93237
93276
  logger.banner(version2);
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.21.17";
1
+ export declare const VERSION = "0.21.18";
2
2
  //# sourceMappingURL=generated-version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by scripts/generate-version.ts — do not edit manually
2
- export const VERSION = '0.21.17';
2
+ export const VERSION = '0.21.18';
3
3
  //# sourceMappingURL=generated-version.js.map
package/dist/validator.js CHANGED
@@ -1374,6 +1374,67 @@ export class WorkflowValidator {
1374
1374
  }
1375
1375
  }
1376
1376
  }
1377
+ // Check: non-scoped connections must not cross scope boundaries
1378
+ // when the parent is a scoped node type (has scoped ports).
1379
+ // A child in scope "a" cannot connect to a child in scope "b" (or root),
1380
+ // because they execute in separate callback contexts.
1381
+ // Only applies to per-port scoped parents (not flat grouping scopes).
1382
+ const parentOf = new Map();
1383
+ for (const inst of workflow.instances) {
1384
+ parentOf.set(inst.id, inst.parent ?? undefined);
1385
+ }
1386
+ // Build set of node IDs that are scoped parent types (have scoped ports)
1387
+ const scopedParentIds = new Set();
1388
+ for (const inst of workflow.instances) {
1389
+ const nt = instanceMap.get(inst.id);
1390
+ if (!nt)
1391
+ continue;
1392
+ const hasScopedPorts = [
1393
+ ...Object.values(nt.inputs ?? {}),
1394
+ ...Object.values(nt.outputs ?? {}),
1395
+ ].some((p) => p.scope);
1396
+ if (hasScopedPorts)
1397
+ scopedParentIds.add(inst.id);
1398
+ }
1399
+ for (const conn of workflow.connections) {
1400
+ // Skip scoped connections (already validated above)
1401
+ if (conn.from.scope || conn.to.scope)
1402
+ continue;
1403
+ const fromParent = parentOf.get(conn.from.node);
1404
+ const toParent = parentOf.get(conn.to.node);
1405
+ // Both must exist in the workflow
1406
+ if (!parentOf.has(conn.from.node) || !parentOf.has(conn.to.node))
1407
+ continue;
1408
+ // If neither node is inside a scope, skip (root-to-root is fine)
1409
+ if (!fromParent && !toParent)
1410
+ continue;
1411
+ // Only validate when the parent is a scoped node type (has scoped ports).
1412
+ // Flat grouping scopes (createScope without scoped ports) are allowed to cross.
1413
+ const fromInScopedParent = fromParent && scopedParentIds.has(fromParent.id);
1414
+ const toInScopedParent = toParent && scopedParentIds.has(toParent.id);
1415
+ if (!fromInScopedParent && !toInScopedParent)
1416
+ continue;
1417
+ // Allow connections where one side is the scoped PARENT itself (not a child)
1418
+ const fromIsParentOfTo = toParent && toParent.id === conn.from.node;
1419
+ const toIsParentOfFrom = fromParent && fromParent.id === conn.to.node;
1420
+ if (fromIsParentOfTo || toIsParentOfFrom)
1421
+ continue;
1422
+ // Check if they share the same parent+scope
1423
+ const sameScope = fromParent && toParent &&
1424
+ fromParent.id === toParent.id &&
1425
+ fromParent.scope === toParent.scope;
1426
+ if (!sameScope) {
1427
+ const fromCtx = fromParent ? `${fromParent.id}.${fromParent.scope}` : 'root';
1428
+ const toCtx = toParent ? `${toParent.id}.${toParent.scope}` : 'root';
1429
+ this.errors.push({
1430
+ type: 'error',
1431
+ code: 'CROSS_SCOPE_CONNECTION',
1432
+ message: `Connection from "${conn.from.node}.${conn.from.port}" (in ${fromCtx}) to "${conn.to.node}.${conn.to.port}" (in ${toCtx}) crosses scope boundaries. Nodes in different scopes cannot connect directly.`,
1433
+ connection: conn,
1434
+ location: this.getConnectionLocation(conn),
1435
+ });
1436
+ }
1437
+ }
1377
1438
  }
1378
1439
  // ── H: Duplicate instance IDs ──────────────────────────────────────────
1379
1440
  validateDuplicateInstanceIds(workflow) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synergenius/flow-weaver",
3
- "version": "0.21.17",
3
+ "version": "0.21.18",
4
4
  "description": "Deterministic workflow compiler for AI agents. Compiles to standalone TypeScript, no runtime dependencies.",
5
5
  "private": false,
6
6
  "type": "module",