yaml-flow 2.2.0 → 2.3.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 CHANGED
@@ -801,6 +801,44 @@ Entry points (no requires) get rounded shapes, leaf tasks get double-bracketed s
801
801
 
802
802
  ---
803
803
 
804
+ ## Graph Validation (Semantic)
805
+
806
+ Validate the logical correctness of a graph — catches issues that structural validation (`validateGraphConfig`) can't.
807
+
808
+ ```typescript
809
+ import { validateGraph } from 'yaml-flow/event-graph';
810
+
811
+ const result = validateGraph(graph);
812
+
813
+ result.valid; // true if no errors (warnings/info allowed)
814
+ result.errors; // issues that will break execution
815
+ result.warnings; // issues that may cause unexpected behavior
816
+ result.issues; // all issues (errors + warnings + info)
817
+
818
+ // Each issue
819
+ result.issues[0].severity; // 'error' | 'warning' | 'info'
820
+ result.issues[0].code; // e.g. 'CIRCULAR_DEPENDENCY'
821
+ result.issues[0].message; // human-readable description
822
+ result.issues[0].tasks; // affected task names
823
+ result.issues[0].tokens; // affected tokens
824
+ ```
825
+
826
+ | Issue Code | Severity | Description |
827
+ |---|---|---|
828
+ | `EMPTY_GRAPH` | error | Graph has no tasks |
829
+ | `DANGLING_REQUIRES` | error | Task requires a token that no task produces |
830
+ | `CIRCULAR_DEPENDENCY` | error | Cycle detected in task dependencies |
831
+ | `SELF_DEPENDENCY` | error | Task requires a token it provides itself |
832
+ | `UNREACHABLE_GOAL` | error | Goal token cannot be produced by any task |
833
+ | `MISSING_GOAL` | error | `goal-reached` strategy without goal array |
834
+ | `PROVIDE_CONFLICT` | warning | Multiple tasks produce the same token |
835
+ | `DEAD_END_TASK` | warning | Task has no provides — can't unblock downstream |
836
+ | `ISOLATED_TASK` | info | Disconnected task with no requires or dependents |
837
+
838
+ Use `validateGraphConfig()` for structural checks (JSON shape) and `validateGraph()` for semantic checks (logical correctness). Both are pure functions.
839
+
840
+ ---
841
+
804
842
  ## Loading & Exporting Graph Configs
805
843
 
806
844
  ```typescript
@@ -835,6 +873,7 @@ import { next, apply, applyAll, getCandidateTasks } from 'yaml-flow/event-graph'
835
873
  import { createInitialExecutionState, isExecutionComplete, detectStuckState } from 'yaml-flow/event-graph';
836
874
  import { planExecution, graphToMermaid, flowToMermaid } from 'yaml-flow/event-graph';
837
875
  import { loadGraphConfig, validateGraphConfig, exportGraphConfig } from 'yaml-flow/event-graph';
876
+ import { validateGraph } from 'yaml-flow/event-graph';
838
877
  import { TASK_STATUS, COMPLETION_STRATEGIES, CONFLICT_STRATEGIES } from 'yaml-flow/event-graph';
839
878
 
840
879
  // Stores
@@ -889,6 +928,7 @@ import { FlowEngine, createEngine } from 'yaml-flow'; // aliases for StepMachin
889
928
  | `validateGraphConfig(config)` | Validate a GraphConfig, returns error strings |
890
929
  | `exportGraphConfig(config, options?)` | Export a GraphConfig to JSON or YAML string |
891
930
  | `exportGraphConfigToFile(config, path)` | Export a GraphConfig to a file |
931
+ | `validateGraph(graph)` | Semantic validation: cycles, dangling requires, unreachable goals, conflicts |
892
932
 
893
933
  ### Event Types (for `apply()`)
894
934
 
@@ -438,6 +438,56 @@ declare function exportGraphConfig(config: GraphConfig, options?: ExportOptions)
438
438
  */
439
439
  declare function exportGraphConfigToFile(config: GraphConfig, filePath: string, options?: ExportOptions): Promise<void>;
440
440
 
441
+ /**
442
+ * Event Graph — Semantic Graph Validation
443
+ *
444
+ * Validates the logical correctness of a static graph configuration.
445
+ * Unlike validateGraphConfig() which checks JSON structure, this checks:
446
+ * - Dangling requires (tokens no task produces)
447
+ * - Circular dependencies
448
+ * - Provide conflicts (multiple tasks producing same token)
449
+ * - Unreachable goal tokens
450
+ * - Dead-end tasks (no provides)
451
+ * - Self-dependencies
452
+ * - Orphaned tasks (disconnected from the graph)
453
+ *
454
+ * Pure function — config in, diagnostics out.
455
+ */
456
+
457
+ type IssueSeverity = 'error' | 'warning' | 'info';
458
+ interface GraphIssue {
459
+ /** Severity: error = will break execution, warning = may cause problems, info = notable */
460
+ severity: IssueSeverity;
461
+ /** Machine-readable issue code */
462
+ code: string;
463
+ /** Human-readable description */
464
+ message: string;
465
+ /** Affected task names (if applicable) */
466
+ tasks?: string[];
467
+ /** Affected tokens (if applicable) */
468
+ tokens?: string[];
469
+ }
470
+ interface GraphValidationResult {
471
+ /** true if no errors (warnings/info are allowed) */
472
+ valid: boolean;
473
+ /** All issues found */
474
+ issues: GraphIssue[];
475
+ /** Just the errors */
476
+ errors: GraphIssue[];
477
+ /** Just the warnings */
478
+ warnings: GraphIssue[];
479
+ }
480
+ /**
481
+ * Validate the semantic correctness of a static event-graph configuration.
482
+ *
483
+ * Checks for logical issues that would cause execution failures, stuck states,
484
+ * or unexpected behavior. Does NOT check JSON structure (use validateGraphConfig for that).
485
+ *
486
+ * @param graph - The event-graph configuration to validate
487
+ * @returns Validation result with categorized issues
488
+ */
489
+ declare function validateGraph(graph: GraphConfig): GraphValidationResult;
490
+
441
491
  /**
442
492
  * Event Graph — Constants
443
493
  */
@@ -454,4 +504,4 @@ declare const DEFAULTS: {
454
504
  readonly MAX_ITERATIONS: 1000;
455
505
  };
456
506
 
457
- export { next as $, type AgentActionEvent as A, createInitialExecutionState as B, COMPLETION_STRATEGIES as C, DEFAULTS as D, EXECUTION_MODES as E, detectStuckState as F, type GraphConfig as G, exportGraphConfig as H, type InjectTokensEvent as I, exportGraphConfigToFile as J, flowToMermaid as K, getAllTasks as L, type MermaidOptions as M, getCandidateTasks as N, getProvides as O, getRequires as P, getTask as Q, graphToMermaid as R, type SchedulerResult as S, type TaskConfig as T, hasTask as U, isExecutionComplete as V, isNonActiveTask as W, isRepeatableTask as X, isTaskCompleted as Y, isTaskRunning as Z, loadGraphConfig as _, CONFLICT_STRATEGIES as a, planExecution as a0, validateGraphConfig as a1, type RepeatableConfig as a2, type TaskCircuitBreakerConfig as a3, type TaskMessage as a4, type TaskProgressEvent as a5, type TaskRetryConfig as a6, addKeyToProvides as a7, addKeyToRequires as a8, getRepeatableMax as a9, groupTasksByProvides as aa, hasOutputConflict as ab, removeKeyFromProvides as ac, removeKeyFromRequires as ad, type CompletionResult as b, type CompletionStrategy as c, type ConflictStrategy as d, EXECUTION_STATUS as e, type ExecutionConfig as f, type ExecutionMode as g, type ExecutionPlan as h, type ExecutionState as i, type ExecutionStatus as j, type ExportOptions as k, type GraphEvent as l, type GraphSettings as m, type StuckDetection as n, TASK_STATUS as o, type TaskCompletedEvent as p, type TaskCreationEvent as q, type TaskFailedEvent as r, type TaskStartedEvent as s, type TaskState as t, type TaskStatus as u, addDynamicTask as v, apply as w, applyAll as x, computeAvailableOutputs as y, createDefaultTaskState as z };
507
+ export { isTaskCompleted as $, type AgentActionEvent as A, applyAll as B, COMPLETION_STRATEGIES as C, DEFAULTS as D, EXECUTION_MODES as E, computeAvailableOutputs as F, type GraphConfig as G, createDefaultTaskState as H, type InjectTokensEvent as I, createInitialExecutionState as J, detectStuckState as K, exportGraphConfig as L, type MermaidOptions as M, exportGraphConfigToFile as N, flowToMermaid as O, getAllTasks as P, getCandidateTasks as Q, getProvides as R, type SchedulerResult as S, type TaskConfig as T, getRequires as U, getTask as V, graphToMermaid as W, hasTask as X, isExecutionComplete as Y, isNonActiveTask as Z, isRepeatableTask as _, CONFLICT_STRATEGIES as a, isTaskRunning as a0, loadGraphConfig as a1, next as a2, planExecution as a3, validateGraph as a4, validateGraphConfig as a5, type RepeatableConfig as a6, type TaskCircuitBreakerConfig as a7, type TaskMessage as a8, type TaskProgressEvent as a9, type TaskRetryConfig as aa, addKeyToProvides as ab, addKeyToRequires as ac, getRepeatableMax as ad, groupTasksByProvides as ae, hasOutputConflict as af, removeKeyFromProvides as ag, removeKeyFromRequires as ah, type CompletionResult as b, type CompletionStrategy as c, type ConflictStrategy as d, EXECUTION_STATUS as e, type ExecutionConfig as f, type ExecutionMode as g, type ExecutionPlan as h, type ExecutionState as i, type ExecutionStatus as j, type ExportOptions as k, type GraphEvent as l, type GraphIssue as m, type GraphSettings as n, type GraphValidationResult as o, type IssueSeverity as p, type StuckDetection as q, TASK_STATUS as r, type TaskCompletedEvent as s, type TaskCreationEvent as t, type TaskFailedEvent as u, type TaskStartedEvent as v, type TaskState as w, type TaskStatus as x, addDynamicTask as y, apply as z };
@@ -438,6 +438,56 @@ declare function exportGraphConfig(config: GraphConfig, options?: ExportOptions)
438
438
  */
439
439
  declare function exportGraphConfigToFile(config: GraphConfig, filePath: string, options?: ExportOptions): Promise<void>;
440
440
 
441
+ /**
442
+ * Event Graph — Semantic Graph Validation
443
+ *
444
+ * Validates the logical correctness of a static graph configuration.
445
+ * Unlike validateGraphConfig() which checks JSON structure, this checks:
446
+ * - Dangling requires (tokens no task produces)
447
+ * - Circular dependencies
448
+ * - Provide conflicts (multiple tasks producing same token)
449
+ * - Unreachable goal tokens
450
+ * - Dead-end tasks (no provides)
451
+ * - Self-dependencies
452
+ * - Orphaned tasks (disconnected from the graph)
453
+ *
454
+ * Pure function — config in, diagnostics out.
455
+ */
456
+
457
+ type IssueSeverity = 'error' | 'warning' | 'info';
458
+ interface GraphIssue {
459
+ /** Severity: error = will break execution, warning = may cause problems, info = notable */
460
+ severity: IssueSeverity;
461
+ /** Machine-readable issue code */
462
+ code: string;
463
+ /** Human-readable description */
464
+ message: string;
465
+ /** Affected task names (if applicable) */
466
+ tasks?: string[];
467
+ /** Affected tokens (if applicable) */
468
+ tokens?: string[];
469
+ }
470
+ interface GraphValidationResult {
471
+ /** true if no errors (warnings/info are allowed) */
472
+ valid: boolean;
473
+ /** All issues found */
474
+ issues: GraphIssue[];
475
+ /** Just the errors */
476
+ errors: GraphIssue[];
477
+ /** Just the warnings */
478
+ warnings: GraphIssue[];
479
+ }
480
+ /**
481
+ * Validate the semantic correctness of a static event-graph configuration.
482
+ *
483
+ * Checks for logical issues that would cause execution failures, stuck states,
484
+ * or unexpected behavior. Does NOT check JSON structure (use validateGraphConfig for that).
485
+ *
486
+ * @param graph - The event-graph configuration to validate
487
+ * @returns Validation result with categorized issues
488
+ */
489
+ declare function validateGraph(graph: GraphConfig): GraphValidationResult;
490
+
441
491
  /**
442
492
  * Event Graph — Constants
443
493
  */
@@ -454,4 +504,4 @@ declare const DEFAULTS: {
454
504
  readonly MAX_ITERATIONS: 1000;
455
505
  };
456
506
 
457
- export { next as $, type AgentActionEvent as A, createInitialExecutionState as B, COMPLETION_STRATEGIES as C, DEFAULTS as D, EXECUTION_MODES as E, detectStuckState as F, type GraphConfig as G, exportGraphConfig as H, type InjectTokensEvent as I, exportGraphConfigToFile as J, flowToMermaid as K, getAllTasks as L, type MermaidOptions as M, getCandidateTasks as N, getProvides as O, getRequires as P, getTask as Q, graphToMermaid as R, type SchedulerResult as S, type TaskConfig as T, hasTask as U, isExecutionComplete as V, isNonActiveTask as W, isRepeatableTask as X, isTaskCompleted as Y, isTaskRunning as Z, loadGraphConfig as _, CONFLICT_STRATEGIES as a, planExecution as a0, validateGraphConfig as a1, type RepeatableConfig as a2, type TaskCircuitBreakerConfig as a3, type TaskMessage as a4, type TaskProgressEvent as a5, type TaskRetryConfig as a6, addKeyToProvides as a7, addKeyToRequires as a8, getRepeatableMax as a9, groupTasksByProvides as aa, hasOutputConflict as ab, removeKeyFromProvides as ac, removeKeyFromRequires as ad, type CompletionResult as b, type CompletionStrategy as c, type ConflictStrategy as d, EXECUTION_STATUS as e, type ExecutionConfig as f, type ExecutionMode as g, type ExecutionPlan as h, type ExecutionState as i, type ExecutionStatus as j, type ExportOptions as k, type GraphEvent as l, type GraphSettings as m, type StuckDetection as n, TASK_STATUS as o, type TaskCompletedEvent as p, type TaskCreationEvent as q, type TaskFailedEvent as r, type TaskStartedEvent as s, type TaskState as t, type TaskStatus as u, addDynamicTask as v, apply as w, applyAll as x, computeAvailableOutputs as y, createDefaultTaskState as z };
507
+ export { isTaskCompleted as $, type AgentActionEvent as A, applyAll as B, COMPLETION_STRATEGIES as C, DEFAULTS as D, EXECUTION_MODES as E, computeAvailableOutputs as F, type GraphConfig as G, createDefaultTaskState as H, type InjectTokensEvent as I, createInitialExecutionState as J, detectStuckState as K, exportGraphConfig as L, type MermaidOptions as M, exportGraphConfigToFile as N, flowToMermaid as O, getAllTasks as P, getCandidateTasks as Q, getProvides as R, type SchedulerResult as S, type TaskConfig as T, getRequires as U, getTask as V, graphToMermaid as W, hasTask as X, isExecutionComplete as Y, isNonActiveTask as Z, isRepeatableTask as _, CONFLICT_STRATEGIES as a, isTaskRunning as a0, loadGraphConfig as a1, next as a2, planExecution as a3, validateGraph as a4, validateGraphConfig as a5, type RepeatableConfig as a6, type TaskCircuitBreakerConfig as a7, type TaskMessage as a8, type TaskProgressEvent as a9, type TaskRetryConfig as aa, addKeyToProvides as ab, addKeyToRequires as ac, getRepeatableMax as ad, groupTasksByProvides as ae, hasOutputConflict as af, removeKeyFromProvides as ag, removeKeyFromRequires as ah, type CompletionResult as b, type CompletionStrategy as c, type ConflictStrategy as d, EXECUTION_STATUS as e, type ExecutionConfig as f, type ExecutionMode as g, type ExecutionPlan as h, type ExecutionState as i, type ExecutionStatus as j, type ExportOptions as k, type GraphEvent as l, type GraphIssue as m, type GraphSettings as n, type GraphValidationResult as o, type IssueSeverity as p, type StuckDetection as q, TASK_STATUS as r, type TaskCompletedEvent as s, type TaskCreationEvent as t, type TaskFailedEvent as u, type TaskStartedEvent as v, type TaskState as w, type TaskStatus as x, addDynamicTask as y, apply as z };
@@ -1254,6 +1254,213 @@ ${serialized}`;
1254
1254
  return String(obj);
1255
1255
  }
1256
1256
 
1257
+ // src/event-graph/validate.ts
1258
+ function buildProducerMap2(tasks) {
1259
+ const map = {};
1260
+ for (const [name, config] of Object.entries(tasks)) {
1261
+ for (const token of getProvides(config)) {
1262
+ if (!map[token]) map[token] = [];
1263
+ map[token].push(name);
1264
+ }
1265
+ if (config.on) {
1266
+ for (const tokens of Object.values(config.on)) {
1267
+ for (const token of tokens) {
1268
+ if (!map[token]) map[token] = [];
1269
+ if (!map[token].includes(name)) map[token].push(name);
1270
+ }
1271
+ }
1272
+ }
1273
+ if (config.on_failure) {
1274
+ for (const token of config.on_failure) {
1275
+ if (!map[token]) map[token] = [];
1276
+ if (!map[token].includes(name)) map[token].push(name);
1277
+ }
1278
+ }
1279
+ }
1280
+ return map;
1281
+ }
1282
+ function buildTaskDeps(tasks, producerMap) {
1283
+ const deps = {};
1284
+ for (const [name, config] of Object.entries(tasks)) {
1285
+ deps[name] = /* @__PURE__ */ new Set();
1286
+ for (const token of getRequires(config)) {
1287
+ for (const producer of producerMap[token] || []) {
1288
+ if (producer !== name) deps[name].add(producer);
1289
+ }
1290
+ }
1291
+ }
1292
+ return deps;
1293
+ }
1294
+ function detectCycles(taskNames, deps) {
1295
+ const WHITE = 0, GRAY = 1, BLACK = 2;
1296
+ const color = {};
1297
+ const parent = {};
1298
+ const cycles = [];
1299
+ for (const name of taskNames) {
1300
+ color[name] = WHITE;
1301
+ parent[name] = null;
1302
+ }
1303
+ function dfs(node) {
1304
+ color[node] = GRAY;
1305
+ for (const dep of deps[node] || []) {
1306
+ if (color[dep] === GRAY) {
1307
+ const cycle = [dep];
1308
+ let cur = node;
1309
+ while (cur !== dep) {
1310
+ cycle.push(cur);
1311
+ cur = parent[cur];
1312
+ }
1313
+ cycle.push(dep);
1314
+ cycle.reverse();
1315
+ cycles.push(cycle);
1316
+ } else if (color[dep] === WHITE) {
1317
+ parent[dep] = node;
1318
+ dfs(dep);
1319
+ }
1320
+ }
1321
+ color[node] = BLACK;
1322
+ }
1323
+ for (const name of taskNames) {
1324
+ if (color[name] === WHITE) {
1325
+ dfs(name);
1326
+ }
1327
+ }
1328
+ return cycles;
1329
+ }
1330
+ function validateGraph(graph) {
1331
+ const issues = [];
1332
+ const tasks = getAllTasks(graph);
1333
+ const taskNames = Object.keys(tasks);
1334
+ if (taskNames.length === 0) {
1335
+ issues.push({
1336
+ severity: "error",
1337
+ code: "EMPTY_GRAPH",
1338
+ message: "Graph has no tasks"
1339
+ });
1340
+ return buildResult(issues);
1341
+ }
1342
+ const producerMap = buildProducerMap2(tasks);
1343
+ const deps = buildTaskDeps(tasks, producerMap);
1344
+ for (const [name, config] of Object.entries(tasks)) {
1345
+ for (const token of getRequires(config)) {
1346
+ if (!producerMap[token]) {
1347
+ issues.push({
1348
+ severity: "error",
1349
+ code: "DANGLING_REQUIRES",
1350
+ message: `Task "${name}" requires token "${token}" but no task produces it`,
1351
+ tasks: [name],
1352
+ tokens: [token]
1353
+ });
1354
+ }
1355
+ }
1356
+ }
1357
+ const cycles = detectCycles(taskNames, deps);
1358
+ for (const cycle of cycles) {
1359
+ issues.push({
1360
+ severity: "error",
1361
+ code: "CIRCULAR_DEPENDENCY",
1362
+ message: `Circular dependency: ${cycle.join(" \u2192 ")}`,
1363
+ tasks: cycle.filter((_t, i) => i < cycle.length - 1)
1364
+ // dedupe last = first
1365
+ });
1366
+ }
1367
+ for (const [name, config] of Object.entries(tasks)) {
1368
+ const req = getRequires(config);
1369
+ const prov = getProvides(config);
1370
+ const self = req.filter((token) => prov.includes(token));
1371
+ if (self.length > 0) {
1372
+ issues.push({
1373
+ severity: "error",
1374
+ code: "SELF_DEPENDENCY",
1375
+ message: `Task "${name}" requires tokens it provides itself: [${self.join(", ")}]`,
1376
+ tasks: [name],
1377
+ tokens: self
1378
+ });
1379
+ }
1380
+ }
1381
+ for (const [token, producers] of Object.entries(producerMap)) {
1382
+ if (producers.length > 1) {
1383
+ issues.push({
1384
+ severity: "warning",
1385
+ code: "PROVIDE_CONFLICT",
1386
+ message: `Token "${token}" is produced by multiple tasks: [${producers.join(", ")}]. This requires a conflict strategy.`,
1387
+ tasks: producers,
1388
+ tokens: [token]
1389
+ });
1390
+ }
1391
+ }
1392
+ if (graph.settings.completion === "goal-reached" && graph.settings.goal) {
1393
+ for (const goalToken of graph.settings.goal) {
1394
+ if (!producerMap[goalToken]) {
1395
+ issues.push({
1396
+ severity: "error",
1397
+ code: "UNREACHABLE_GOAL",
1398
+ message: `Goal token "${goalToken}" cannot be produced by any task`,
1399
+ tokens: [goalToken]
1400
+ });
1401
+ }
1402
+ }
1403
+ }
1404
+ if (taskNames.length > 1) {
1405
+ for (const [name, config] of Object.entries(tasks)) {
1406
+ const prov = getProvides(config);
1407
+ const onProv = config.on ? Object.values(config.on).flat() : [];
1408
+ const failProv = config.on_failure || [];
1409
+ if (prov.length === 0 && onProv.length === 0 && failProv.length === 0) {
1410
+ issues.push({
1411
+ severity: "warning",
1412
+ code: "DEAD_END_TASK",
1413
+ message: `Task "${name}" has no provides \u2014 it cannot unblock any downstream task`,
1414
+ tasks: [name]
1415
+ });
1416
+ }
1417
+ }
1418
+ }
1419
+ const allRequired = /* @__PURE__ */ new Set();
1420
+ for (const config of Object.values(tasks)) {
1421
+ for (const token of getRequires(config)) {
1422
+ allRequired.add(token);
1423
+ }
1424
+ }
1425
+ for (const [name, config] of Object.entries(tasks)) {
1426
+ const req = getRequires(config);
1427
+ const prov = getProvides(config);
1428
+ const onProv = config.on ? Object.values(config.on).flat() : [];
1429
+ const allProv = [...prov, ...onProv];
1430
+ const isEntryPoint = req.length === 0;
1431
+ const hasDownstream = allProv.some((token) => allRequired.has(token));
1432
+ if (isEntryPoint && !hasDownstream && taskNames.length > 1) {
1433
+ const isGoalRelevant = graph.settings.completion === "goal-reached" && graph.settings.goal?.some((g) => allProv.includes(g));
1434
+ if (!isGoalRelevant) {
1435
+ issues.push({
1436
+ severity: "info",
1437
+ code: "ISOLATED_TASK",
1438
+ message: `Task "${name}" is disconnected \u2014 it has no requires and nothing depends on its provides`,
1439
+ tasks: [name]
1440
+ });
1441
+ }
1442
+ }
1443
+ }
1444
+ if (graph.settings.completion === "goal-reached" && !graph.settings.goal) {
1445
+ issues.push({
1446
+ severity: "error",
1447
+ code: "MISSING_GOAL",
1448
+ message: 'Completion strategy is "goal-reached" but no goal tokens are defined'
1449
+ });
1450
+ }
1451
+ return buildResult(issues);
1452
+ }
1453
+ function buildResult(issues) {
1454
+ const errors = issues.filter((i) => i.severity === "error");
1455
+ const warnings = issues.filter((i) => i.severity === "warning");
1456
+ return {
1457
+ valid: errors.length === 0,
1458
+ issues,
1459
+ errors,
1460
+ warnings
1461
+ };
1462
+ }
1463
+
1257
1464
  exports.COMPLETION_STRATEGIES = COMPLETION_STRATEGIES;
1258
1465
  exports.CONFLICT_STRATEGIES = CONFLICT_STRATEGIES;
1259
1466
  exports.DEFAULTS = DEFAULTS;
@@ -1299,6 +1506,7 @@ exports.removeKeyFromProvides = removeKeyFromProvides;
1299
1506
  exports.removeKeyFromRequires = removeKeyFromRequires;
1300
1507
  exports.selectBestAlternative = selectBestAlternative;
1301
1508
  exports.selectRandomTasks = selectRandomTasks;
1509
+ exports.validateGraph = validateGraph;
1302
1510
  exports.validateGraphConfig = validateGraphConfig;
1303
1511
  //# sourceMappingURL=index.cjs.map
1304
1512
  //# sourceMappingURL=index.cjs.map