@principal-ai/principal-view-cli 0.6.3 → 0.8.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/commands/formats.js +19 -19
- package/dist/commands/lint.js +44 -44
- package/dist/commands/workflow/index.d.ts +3 -0
- package/dist/commands/workflow/index.d.ts.map +1 -0
- package/dist/commands/{narrative → workflow}/index.js +3 -3
- package/dist/commands/workflow/inspect.d.ts.map +1 -0
- package/dist/commands/workflow/list.d.ts.map +1 -0
- package/dist/commands/{narrative → workflow}/list.js +32 -32
- package/dist/commands/workflow/render.d.ts.map +1 -0
- package/dist/commands/{narrative → workflow}/render.js +16 -16
- package/dist/commands/workflow/test.d.ts.map +1 -0
- package/dist/commands/{narrative → workflow}/test.js +8 -8
- package/dist/commands/{narrative → workflow}/utils.d.ts +4 -4
- package/dist/commands/workflow/utils.d.ts.map +1 -0
- package/dist/commands/{narrative → workflow}/utils.js +5 -5
- package/dist/commands/workflow/validate.d.ts.map +1 -0
- package/dist/commands/{narrative → workflow}/validate.js +21 -21
- package/dist/index.cjs +370 -267
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +2 -2
- package/package.json +3 -3
- package/dist/commands/narrative/index.d.ts +0 -3
- package/dist/commands/narrative/index.d.ts.map +0 -1
- package/dist/commands/narrative/inspect.d.ts.map +0 -1
- package/dist/commands/narrative/list.d.ts.map +0 -1
- package/dist/commands/narrative/render.d.ts.map +0 -1
- package/dist/commands/narrative/test.d.ts.map +0 -1
- package/dist/commands/narrative/utils.d.ts.map +0 -1
- package/dist/commands/narrative/validate.d.ts.map +0 -1
- /package/dist/commands/{narrative → workflow}/inspect.d.ts +0 -0
- /package/dist/commands/{narrative → workflow}/inspect.js +0 -0
- /package/dist/commands/{narrative → workflow}/list.d.ts +0 -0
- /package/dist/commands/{narrative → workflow}/render.d.ts +0 -0
- /package/dist/commands/{narrative → workflow}/test.d.ts +0 -0
- /package/dist/commands/{narrative → workflow}/validate.d.ts +0 -0
package/dist/index.cjs
CHANGED
|
@@ -210597,7 +210597,7 @@ var ConfigurationLoader = class _ConfigurationLoader {
|
|
|
210597
210597
|
};
|
|
210598
210598
|
ConfigurationLoader.CONFIG_DIR = ".principal-views";
|
|
210599
210599
|
|
|
210600
|
-
// ../core/dist/
|
|
210600
|
+
// ../core/dist/workflow/template-parser.js
|
|
210601
210601
|
var import_handlebars = __toESM(require_lib());
|
|
210602
210602
|
import_handlebars.default.registerHelper("eq", (a, b) => a === b);
|
|
210603
210603
|
import_handlebars.default.registerHelper("ne", (a, b) => a !== b);
|
|
@@ -210623,7 +210623,7 @@ function parseTemplate(template, context) {
|
|
|
210623
210623
|
}
|
|
210624
210624
|
}
|
|
210625
210625
|
|
|
210626
|
-
// ../core/dist/
|
|
210626
|
+
// ../core/dist/workflow/scenario-matcher.js
|
|
210627
210627
|
function selectScenario(template, events, attributes = {}) {
|
|
210628
210628
|
const sorted = [...template.scenarios].sort((a, b) => a.priority - b.priority);
|
|
210629
210629
|
const applicableScenarios = [];
|
|
@@ -210780,8 +210780,8 @@ function computeAggregates(events) {
|
|
|
210780
210780
|
return aggregates;
|
|
210781
210781
|
}
|
|
210782
210782
|
|
|
210783
|
-
// ../core/dist/
|
|
210784
|
-
function
|
|
210783
|
+
// ../core/dist/workflow/template-renderer.js
|
|
210784
|
+
function renderWorkflow(template, events) {
|
|
210785
210785
|
const aggregates = computeAggregates(events);
|
|
210786
210786
|
const matchResult = selectScenario(template, events, aggregates);
|
|
210787
210787
|
const context = {
|
|
@@ -214496,7 +214496,7 @@ var CanvasDiscovery = class _CanvasDiscovery {
|
|
|
214496
214496
|
*
|
|
214497
214497
|
* @param fileTree - FileTree from repository-abstraction
|
|
214498
214498
|
* @param options - Discovery options (fileReader, includeContent)
|
|
214499
|
-
* @returns Discovery result with canvases, executions, and errors
|
|
214499
|
+
* @returns Discovery result with canvases, executions, storyboards, and errors
|
|
214500
214500
|
*/
|
|
214501
214501
|
async discover(fileTree, options = {}) {
|
|
214502
214502
|
const errors = [];
|
|
@@ -214504,9 +214504,11 @@ var CanvasDiscovery = class _CanvasDiscovery {
|
|
|
214504
214504
|
const packageMap = this.buildPackageMap(packages);
|
|
214505
214505
|
const canvases = await this.discoverCanvasFiles(fileTree, packageMap, options, errors);
|
|
214506
214506
|
const executions = await this.discoverExecutionFiles(fileTree, packageMap, options, errors);
|
|
214507
|
+
const storyboards = await this.discoverStoryboards(fileTree, packageMap, canvases, executions, options, errors);
|
|
214507
214508
|
canvases.sort(this.compareByPackageThenName);
|
|
214508
214509
|
executions.sort(this.compareByPackageThenName);
|
|
214509
|
-
|
|
214510
|
+
storyboards.sort(this.compareByPackageThenName);
|
|
214511
|
+
return { canvases, executions, storyboards, errors };
|
|
214510
214512
|
}
|
|
214511
214513
|
/**
|
|
214512
214514
|
* Find canvas file for a given execution
|
|
@@ -214534,6 +214536,106 @@ var CanvasDiscovery = class _CanvasDiscovery {
|
|
|
214534
214536
|
clearCache() {
|
|
214535
214537
|
this.packageCache.clear();
|
|
214536
214538
|
}
|
|
214539
|
+
/**
|
|
214540
|
+
* Discover storyboards (hierarchical organization of canvas + workflows + executions)
|
|
214541
|
+
*/
|
|
214542
|
+
async discoverStoryboards(fileTree, packageMap, canvases, executions, options, errors) {
|
|
214543
|
+
const storyboards = [];
|
|
214544
|
+
const storyboardDirs = /* @__PURE__ */ new Map();
|
|
214545
|
+
for (const file of fileTree.allFiles) {
|
|
214546
|
+
const path4 = file.relativePath || file.path || "";
|
|
214547
|
+
const parts = path4.split("/");
|
|
214548
|
+
const pvIndex = parts.indexOf(_CanvasDiscovery.CANVAS_DIR);
|
|
214549
|
+
if (pvIndex === -1 || parts.length < pvIndex + 3)
|
|
214550
|
+
continue;
|
|
214551
|
+
const storyboardName = parts[pvIndex + 1];
|
|
214552
|
+
const storyboardPath = parts.slice(0, pvIndex + 2).join("/");
|
|
214553
|
+
if (!storyboardDirs.has(storyboardPath)) {
|
|
214554
|
+
storyboardDirs.set(storyboardPath, /* @__PURE__ */ new Set());
|
|
214555
|
+
}
|
|
214556
|
+
storyboardDirs.get(storyboardPath).add(storyboardName);
|
|
214557
|
+
}
|
|
214558
|
+
for (const [storyboardParentPath, storyboardNames] of storyboardDirs) {
|
|
214559
|
+
for (const storyboardName of storyboardNames) {
|
|
214560
|
+
const storyboardPath = `${storyboardParentPath}/${storyboardName}`;
|
|
214561
|
+
if (storyboardName === _CanvasDiscovery.EXECUTIONS_DIR)
|
|
214562
|
+
continue;
|
|
214563
|
+
const storyboardCanvas = canvases.find((c) => {
|
|
214564
|
+
const canvasDir = c.path.split("/").slice(0, -1).join("/");
|
|
214565
|
+
return canvasDir === storyboardPath && c.basename === storyboardName;
|
|
214566
|
+
});
|
|
214567
|
+
if (!storyboardCanvas)
|
|
214568
|
+
continue;
|
|
214569
|
+
const workflows = await this.discoverWorkflowsInStoryboard(fileTree, storyboardPath, storyboardName, packageMap, executions, options, errors);
|
|
214570
|
+
if (workflows.length === 0)
|
|
214571
|
+
continue;
|
|
214572
|
+
const packageInfo = this.findPackageForPath(storyboardPath, packageMap);
|
|
214573
|
+
const id = packageInfo ? `${packageInfo.packageData.name}/${storyboardName}` : storyboardName;
|
|
214574
|
+
const storyboard = {
|
|
214575
|
+
id,
|
|
214576
|
+
name: this.toDisplayName(storyboardName),
|
|
214577
|
+
path: storyboardPath,
|
|
214578
|
+
basename: storyboardName,
|
|
214579
|
+
canvas: storyboardCanvas,
|
|
214580
|
+
workflows,
|
|
214581
|
+
packageName: packageInfo?.packageData.name,
|
|
214582
|
+
packagePath: packageInfo?.packageData.path,
|
|
214583
|
+
scope: packageInfo ? "package" : "root"
|
|
214584
|
+
};
|
|
214585
|
+
storyboards.push(storyboard);
|
|
214586
|
+
}
|
|
214587
|
+
}
|
|
214588
|
+
return storyboards;
|
|
214589
|
+
}
|
|
214590
|
+
/**
|
|
214591
|
+
* Discover workflows within a storyboard folder
|
|
214592
|
+
*/
|
|
214593
|
+
async discoverWorkflowsInStoryboard(fileTree, storyboardPath, storyboardName, packageMap, executions, options, errors) {
|
|
214594
|
+
const workflows = [];
|
|
214595
|
+
for (const file of fileTree.allFiles) {
|
|
214596
|
+
const path4 = file.relativePath || file.path || "";
|
|
214597
|
+
if (!path4.startsWith(storyboardPath + "/"))
|
|
214598
|
+
continue;
|
|
214599
|
+
if (!path4.endsWith(_CanvasDiscovery.WORKFLOW_EXTENSION))
|
|
214600
|
+
continue;
|
|
214601
|
+
const filename = path4.split("/").pop();
|
|
214602
|
+
if (!filename)
|
|
214603
|
+
continue;
|
|
214604
|
+
const basename3 = filename.replace(_CanvasDiscovery.WORKFLOW_EXTENSION, "");
|
|
214605
|
+
const workflowDir = path4.split("/").slice(0, -1).join("/");
|
|
214606
|
+
const packageInfo = this.findPackageForPath(path4, packageMap);
|
|
214607
|
+
const id = packageInfo ? `${packageInfo.packageData.name}/${storyboardName}/${basename3}` : `${storyboardName}/${basename3}`;
|
|
214608
|
+
const workflowExecutions = executions.filter((e) => {
|
|
214609
|
+
const execDir = e.path.split("/").slice(0, -1).join("/");
|
|
214610
|
+
return execDir === workflowDir;
|
|
214611
|
+
});
|
|
214612
|
+
let workflow = {
|
|
214613
|
+
id,
|
|
214614
|
+
name: this.toDisplayName(basename3),
|
|
214615
|
+
path: path4,
|
|
214616
|
+
basename: basename3,
|
|
214617
|
+
storyboardId: packageInfo ? `${packageInfo.packageData.name}/${storyboardName}` : storyboardName,
|
|
214618
|
+
packageName: packageInfo?.packageData.name,
|
|
214619
|
+
packagePath: packageInfo?.packageData.path,
|
|
214620
|
+
scope: packageInfo ? "package" : "root",
|
|
214621
|
+
executions: workflowExecutions
|
|
214622
|
+
};
|
|
214623
|
+
if (options.includeContent && options.fileReader) {
|
|
214624
|
+
try {
|
|
214625
|
+
const content = await options.fileReader(path4);
|
|
214626
|
+
const parsedContent = JSON.parse(content);
|
|
214627
|
+
workflow = { ...workflow, content: parsedContent };
|
|
214628
|
+
} catch (error) {
|
|
214629
|
+
errors.push({
|
|
214630
|
+
path: path4,
|
|
214631
|
+
error: `Failed to parse workflow content: ${error.message}`
|
|
214632
|
+
});
|
|
214633
|
+
}
|
|
214634
|
+
}
|
|
214635
|
+
workflows.push(workflow);
|
|
214636
|
+
}
|
|
214637
|
+
return workflows;
|
|
214638
|
+
}
|
|
214537
214639
|
/**
|
|
214538
214640
|
* Discover packages with caching by fileTree SHA
|
|
214539
214641
|
*/
|
|
@@ -214745,6 +214847,7 @@ var CanvasDiscovery = class _CanvasDiscovery {
|
|
|
214745
214847
|
};
|
|
214746
214848
|
CanvasDiscovery.CANVAS_DIR = ".principal-views";
|
|
214747
214849
|
CanvasDiscovery.EXECUTIONS_DIR = "__executions__";
|
|
214850
|
+
CanvasDiscovery.WORKFLOW_EXTENSION = ".workflow.json";
|
|
214748
214851
|
|
|
214749
214852
|
// ../core/dist/execution/ExecutionValidator.js
|
|
214750
214853
|
function convertOtlpValue(value) {
|
|
@@ -216247,9 +216350,9 @@ ${source_default.bold("1. Canvas Files")} ${source_default.yellow(".otel.canvas"
|
|
|
216247
216350
|
Define OTEL event schemas and telemetry structure for a feature.
|
|
216248
216351
|
These are the single source of truth for what events should be emitted.
|
|
216249
216352
|
|
|
216250
|
-
${source_default.bold("2.
|
|
216353
|
+
${source_default.bold("2. Workflow Files")} ${source_default.yellow(".workflow.json")}
|
|
216251
216354
|
Define scenarios and templates for rendering executions as human-readable
|
|
216252
|
-
|
|
216355
|
+
workflows based on the emitted events.
|
|
216253
216356
|
|
|
216254
216357
|
${source_default.bold("3. Execution Files")} ${source_default.yellow(".otel.json")}
|
|
216255
216358
|
Captured OTEL spans from test runs or production code, exported for
|
|
@@ -216257,7 +216360,7 @@ ${source_default.bold("3. Execution Files")} ${source_default.yellow(".otel.json
|
|
|
216257
216360
|
|
|
216258
216361
|
Run ${source_default.cyan("npx @principal-ai/principal-view-cli formats <section>")} for details on:
|
|
216259
216362
|
${source_default.yellow("canvas")} .otel.canvas format and event schemas
|
|
216260
|
-
${source_default.yellow("
|
|
216363
|
+
${source_default.yellow("workflow")} .workflow.json format and scenario structure
|
|
216261
216364
|
${source_default.yellow("execution")} .otel.json format for captured spans
|
|
216262
216365
|
${source_default.yellow("examples")} Complete example files
|
|
216263
216366
|
`,
|
|
@@ -216341,28 +216444,28 @@ ${source_default.cyan("5. Required vs Optional attributes:")}
|
|
|
216341
216444
|
${source_default.bold("Validation:")}
|
|
216342
216445
|
${source_default.cyan("npx @principal-ai/principal-view-cli validate")}
|
|
216343
216446
|
`,
|
|
216344
|
-
|
|
216345
|
-
${source_default.bold.cyan("
|
|
216447
|
+
workflow: `
|
|
216448
|
+
${source_default.bold.cyan("Workflow Format (.workflow.json)")}
|
|
216346
216449
|
${source_default.dim("\u2550".repeat(70))}
|
|
216347
216450
|
|
|
216348
|
-
|
|
216451
|
+
Workflow files define scenarios for rendering execution data as human-readable
|
|
216349
216452
|
stories. They evaluate conditions against captured events to select the best
|
|
216350
|
-
matching
|
|
216453
|
+
matching workflow template.
|
|
216351
216454
|
|
|
216352
216455
|
${source_default.bold("File Location:")}
|
|
216353
|
-
${source_default.dim(".principal-views/")}${source_default.yellow("<feature-name>.
|
|
216456
|
+
${source_default.dim(".principal-views/")}${source_default.yellow("<feature-name>.workflow.json")}
|
|
216354
216457
|
${source_default.dim("(co-located with corresponding .otel.canvas file)")}
|
|
216355
216458
|
|
|
216356
216459
|
${source_default.bold("Required Structure:")}
|
|
216357
216460
|
${source_default.dim("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510")}
|
|
216358
216461
|
${source_default.dim("\u2502")} { ${source_default.dim("\u2502")}
|
|
216359
|
-
${source_default.dim("\u2502")} ${source_default.green('"name"')}: "Feature Name", ${source_default.dim('// NOT "Feature Name
|
|
216360
|
-
${source_default.dim("\u2502")} ${source_default.green('"description"')}: "What the feature does", ${source_default.dim('// Purpose, not "
|
|
216462
|
+
${source_default.dim("\u2502")} ${source_default.green('"name"')}: "Feature Name", ${source_default.dim('// NOT "Feature Name Workflows"')} ${source_default.dim("\u2502")}
|
|
216463
|
+
${source_default.dim("\u2502")} ${source_default.green('"description"')}: "What the feature does", ${source_default.dim('// Purpose, not "Workflows for..."')} ${source_default.dim("\u2502")}
|
|
216361
216464
|
${source_default.dim("\u2502")} ${source_default.green('"scenarios"')}: [ ${source_default.dim("\u2502")}
|
|
216362
216465
|
${source_default.dim("\u2502")} { ${source_default.dim("\u2502")}
|
|
216363
216466
|
${source_default.dim("\u2502")} ${source_default.yellow('"priority"')}: 1, ${source_default.dim("// Lower = higher priority")} ${source_default.dim("\u2502")}
|
|
216364
216467
|
${source_default.dim("\u2502")} ${source_default.yellow('"condition"')}: "...", ${source_default.dim("// JSONPath/logic expression")} ${source_default.dim("\u2502")}
|
|
216365
|
-
${source_default.dim("\u2502")} ${source_default.yellow('"template"')}: { ${source_default.dim("//
|
|
216468
|
+
${source_default.dim("\u2502")} ${source_default.yellow('"template"')}: { ${source_default.dim("// Workflow template")} ${source_default.dim("\u2502")}
|
|
216366
216469
|
${source_default.dim("\u2502")} ${source_default.cyan('"summary"')}: "Completed {{count}} items", ${source_default.dim("// Handlebars template")} ${source_default.dim("\u2502")}
|
|
216367
216470
|
${source_default.dim("\u2502")} ${source_default.cyan('"events"')}: { ${source_default.dim("// Per-event templates")} ${source_default.dim("\u2502")}
|
|
216368
216471
|
${source_default.dim("\u2502")} "event.name": "Event {{attribute}} occurred" ${source_default.dim("\u2502")}
|
|
@@ -216375,14 +216478,14 @@ ${source_default.dim("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25
|
|
|
216375
216478
|
|
|
216376
216479
|
${source_default.bold("Naming Guidelines:")}
|
|
216377
216480
|
|
|
216378
|
-
\u274C DON'T append "
|
|
216379
|
-
"name": "Package Processor
|
|
216481
|
+
\u274C DON'T append "Workflows" to the name:
|
|
216482
|
+
"name": "Package Processor Workflows"
|
|
216380
216483
|
|
|
216381
216484
|
\u2705 DO use the feature name directly:
|
|
216382
216485
|
"name": "Package Processor"
|
|
216383
216486
|
|
|
216384
216487
|
\u274C DON'T prefix description with boilerplate:
|
|
216385
|
-
"description": "Human-readable
|
|
216488
|
+
"description": "Human-readable workflows for package extraction..."
|
|
216386
216489
|
|
|
216387
216490
|
\u2705 DO describe the feature's purpose:
|
|
216388
216491
|
"description": "Package extraction and analysis from repository file trees"
|
|
@@ -216433,7 +216536,7 @@ ${source_default.cyan("5. Template style:")}
|
|
|
216433
216536
|
- Include key metrics and IDs
|
|
216434
216537
|
|
|
216435
216538
|
${source_default.bold("Validation:")}
|
|
216436
|
-
${source_default.cyan("npx @principal-ai/principal-view-cli
|
|
216539
|
+
${source_default.cyan("npx @principal-ai/principal-view-cli workflow validate")}
|
|
216437
216540
|
`,
|
|
216438
216541
|
execution: `
|
|
216439
216542
|
${source_default.bold.cyan("Execution Format (.otel.json)")}
|
|
@@ -216632,9 +216735,9 @@ ${source_default.yellow(".principal-views/data-validator.otel.canvas")}
|
|
|
216632
216735
|
}
|
|
216633
216736
|
}
|
|
216634
216737
|
|
|
216635
|
-
${source_default.bold("Example 2:
|
|
216738
|
+
${source_default.bold("Example 2: Workflow Scenarios")}
|
|
216636
216739
|
${source_default.dim("\u2500".repeat(70))}
|
|
216637
|
-
${source_default.yellow(".principal-views/data-validator.
|
|
216740
|
+
${source_default.yellow(".principal-views/data-validator.workflow.json")}
|
|
216638
216741
|
|
|
216639
216742
|
{
|
|
216640
216743
|
"name": "Data Validator",
|
|
@@ -216734,7 +216837,7 @@ ${source_default.yellow("__executions__/data-validator.otel.json")}
|
|
|
216734
216837
|
|
|
216735
216838
|
${source_default.bold("Next Steps:")}
|
|
216736
216839
|
${source_default.cyan("npx @principal-ai/principal-view-cli validate")} Validate canvas
|
|
216737
|
-
${source_default.cyan("npx @principal-ai/principal-view-cli
|
|
216840
|
+
${source_default.cyan("npx @principal-ai/principal-view-cli workflow validate")} Validate workflows
|
|
216738
216841
|
${source_default.cyan("npx @principal-ai/principal-view-cli validate-execution")} Validate execution
|
|
216739
216842
|
`
|
|
216740
216843
|
};
|
|
@@ -216742,7 +216845,7 @@ function createFormatsCommand() {
|
|
|
216742
216845
|
const command = new Command("formats");
|
|
216743
216846
|
command.description("Display documentation about file formats").argument(
|
|
216744
216847
|
"[section]",
|
|
216745
|
-
"Section to display: overview, canvas,
|
|
216848
|
+
"Section to display: overview, canvas, workflow, execution, examples"
|
|
216746
216849
|
).action((section) => {
|
|
216747
216850
|
const validSections = Object.keys(FORMAT_SECTIONS);
|
|
216748
216851
|
if (!section) {
|
|
@@ -220293,12 +220396,12 @@ function createDefaultRulesEngine() {
|
|
|
220293
220396
|
return createRulesEngine(builtinRules);
|
|
220294
220397
|
}
|
|
220295
220398
|
|
|
220296
|
-
// ../core/dist/
|
|
220399
|
+
// ../core/dist/workflow/validator.js
|
|
220297
220400
|
var import_fs = require("fs");
|
|
220298
220401
|
var import_path2 = require("path");
|
|
220299
|
-
var
|
|
220402
|
+
var WorkflowValidator = class {
|
|
220300
220403
|
/**
|
|
220301
|
-
* Validate a
|
|
220404
|
+
* Validate a workflow template
|
|
220302
220405
|
*/
|
|
220303
220406
|
async validate(context) {
|
|
220304
220407
|
const violations = [];
|
|
@@ -220319,122 +220422,122 @@ var NarrativeValidator = class {
|
|
|
220319
220422
|
*/
|
|
220320
220423
|
checkSchema(context) {
|
|
220321
220424
|
const violations = [];
|
|
220322
|
-
const {
|
|
220323
|
-
if (!
|
|
220425
|
+
const { workflow, workflowPath } = context;
|
|
220426
|
+
if (!workflow.version) {
|
|
220324
220427
|
violations.push({
|
|
220325
|
-
ruleId: "
|
|
220428
|
+
ruleId: "workflow-schema-valid",
|
|
220326
220429
|
severity: "error",
|
|
220327
|
-
file:
|
|
220430
|
+
file: workflowPath,
|
|
220328
220431
|
path: "version",
|
|
220329
220432
|
message: 'Missing required field "version"',
|
|
220330
220433
|
impact: "Cannot determine template version for compatibility",
|
|
220331
220434
|
suggestion: 'Add a version field (e.g., "1.0.0")',
|
|
220332
220435
|
fixable: false
|
|
220333
220436
|
});
|
|
220334
|
-
} else if (!this.isValidSemver(
|
|
220437
|
+
} else if (!this.isValidSemver(workflow.version)) {
|
|
220335
220438
|
violations.push({
|
|
220336
|
-
ruleId: "
|
|
220439
|
+
ruleId: "workflow-schema-valid",
|
|
220337
220440
|
severity: "error",
|
|
220338
|
-
file:
|
|
220441
|
+
file: workflowPath,
|
|
220339
220442
|
path: "version",
|
|
220340
|
-
message: `Invalid version format: "${
|
|
220443
|
+
message: `Invalid version format: "${workflow.version}"`,
|
|
220341
220444
|
impact: "Version must follow semver format",
|
|
220342
220445
|
suggestion: 'Use semver format like "1.0.0"',
|
|
220343
220446
|
fixable: false
|
|
220344
220447
|
});
|
|
220345
220448
|
}
|
|
220346
|
-
if (!
|
|
220449
|
+
if (!workflow.canvas) {
|
|
220347
220450
|
violations.push({
|
|
220348
|
-
ruleId: "
|
|
220451
|
+
ruleId: "workflow-schema-valid",
|
|
220349
220452
|
severity: "error",
|
|
220350
|
-
file:
|
|
220453
|
+
file: workflowPath,
|
|
220351
220454
|
path: "canvas",
|
|
220352
220455
|
message: 'Missing required field "canvas"',
|
|
220353
|
-
impact: "Cannot determine which canvas this
|
|
220456
|
+
impact: "Cannot determine which canvas this workflow belongs to",
|
|
220354
220457
|
suggestion: "Add a canvas field pointing to an .otel.canvas file",
|
|
220355
220458
|
fixable: false
|
|
220356
220459
|
});
|
|
220357
220460
|
}
|
|
220358
|
-
if (!
|
|
220461
|
+
if (!workflow.name) {
|
|
220359
220462
|
violations.push({
|
|
220360
|
-
ruleId: "
|
|
220463
|
+
ruleId: "workflow-schema-valid",
|
|
220361
220464
|
severity: "error",
|
|
220362
|
-
file:
|
|
220465
|
+
file: workflowPath,
|
|
220363
220466
|
path: "name",
|
|
220364
220467
|
message: 'Missing required field "name"',
|
|
220365
|
-
impact: "Cannot identify this
|
|
220468
|
+
impact: "Cannot identify this workflow template",
|
|
220366
220469
|
suggestion: "Add a human-readable name",
|
|
220367
220470
|
fixable: false
|
|
220368
220471
|
});
|
|
220369
220472
|
}
|
|
220370
|
-
if (!
|
|
220473
|
+
if (!workflow.description) {
|
|
220371
220474
|
violations.push({
|
|
220372
|
-
ruleId: "
|
|
220475
|
+
ruleId: "workflow-schema-valid",
|
|
220373
220476
|
severity: "error",
|
|
220374
|
-
file:
|
|
220477
|
+
file: workflowPath,
|
|
220375
220478
|
path: "description",
|
|
220376
220479
|
message: 'Missing required field "description"',
|
|
220377
|
-
impact: "Cannot understand the purpose of this
|
|
220378
|
-
suggestion: "Add a description explaining what this
|
|
220480
|
+
impact: "Cannot understand the purpose of this workflow",
|
|
220481
|
+
suggestion: "Add a description explaining what this workflow shows",
|
|
220379
220482
|
fixable: false
|
|
220380
220483
|
});
|
|
220381
220484
|
}
|
|
220382
220485
|
const validModes = ["span-tree", "timeline"];
|
|
220383
|
-
if (!
|
|
220486
|
+
if (!workflow.mode) {
|
|
220384
220487
|
violations.push({
|
|
220385
|
-
ruleId: "
|
|
220488
|
+
ruleId: "workflow-schema-valid",
|
|
220386
220489
|
severity: "error",
|
|
220387
|
-
file:
|
|
220490
|
+
file: workflowPath,
|
|
220388
220491
|
path: "mode",
|
|
220389
220492
|
message: 'Missing required field "mode"',
|
|
220390
|
-
impact: "Cannot determine how to structure the
|
|
220493
|
+
impact: "Cannot determine how to structure the workflow",
|
|
220391
220494
|
suggestion: `Set mode to one of: ${validModes.join(", ")}`,
|
|
220392
220495
|
fixable: false
|
|
220393
220496
|
});
|
|
220394
|
-
} else if (!validModes.includes(
|
|
220497
|
+
} else if (!validModes.includes(workflow.mode)) {
|
|
220395
220498
|
violations.push({
|
|
220396
|
-
ruleId: "
|
|
220499
|
+
ruleId: "workflow-schema-valid",
|
|
220397
220500
|
severity: "error",
|
|
220398
|
-
file:
|
|
220501
|
+
file: workflowPath,
|
|
220399
220502
|
path: "mode",
|
|
220400
|
-
message: `Invalid mode: "${
|
|
220503
|
+
message: `Invalid mode: "${workflow.mode}"`,
|
|
220401
220504
|
impact: "Mode must be one of the supported types",
|
|
220402
220505
|
suggestion: `Use one of: ${validModes.join(", ")}`,
|
|
220403
220506
|
fixable: false
|
|
220404
220507
|
});
|
|
220405
220508
|
}
|
|
220406
220509
|
const validSelections = ["first-match", "manual"];
|
|
220407
|
-
if (
|
|
220510
|
+
if (workflow.scenarioSelection && !validSelections.includes(workflow.scenarioSelection)) {
|
|
220408
220511
|
violations.push({
|
|
220409
|
-
ruleId: "
|
|
220512
|
+
ruleId: "workflow-schema-valid",
|
|
220410
220513
|
severity: "error",
|
|
220411
|
-
file:
|
|
220514
|
+
file: workflowPath,
|
|
220412
220515
|
path: "scenarioSelection",
|
|
220413
|
-
message: `Invalid scenarioSelection: "${
|
|
220516
|
+
message: `Invalid scenarioSelection: "${workflow.scenarioSelection}"`,
|
|
220414
220517
|
impact: "Scenario selection must be a valid type",
|
|
220415
220518
|
suggestion: `Use one of: ${validSelections.join(", ")}`,
|
|
220416
220519
|
fixable: false
|
|
220417
220520
|
});
|
|
220418
220521
|
}
|
|
220419
|
-
if (!
|
|
220522
|
+
if (!workflow.scenarios || !Array.isArray(workflow.scenarios)) {
|
|
220420
220523
|
violations.push({
|
|
220421
|
-
ruleId: "
|
|
220524
|
+
ruleId: "workflow-schema-valid",
|
|
220422
220525
|
severity: "error",
|
|
220423
|
-
file:
|
|
220526
|
+
file: workflowPath,
|
|
220424
220527
|
path: "scenarios",
|
|
220425
220528
|
message: 'Missing or invalid "scenarios" field',
|
|
220426
|
-
impact: "Cannot generate
|
|
220529
|
+
impact: "Cannot generate workflows without scenarios",
|
|
220427
220530
|
suggestion: "Add a scenarios array with at least one scenario",
|
|
220428
220531
|
fixable: false
|
|
220429
220532
|
});
|
|
220430
|
-
} else if (
|
|
220533
|
+
} else if (workflow.scenarios.length === 0) {
|
|
220431
220534
|
violations.push({
|
|
220432
|
-
ruleId: "
|
|
220535
|
+
ruleId: "workflow-schema-valid",
|
|
220433
220536
|
severity: "error",
|
|
220434
|
-
file:
|
|
220537
|
+
file: workflowPath,
|
|
220435
220538
|
path: "scenarios",
|
|
220436
220539
|
message: "Scenarios array is empty",
|
|
220437
|
-
impact: "Cannot generate
|
|
220540
|
+
impact: "Cannot generate workflows without scenarios",
|
|
220438
220541
|
suggestion: "Add at least one scenario definition",
|
|
220439
220542
|
fixable: false
|
|
220440
220543
|
});
|
|
@@ -220446,18 +220549,18 @@ var NarrativeValidator = class {
|
|
|
220446
220549
|
*/
|
|
220447
220550
|
checkCanvasExists(context) {
|
|
220448
220551
|
const violations = [];
|
|
220449
|
-
const {
|
|
220450
|
-
if (!
|
|
220552
|
+
const { workflow, workflowPath, basePath, canvasPath } = context;
|
|
220553
|
+
if (!workflow.canvas) {
|
|
220451
220554
|
return violations;
|
|
220452
220555
|
}
|
|
220453
|
-
const resolvedPath = canvasPath || (0, import_path2.resolve)(basePath,
|
|
220556
|
+
const resolvedPath = canvasPath || (0, import_path2.resolve)(basePath, workflow.canvas);
|
|
220454
220557
|
if (!(0, import_fs.existsSync)(resolvedPath)) {
|
|
220455
220558
|
violations.push({
|
|
220456
|
-
ruleId: "
|
|
220559
|
+
ruleId: "workflow-canvas-exists",
|
|
220457
220560
|
severity: "error",
|
|
220458
|
-
file:
|
|
220561
|
+
file: workflowPath,
|
|
220459
220562
|
path: "canvas",
|
|
220460
|
-
message: `Referenced canvas file does not exist: ${
|
|
220563
|
+
message: `Referenced canvas file does not exist: ${workflow.canvas}`,
|
|
220461
220564
|
impact: "Cannot validate event references without the canvas",
|
|
220462
220565
|
suggestion: "Ensure the canvas field points to a valid .otel.canvas file",
|
|
220463
220566
|
fixable: false
|
|
@@ -220474,7 +220577,7 @@ var NarrativeValidator = class {
|
|
|
220474
220577
|
*/
|
|
220475
220578
|
checkEventReferences(context) {
|
|
220476
220579
|
const violations = [];
|
|
220477
|
-
const {
|
|
220580
|
+
const { workflow, workflowPath, canvas } = context;
|
|
220478
220581
|
if (!canvas || !canvas.nodes) {
|
|
220479
220582
|
return violations;
|
|
220480
220583
|
}
|
|
@@ -220485,10 +220588,10 @@ var NarrativeValidator = class {
|
|
|
220485
220588
|
violations.push({
|
|
220486
220589
|
ruleId: "canvas-event-format-deprecated",
|
|
220487
220590
|
severity: "error",
|
|
220488
|
-
file:
|
|
220591
|
+
file: workflow.canvas || "canvas",
|
|
220489
220592
|
path: `nodes[${node.id}].pv.event`,
|
|
220490
220593
|
message: `Canvas node "${node.id}" uses deprecated string format for event: "${node.pv.event}"`,
|
|
220491
|
-
impact: "Event will not be recognized by
|
|
220594
|
+
impact: "Event will not be recognized by workflow validator and workflows will fail to match",
|
|
220492
220595
|
suggestion: `Use "eventRef": "${node.pv.event}" to reference a library event, or use "event": { "name": "${node.pv.event}", "attributes": {} } for inline definition. If using eventRef, define the event schema in library.yaml under eventSchemas.`,
|
|
220493
220596
|
fixable: false
|
|
220494
220597
|
});
|
|
@@ -220500,47 +220603,47 @@ var NarrativeValidator = class {
|
|
|
220500
220603
|
canvasEvents.add(node.pv.eventRef);
|
|
220501
220604
|
}
|
|
220502
220605
|
}
|
|
220503
|
-
const
|
|
220504
|
-
for (const scenario of
|
|
220606
|
+
const workflowEvents = /* @__PURE__ */ new Set();
|
|
220607
|
+
for (const scenario of workflow.scenarios) {
|
|
220505
220608
|
if (scenario.condition?.requires) {
|
|
220506
220609
|
for (const eventPattern of scenario.condition.requires) {
|
|
220507
220610
|
if (!eventPattern.includes("*")) {
|
|
220508
|
-
|
|
220611
|
+
workflowEvents.add(eventPattern);
|
|
220509
220612
|
}
|
|
220510
220613
|
}
|
|
220511
220614
|
}
|
|
220512
220615
|
if (scenario.template?.events) {
|
|
220513
220616
|
for (const eventName of Object.keys(scenario.template.events)) {
|
|
220514
220617
|
if (!eventName.includes("*")) {
|
|
220515
|
-
|
|
220618
|
+
workflowEvents.add(eventName);
|
|
220516
220619
|
}
|
|
220517
220620
|
}
|
|
220518
220621
|
}
|
|
220519
220622
|
}
|
|
220520
|
-
for (const eventName of Array.from(
|
|
220623
|
+
for (const eventName of Array.from(workflowEvents)) {
|
|
220521
220624
|
if (!canvasEvents.has(eventName)) {
|
|
220522
220625
|
violations.push({
|
|
220523
|
-
ruleId: "
|
|
220626
|
+
ruleId: "workflow-event-sync",
|
|
220524
220627
|
severity: "error",
|
|
220525
|
-
file:
|
|
220628
|
+
file: workflowPath,
|
|
220526
220629
|
path: "events",
|
|
220527
|
-
message: `
|
|
220630
|
+
message: `Workflow references event "${eventName}" which is not defined in canvas`,
|
|
220528
220631
|
impact: "This event will never highlight a canvas node and may never match",
|
|
220529
|
-
suggestion: `Add event "${eventName}" to a node in ${
|
|
220632
|
+
suggestion: `Add event "${eventName}" to a node in ${workflow.canvas} or remove it from the workflow`,
|
|
220530
220633
|
fixable: false
|
|
220531
220634
|
});
|
|
220532
220635
|
}
|
|
220533
220636
|
}
|
|
220534
|
-
const eventsToCheckAgainst = context.
|
|
220637
|
+
const eventsToCheckAgainst = context.allWorkflowEvents ?? workflowEvents;
|
|
220535
220638
|
for (const eventName of Array.from(canvasEvents)) {
|
|
220536
220639
|
if (!eventsToCheckAgainst.has(eventName)) {
|
|
220537
220640
|
violations.push({
|
|
220538
|
-
ruleId: "
|
|
220641
|
+
ruleId: "workflow-event-coverage",
|
|
220539
220642
|
severity: "warn",
|
|
220540
|
-
file:
|
|
220643
|
+
file: workflowPath,
|
|
220541
220644
|
path: "events",
|
|
220542
|
-
message: context.
|
|
220543
|
-
impact: "This canvas node may never be highlighted during
|
|
220645
|
+
message: context.allWorkflowEvents ? `Canvas defines event "${eventName}" which is not used in any workflow for this canvas` : `Canvas defines event "${eventName}" which is not used in this workflow scenario`,
|
|
220646
|
+
impact: "This canvas node may never be highlighted during workflow playback",
|
|
220544
220647
|
suggestion: `Add event "${eventName}" to a scenario's template.events or condition.requires`,
|
|
220545
220648
|
fixable: false
|
|
220546
220649
|
});
|
|
@@ -220553,19 +220656,19 @@ var NarrativeValidator = class {
|
|
|
220553
220656
|
*/
|
|
220554
220657
|
checkScenarios(context) {
|
|
220555
220658
|
const violations = [];
|
|
220556
|
-
const {
|
|
220557
|
-
if (!
|
|
220659
|
+
const { workflow, workflowPath } = context;
|
|
220660
|
+
if (!workflow.scenarios || workflow.scenarios.length === 0) {
|
|
220558
220661
|
return violations;
|
|
220559
220662
|
}
|
|
220560
220663
|
const scenarioIds = /* @__PURE__ */ new Set();
|
|
220561
220664
|
const priorities = /* @__PURE__ */ new Set();
|
|
220562
220665
|
let hasDefault = false;
|
|
220563
|
-
|
|
220666
|
+
workflow.scenarios.forEach((scenario, idx) => {
|
|
220564
220667
|
if (!scenario.id) {
|
|
220565
220668
|
violations.push({
|
|
220566
|
-
ruleId: "
|
|
220669
|
+
ruleId: "workflow-scenario-valid",
|
|
220567
220670
|
severity: "error",
|
|
220568
|
-
file:
|
|
220671
|
+
file: workflowPath,
|
|
220569
220672
|
path: `scenarios[${idx}].id`,
|
|
220570
220673
|
message: 'Scenario is missing required "id" field',
|
|
220571
220674
|
impact: "Cannot identify this scenario",
|
|
@@ -220575,9 +220678,9 @@ var NarrativeValidator = class {
|
|
|
220575
220678
|
} else {
|
|
220576
220679
|
if (scenarioIds.has(scenario.id)) {
|
|
220577
220680
|
violations.push({
|
|
220578
|
-
ruleId: "
|
|
220681
|
+
ruleId: "workflow-scenario-valid",
|
|
220579
220682
|
severity: "error",
|
|
220580
|
-
file:
|
|
220683
|
+
file: workflowPath,
|
|
220581
220684
|
path: `scenarios[${idx}].id`,
|
|
220582
220685
|
message: `Duplicate scenario ID: "${scenario.id}"`,
|
|
220583
220686
|
impact: "Scenario IDs must be unique",
|
|
@@ -220589,9 +220692,9 @@ var NarrativeValidator = class {
|
|
|
220589
220692
|
}
|
|
220590
220693
|
if (scenario.priority === void 0 || scenario.priority === null) {
|
|
220591
220694
|
violations.push({
|
|
220592
|
-
ruleId: "
|
|
220695
|
+
ruleId: "workflow-scenario-valid",
|
|
220593
220696
|
severity: "error",
|
|
220594
|
-
file:
|
|
220697
|
+
file: workflowPath,
|
|
220595
220698
|
path: `scenarios[${idx}].priority`,
|
|
220596
220699
|
message: 'Scenario is missing required "priority" field',
|
|
220597
220700
|
impact: "Cannot determine scenario selection order",
|
|
@@ -220601,9 +220704,9 @@ var NarrativeValidator = class {
|
|
|
220601
220704
|
} else {
|
|
220602
220705
|
if (scenario.priority < 0) {
|
|
220603
220706
|
violations.push({
|
|
220604
|
-
ruleId: "
|
|
220707
|
+
ruleId: "workflow-scenario-valid",
|
|
220605
220708
|
severity: "error",
|
|
220606
|
-
file:
|
|
220709
|
+
file: workflowPath,
|
|
220607
220710
|
path: `scenarios[${idx}].priority`,
|
|
220608
220711
|
message: "Priority must be a non-negative number",
|
|
220609
220712
|
impact: "Invalid priority value",
|
|
@@ -220613,9 +220716,9 @@ var NarrativeValidator = class {
|
|
|
220613
220716
|
}
|
|
220614
220717
|
if (priorities.has(scenario.priority)) {
|
|
220615
220718
|
violations.push({
|
|
220616
|
-
ruleId: "
|
|
220719
|
+
ruleId: "workflow-scenario-valid",
|
|
220617
220720
|
severity: "error",
|
|
220618
|
-
file:
|
|
220721
|
+
file: workflowPath,
|
|
220619
220722
|
path: `scenarios[${idx}].priority`,
|
|
220620
220723
|
message: `Duplicate priority: ${scenario.priority}`,
|
|
220621
220724
|
impact: "Priorities must be unique to determine selection order",
|
|
@@ -220630,9 +220733,9 @@ var NarrativeValidator = class {
|
|
|
220630
220733
|
}
|
|
220631
220734
|
if (!scenario.condition) {
|
|
220632
220735
|
violations.push({
|
|
220633
|
-
ruleId: "
|
|
220736
|
+
ruleId: "workflow-scenario-valid",
|
|
220634
220737
|
severity: "error",
|
|
220635
|
-
file:
|
|
220738
|
+
file: workflowPath,
|
|
220636
220739
|
path: `scenarios[${idx}].condition`,
|
|
220637
220740
|
message: 'Scenario is missing required "condition" field',
|
|
220638
220741
|
impact: "Cannot determine when to use this scenario",
|
|
@@ -220640,31 +220743,31 @@ var NarrativeValidator = class {
|
|
|
220640
220743
|
fixable: false
|
|
220641
220744
|
});
|
|
220642
220745
|
} else {
|
|
220643
|
-
violations.push(...this.checkConditionStructure(scenario.condition,
|
|
220746
|
+
violations.push(...this.checkConditionStructure(scenario.condition, workflowPath, idx));
|
|
220644
220747
|
}
|
|
220645
220748
|
if (!scenario.template) {
|
|
220646
220749
|
violations.push({
|
|
220647
|
-
ruleId: "
|
|
220750
|
+
ruleId: "workflow-scenario-valid",
|
|
220648
220751
|
severity: "error",
|
|
220649
|
-
file:
|
|
220752
|
+
file: workflowPath,
|
|
220650
220753
|
path: `scenarios[${idx}].template`,
|
|
220651
220754
|
message: 'Scenario is missing required "template" field',
|
|
220652
|
-
impact: "Cannot render
|
|
220755
|
+
impact: "Cannot render workflow without a template",
|
|
220653
220756
|
suggestion: "Add a template with introduction, events, or flow",
|
|
220654
220757
|
fixable: false
|
|
220655
220758
|
});
|
|
220656
220759
|
} else {
|
|
220657
|
-
violations.push(...this.checkTemplateStructure(scenario.template,
|
|
220760
|
+
violations.push(...this.checkTemplateStructure(scenario.template, workflowPath, idx));
|
|
220658
220761
|
}
|
|
220659
220762
|
});
|
|
220660
220763
|
if (!hasDefault) {
|
|
220661
220764
|
violations.push({
|
|
220662
|
-
ruleId: "
|
|
220765
|
+
ruleId: "workflow-scenario-valid",
|
|
220663
220766
|
severity: "error",
|
|
220664
|
-
file:
|
|
220767
|
+
file: workflowPath,
|
|
220665
220768
|
path: "scenarios",
|
|
220666
220769
|
message: "No default scenario defined",
|
|
220667
|
-
impact: "
|
|
220770
|
+
impact: "Workflow rendering may fail if no scenario matches",
|
|
220668
220771
|
suggestion: 'Add a scenario with "condition.default: true" as a fallback',
|
|
220669
220772
|
fixable: false
|
|
220670
220773
|
});
|
|
@@ -220685,7 +220788,7 @@ var NarrativeValidator = class {
|
|
|
220685
220788
|
if (!validFields.includes(key)) {
|
|
220686
220789
|
if (key === "event") {
|
|
220687
220790
|
violations.push({
|
|
220688
|
-
ruleId: "
|
|
220791
|
+
ruleId: "workflow-condition-structure",
|
|
220689
220792
|
severity: "error",
|
|
220690
220793
|
file,
|
|
220691
220794
|
path: `scenarios[${scenarioIdx}].condition.${key}`,
|
|
@@ -220696,7 +220799,7 @@ var NarrativeValidator = class {
|
|
|
220696
220799
|
});
|
|
220697
220800
|
} else if (key === "attributes") {
|
|
220698
220801
|
violations.push({
|
|
220699
|
-
ruleId: "
|
|
220802
|
+
ruleId: "workflow-condition-structure",
|
|
220700
220803
|
severity: "error",
|
|
220701
220804
|
file,
|
|
220702
220805
|
path: `scenarios[${scenarioIdx}].condition.${key}`,
|
|
@@ -220707,7 +220810,7 @@ var NarrativeValidator = class {
|
|
|
220707
220810
|
});
|
|
220708
220811
|
} else {
|
|
220709
220812
|
violations.push({
|
|
220710
|
-
ruleId: "
|
|
220813
|
+
ruleId: "workflow-condition-structure",
|
|
220711
220814
|
severity: "error",
|
|
220712
220815
|
file,
|
|
220713
220816
|
path: `scenarios[${scenarioIdx}].condition.${key}`,
|
|
@@ -220730,7 +220833,7 @@ var NarrativeValidator = class {
|
|
|
220730
220833
|
const templateKeys = Object.keys(template);
|
|
220731
220834
|
if (!template.events) {
|
|
220732
220835
|
violations.push({
|
|
220733
|
-
ruleId: "
|
|
220836
|
+
ruleId: "workflow-template-structure",
|
|
220734
220837
|
severity: "error",
|
|
220735
220838
|
file,
|
|
220736
220839
|
path: `scenarios[${scenarioIdx}].template`,
|
|
@@ -220741,7 +220844,7 @@ var NarrativeValidator = class {
|
|
|
220741
220844
|
});
|
|
220742
220845
|
} else if (typeof template.events !== "object" || Array.isArray(template.events)) {
|
|
220743
220846
|
violations.push({
|
|
220744
|
-
ruleId: "
|
|
220847
|
+
ruleId: "workflow-template-structure",
|
|
220745
220848
|
severity: "error",
|
|
220746
220849
|
file,
|
|
220747
220850
|
path: `scenarios[${scenarioIdx}].template.events`,
|
|
@@ -220752,7 +220855,7 @@ var NarrativeValidator = class {
|
|
|
220752
220855
|
});
|
|
220753
220856
|
} else if (Object.keys(template.events).length === 0) {
|
|
220754
220857
|
violations.push({
|
|
220755
|
-
ruleId: "
|
|
220858
|
+
ruleId: "workflow-template-structure",
|
|
220756
220859
|
severity: "error",
|
|
220757
220860
|
file,
|
|
220758
220861
|
path: `scenarios[${scenarioIdx}].template.events`,
|
|
@@ -220766,7 +220869,7 @@ var NarrativeValidator = class {
|
|
|
220766
220869
|
if (!validFields.includes(key)) {
|
|
220767
220870
|
if (key === "steps") {
|
|
220768
220871
|
violations.push({
|
|
220769
|
-
ruleId: "
|
|
220872
|
+
ruleId: "workflow-template-structure",
|
|
220770
220873
|
severity: "error",
|
|
220771
220874
|
file,
|
|
220772
220875
|
path: `scenarios[${scenarioIdx}].template.${key}`,
|
|
@@ -220777,7 +220880,7 @@ var NarrativeValidator = class {
|
|
|
220777
220880
|
});
|
|
220778
220881
|
} else if (key === "details") {
|
|
220779
220882
|
violations.push({
|
|
220780
|
-
ruleId: "
|
|
220883
|
+
ruleId: "workflow-template-structure",
|
|
220781
220884
|
severity: "error",
|
|
220782
220885
|
file,
|
|
220783
220886
|
path: `scenarios[${scenarioIdx}].template.${key}`,
|
|
@@ -220788,7 +220891,7 @@ var NarrativeValidator = class {
|
|
|
220788
220891
|
});
|
|
220789
220892
|
} else {
|
|
220790
220893
|
violations.push({
|
|
220791
|
-
ruleId: "
|
|
220894
|
+
ruleId: "workflow-template-structure",
|
|
220792
220895
|
severity: "error",
|
|
220793
220896
|
file,
|
|
220794
220897
|
path: `scenarios[${scenarioIdx}].template.${key}`,
|
|
@@ -220807,15 +220910,15 @@ var NarrativeValidator = class {
|
|
|
220807
220910
|
*/
|
|
220808
220911
|
checkEventNameSyntax(context) {
|
|
220809
220912
|
const violations = [];
|
|
220810
|
-
const {
|
|
220811
|
-
|
|
220913
|
+
const { workflow, workflowPath } = context;
|
|
220914
|
+
workflow.scenarios.forEach((scenario, scenarioIdx) => {
|
|
220812
220915
|
if (scenario.condition?.requires) {
|
|
220813
220916
|
scenario.condition.requires.forEach((eventPattern, idx) => {
|
|
220814
220917
|
if (eventPattern.includes("[") && eventPattern.includes("]")) {
|
|
220815
220918
|
violations.push({
|
|
220816
|
-
ruleId: "
|
|
220919
|
+
ruleId: "workflow-event-name-syntax",
|
|
220817
220920
|
severity: "error",
|
|
220818
|
-
file:
|
|
220921
|
+
file: workflowPath,
|
|
220819
220922
|
path: `scenarios[${scenarioIdx}].condition.requires[${idx}]`,
|
|
220820
220923
|
message: `Event name uses unsupported [attribute=value] syntax: "${eventPattern}"`,
|
|
220821
220924
|
impact: "Attribute filter syntax is not supported - event will not match",
|
|
@@ -220829,9 +220932,9 @@ var NarrativeValidator = class {
|
|
|
220829
220932
|
scenario.condition.excludes.forEach((eventPattern, idx) => {
|
|
220830
220933
|
if (eventPattern.includes("[") && eventPattern.includes("]")) {
|
|
220831
220934
|
violations.push({
|
|
220832
|
-
ruleId: "
|
|
220935
|
+
ruleId: "workflow-event-name-syntax",
|
|
220833
220936
|
severity: "error",
|
|
220834
|
-
file:
|
|
220937
|
+
file: workflowPath,
|
|
220835
220938
|
path: `scenarios[${scenarioIdx}].condition.excludes[${idx}]`,
|
|
220836
220939
|
message: `Event name uses unsupported [attribute=value] syntax: "${eventPattern}"`,
|
|
220837
220940
|
impact: "Attribute filter syntax is not supported - event will not match",
|
|
@@ -220845,9 +220948,9 @@ var NarrativeValidator = class {
|
|
|
220845
220948
|
Object.keys(scenario.template.events).forEach((eventName) => {
|
|
220846
220949
|
if (eventName.includes("[") && eventName.includes("]")) {
|
|
220847
220950
|
violations.push({
|
|
220848
|
-
ruleId: "
|
|
220951
|
+
ruleId: "workflow-event-name-syntax",
|
|
220849
220952
|
severity: "error",
|
|
220850
|
-
file:
|
|
220953
|
+
file: workflowPath,
|
|
220851
220954
|
path: `scenarios[${scenarioIdx}].template.events["${eventName}"]`,
|
|
220852
220955
|
message: `Event name uses unsupported [attribute=value] syntax: "${eventName}"`,
|
|
220853
220956
|
impact: "Attribute filter syntax is not supported - template will never render",
|
|
@@ -220865,36 +220968,36 @@ var NarrativeValidator = class {
|
|
|
220865
220968
|
*/
|
|
220866
220969
|
checkTemplateSyntax(context) {
|
|
220867
220970
|
const violations = [];
|
|
220868
|
-
const {
|
|
220869
|
-
|
|
220971
|
+
const { workflow, workflowPath } = context;
|
|
220972
|
+
workflow.scenarios.forEach((scenario, scenarioIdx) => {
|
|
220870
220973
|
if (!scenario.template) {
|
|
220871
220974
|
return;
|
|
220872
220975
|
}
|
|
220873
220976
|
const template = scenario.template;
|
|
220874
220977
|
if (template.introduction) {
|
|
220875
|
-
violations.push(...this.validateTemplateString(template.introduction,
|
|
220978
|
+
violations.push(...this.validateTemplateString(template.introduction, workflowPath, `scenarios[${scenarioIdx}].template.introduction`));
|
|
220876
220979
|
}
|
|
220877
220980
|
if (template.summary) {
|
|
220878
|
-
violations.push(...this.validateTemplateString(template.summary,
|
|
220981
|
+
violations.push(...this.validateTemplateString(template.summary, workflowPath, `scenarios[${scenarioIdx}].template.summary`));
|
|
220879
220982
|
}
|
|
220880
220983
|
if (template.events) {
|
|
220881
220984
|
Object.entries(template.events).forEach(([eventName, templateStr]) => {
|
|
220882
|
-
violations.push(...this.validateTemplateString(templateStr,
|
|
220985
|
+
violations.push(...this.validateTemplateString(templateStr, workflowPath, `scenarios[${scenarioIdx}].template.events.${eventName}`));
|
|
220883
220986
|
});
|
|
220884
220987
|
}
|
|
220885
220988
|
if (template.logs) {
|
|
220886
220989
|
Object.entries(template.logs).forEach(([severity, templateStr]) => {
|
|
220887
220990
|
if (typeof templateStr === "string") {
|
|
220888
|
-
violations.push(...this.validateTemplateString(templateStr,
|
|
220991
|
+
violations.push(...this.validateTemplateString(templateStr, workflowPath, `scenarios[${scenarioIdx}].template.logs.${severity}`));
|
|
220889
220992
|
}
|
|
220890
220993
|
});
|
|
220891
220994
|
}
|
|
220892
220995
|
if (template.flow && Array.isArray(template.flow)) {
|
|
220893
220996
|
template.flow.forEach((item, flowIdx) => {
|
|
220894
220997
|
if (typeof item === "string") {
|
|
220895
|
-
violations.push(...this.validateTemplateString(item,
|
|
220998
|
+
violations.push(...this.validateTemplateString(item, workflowPath, `scenarios[${scenarioIdx}].template.flow[${flowIdx}]`));
|
|
220896
220999
|
} else if (typeof item === "object" && item.template) {
|
|
220897
|
-
violations.push(...this.validateTemplateString(item.template,
|
|
221000
|
+
violations.push(...this.validateTemplateString(item.template, workflowPath, `scenarios[${scenarioIdx}].template.flow[${flowIdx}].template`));
|
|
220898
221001
|
}
|
|
220899
221002
|
});
|
|
220900
221003
|
}
|
|
@@ -220928,7 +221031,7 @@ var NarrativeValidator = class {
|
|
|
220928
221031
|
braceDepth--;
|
|
220929
221032
|
if (braceDepth < 0) {
|
|
220930
221033
|
violations.push({
|
|
220931
|
-
ruleId: "
|
|
221034
|
+
ruleId: "workflow-template-syntax",
|
|
220932
221035
|
severity: "error",
|
|
220933
221036
|
file,
|
|
220934
221037
|
path: path4,
|
|
@@ -220944,7 +221047,7 @@ var NarrativeValidator = class {
|
|
|
220944
221047
|
}
|
|
220945
221048
|
if (braceDepth > 0) {
|
|
220946
221049
|
violations.push({
|
|
220947
|
-
ruleId: "
|
|
221050
|
+
ruleId: "workflow-template-syntax",
|
|
220948
221051
|
severity: "error",
|
|
220949
221052
|
file,
|
|
220950
221053
|
path: path4,
|
|
@@ -220961,7 +221064,7 @@ var NarrativeValidator = class {
|
|
|
220961
221064
|
const colonCount = (expr.match(/:/g) || []).length;
|
|
220962
221065
|
if (questionCount > colonCount) {
|
|
220963
221066
|
violations.push({
|
|
220964
|
-
ruleId: "
|
|
221067
|
+
ruleId: "workflow-template-syntax",
|
|
220965
221068
|
severity: "error",
|
|
220966
221069
|
file,
|
|
220967
221070
|
path: path4,
|
|
@@ -220984,12 +221087,12 @@ var NarrativeValidator = class {
|
|
|
220984
221087
|
*/
|
|
220985
221088
|
checkAttributeReferences(context) {
|
|
220986
221089
|
const violations = [];
|
|
220987
|
-
const {
|
|
221090
|
+
const { workflow, workflowPath, executionData } = context;
|
|
220988
221091
|
if (!executionData) {
|
|
220989
221092
|
return violations;
|
|
220990
221093
|
}
|
|
220991
221094
|
const { aggregates, eventAttributes } = executionData;
|
|
220992
|
-
for (const scenario of
|
|
221095
|
+
for (const scenario of workflow.scenarios) {
|
|
220993
221096
|
const scenarioPath = `scenarios[${scenario.id}]`;
|
|
220994
221097
|
if (scenario.template.introduction) {
|
|
220995
221098
|
const attrs = this.extractAttributeReferences(scenario.template.introduction);
|
|
@@ -220998,7 +221101,7 @@ var NarrativeValidator = class {
|
|
|
220998
221101
|
aggregates,
|
|
220999
221102
|
null,
|
|
221000
221103
|
// introduction doesn't have specific event context
|
|
221001
|
-
|
|
221104
|
+
workflowPath,
|
|
221002
221105
|
`${scenarioPath}.template.introduction`
|
|
221003
221106
|
));
|
|
221004
221107
|
}
|
|
@@ -221006,7 +221109,7 @@ var NarrativeValidator = class {
|
|
|
221006
221109
|
for (const [eventName, eventTemplate] of Object.entries(scenario.template.events)) {
|
|
221007
221110
|
const attrs = this.extractAttributeReferences(eventTemplate);
|
|
221008
221111
|
const eventAttrs = eventAttributes.get(eventName);
|
|
221009
|
-
violations.push(...this.validateAttributes(attrs, aggregates, eventAttrs || null,
|
|
221112
|
+
violations.push(...this.validateAttributes(attrs, aggregates, eventAttrs || null, workflowPath, `${scenarioPath}.template.events.${eventName}`, eventName));
|
|
221010
221113
|
}
|
|
221011
221114
|
}
|
|
221012
221115
|
if (scenario.template.summary) {
|
|
@@ -221016,7 +221119,7 @@ var NarrativeValidator = class {
|
|
|
221016
221119
|
aggregates,
|
|
221017
221120
|
null,
|
|
221018
221121
|
// summary uses global aggregates
|
|
221019
|
-
|
|
221122
|
+
workflowPath,
|
|
221020
221123
|
`${scenarioPath}.template.summary`
|
|
221021
221124
|
));
|
|
221022
221125
|
}
|
|
@@ -221046,7 +221149,7 @@ var NarrativeValidator = class {
|
|
|
221046
221149
|
];
|
|
221047
221150
|
const similar = this.findSimilarAttributes(attr, allKeys);
|
|
221048
221151
|
violations.push({
|
|
221049
|
-
ruleId: "
|
|
221152
|
+
ruleId: "workflow-attribute-undefined",
|
|
221050
221153
|
severity: "warn",
|
|
221051
221154
|
file,
|
|
221052
221155
|
path: path4,
|
|
@@ -221062,7 +221165,7 @@ var NarrativeValidator = class {
|
|
|
221062
221165
|
const objectKeys = Object.keys(value);
|
|
221063
221166
|
const suggestions = objectKeys.slice(0, 3).map((k) => `{{${attr}.${k}}}`);
|
|
221064
221167
|
violations.push({
|
|
221065
|
-
ruleId: "
|
|
221168
|
+
ruleId: "workflow-attribute-object",
|
|
221066
221169
|
severity: "warn",
|
|
221067
221170
|
file,
|
|
221068
221171
|
path: path4,
|
|
@@ -221111,19 +221214,19 @@ var NarrativeValidator = class {
|
|
|
221111
221214
|
*/
|
|
221112
221215
|
checkFormattingOptions(context) {
|
|
221113
221216
|
const violations = [];
|
|
221114
|
-
const {
|
|
221115
|
-
if (!
|
|
221217
|
+
const { workflow, workflowPath } = context;
|
|
221218
|
+
if (!workflow.formatting) {
|
|
221116
221219
|
return violations;
|
|
221117
221220
|
}
|
|
221118
|
-
if (
|
|
221221
|
+
if (workflow.formatting.showAttributes) {
|
|
221119
221222
|
const validValues = ["none", "matched", "all"];
|
|
221120
|
-
if (!validValues.includes(
|
|
221223
|
+
if (!validValues.includes(workflow.formatting.showAttributes)) {
|
|
221121
221224
|
violations.push({
|
|
221122
|
-
ruleId: "
|
|
221225
|
+
ruleId: "workflow-formatting-options",
|
|
221123
221226
|
severity: "warn",
|
|
221124
|
-
file:
|
|
221227
|
+
file: workflowPath,
|
|
221125
221228
|
path: "formatting.showAttributes",
|
|
221126
|
-
message: `Invalid showAttributes value: "${
|
|
221229
|
+
message: `Invalid showAttributes value: "${workflow.formatting.showAttributes}"`,
|
|
221127
221230
|
impact: "May not display attributes correctly",
|
|
221128
221231
|
suggestion: `Use one of: ${validValues.join(", ")}`,
|
|
221129
221232
|
fixable: false
|
|
@@ -221273,8 +221376,8 @@ var NarrativeValidator = class {
|
|
|
221273
221376
|
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
|
|
221274
221377
|
}
|
|
221275
221378
|
};
|
|
221276
|
-
function
|
|
221277
|
-
return new
|
|
221379
|
+
function createWorkflowValidator() {
|
|
221380
|
+
return new WorkflowValidator();
|
|
221278
221381
|
}
|
|
221279
221382
|
|
|
221280
221383
|
// ../core/dist/execution/ExecutionLoader.js
|
|
@@ -221558,14 +221661,14 @@ function loadGraphConfig(filePath) {
|
|
|
221558
221661
|
return null;
|
|
221559
221662
|
}
|
|
221560
221663
|
}
|
|
221561
|
-
function
|
|
221664
|
+
function loadWorkflowTemplate(filePath) {
|
|
221562
221665
|
if (!(0, import_node_fs11.existsSync)(filePath)) {
|
|
221563
221666
|
return null;
|
|
221564
221667
|
}
|
|
221565
221668
|
try {
|
|
221566
221669
|
const raw = (0, import_node_fs11.readFileSync)(filePath, "utf8");
|
|
221567
|
-
const
|
|
221568
|
-
return {
|
|
221670
|
+
const workflow = JSON.parse(raw);
|
|
221671
|
+
return { workflow, raw };
|
|
221569
221672
|
} catch {
|
|
221570
221673
|
return null;
|
|
221571
221674
|
}
|
|
@@ -221588,8 +221691,8 @@ function loadCanvas(filePath) {
|
|
|
221588
221691
|
}
|
|
221589
221692
|
function getFileType(filePath) {
|
|
221590
221693
|
const name = (0, import_node_path12.basename)(filePath).toLowerCase();
|
|
221591
|
-
if (name.endsWith(".
|
|
221592
|
-
return "
|
|
221694
|
+
if (name.endsWith(".workflow.json")) {
|
|
221695
|
+
return "workflow";
|
|
221593
221696
|
}
|
|
221594
221697
|
if (name.endsWith(".canvas") || name.endsWith(".otel.canvas")) {
|
|
221595
221698
|
return "canvas";
|
|
@@ -221772,38 +221875,38 @@ function createLintCommand() {
|
|
|
221772
221875
|
}
|
|
221773
221876
|
}
|
|
221774
221877
|
const engine = createDefaultRulesEngine();
|
|
221775
|
-
const
|
|
221878
|
+
const workflowValidator = createWorkflowValidator();
|
|
221776
221879
|
const results = /* @__PURE__ */ new Map();
|
|
221777
|
-
const
|
|
221880
|
+
const workflowsByCanvas = /* @__PURE__ */ new Map();
|
|
221778
221881
|
const canvasEventMap = /* @__PURE__ */ new Map();
|
|
221779
221882
|
for (const filePath of configFiles) {
|
|
221780
221883
|
const absolutePath = (0, import_node_path12.resolve)(cwd, filePath);
|
|
221781
221884
|
const relativePath = (0, import_node_path12.relative)(cwd, absolutePath);
|
|
221782
221885
|
const fileType = getFileType(absolutePath);
|
|
221783
|
-
if (fileType === "
|
|
221784
|
-
const loaded =
|
|
221886
|
+
if (fileType === "workflow") {
|
|
221887
|
+
const loaded = loadWorkflowTemplate(absolutePath);
|
|
221785
221888
|
if (!loaded) continue;
|
|
221786
|
-
const canvasPath = loaded.
|
|
221889
|
+
const canvasPath = loaded.workflow.canvas ? (0, import_node_path12.resolve)((0, import_node_path12.dirname)(absolutePath), loaded.workflow.canvas) : void 0;
|
|
221787
221890
|
if (canvasPath) {
|
|
221788
221891
|
const canvasKey = (0, import_node_path12.relative)(cwd, canvasPath);
|
|
221789
|
-
if (!
|
|
221790
|
-
|
|
221892
|
+
if (!workflowsByCanvas.has(canvasKey)) {
|
|
221893
|
+
workflowsByCanvas.set(canvasKey, []);
|
|
221791
221894
|
canvasEventMap.set(canvasKey, /* @__PURE__ */ new Set());
|
|
221792
221895
|
}
|
|
221793
|
-
|
|
221794
|
-
const
|
|
221795
|
-
for (const scenario of loaded.
|
|
221896
|
+
workflowsByCanvas.get(canvasKey).push({ absolutePath, relativePath, loaded });
|
|
221897
|
+
const workflowEvents = canvasEventMap.get(canvasKey);
|
|
221898
|
+
for (const scenario of loaded.workflow.scenarios) {
|
|
221796
221899
|
if (scenario.condition?.requires) {
|
|
221797
221900
|
for (const eventPattern of scenario.condition.requires) {
|
|
221798
221901
|
if (!eventPattern.includes("*")) {
|
|
221799
|
-
|
|
221902
|
+
workflowEvents.add(eventPattern);
|
|
221800
221903
|
}
|
|
221801
221904
|
}
|
|
221802
221905
|
}
|
|
221803
221906
|
if (scenario.template?.events) {
|
|
221804
221907
|
for (const eventName of Object.keys(scenario.template.events)) {
|
|
221805
221908
|
if (!eventName.includes("*")) {
|
|
221806
|
-
|
|
221909
|
+
workflowEvents.add(eventName);
|
|
221807
221910
|
}
|
|
221808
221911
|
}
|
|
221809
221912
|
}
|
|
@@ -221815,8 +221918,8 @@ function createLintCommand() {
|
|
|
221815
221918
|
const absolutePath = (0, import_node_path12.resolve)(cwd, filePath);
|
|
221816
221919
|
const relativePath = (0, import_node_path12.relative)(cwd, absolutePath);
|
|
221817
221920
|
const fileType = getFileType(absolutePath);
|
|
221818
|
-
if (fileType === "
|
|
221819
|
-
const loaded =
|
|
221921
|
+
if (fileType === "workflow") {
|
|
221922
|
+
const loaded = loadWorkflowTemplate(absolutePath);
|
|
221820
221923
|
if (!loaded) {
|
|
221821
221924
|
results.set(relativePath, {
|
|
221822
221925
|
violations: [
|
|
@@ -221824,7 +221927,7 @@ function createLintCommand() {
|
|
|
221824
221927
|
ruleId: "parse-error",
|
|
221825
221928
|
severity: "error",
|
|
221826
221929
|
file: relativePath,
|
|
221827
|
-
message: `Could not parse
|
|
221930
|
+
message: `Could not parse workflow file: ${filePath}`,
|
|
221828
221931
|
impact: "File cannot be validated",
|
|
221829
221932
|
fixable: false
|
|
221830
221933
|
}
|
|
@@ -221837,20 +221940,20 @@ function createLintCommand() {
|
|
|
221837
221940
|
});
|
|
221838
221941
|
continue;
|
|
221839
221942
|
}
|
|
221840
|
-
const canvasPath = loaded.
|
|
221943
|
+
const canvasPath = loaded.workflow.canvas ? (0, import_node_path12.resolve)((0, import_node_path12.dirname)(absolutePath), loaded.workflow.canvas) : void 0;
|
|
221841
221944
|
const canvas = canvasPath ? loadCanvas(canvasPath) : void 0;
|
|
221842
221945
|
const canvasKey = canvasPath ? (0, import_node_path12.relative)(cwd, canvasPath) : void 0;
|
|
221843
|
-
const
|
|
221844
|
-
const
|
|
221845
|
-
|
|
221846
|
-
|
|
221946
|
+
const allWorkflowEvents = canvasKey ? canvasEventMap.get(canvasKey) : void 0;
|
|
221947
|
+
const workflowResult = await workflowValidator.validate({
|
|
221948
|
+
workflow: loaded.workflow,
|
|
221949
|
+
workflowPath: relativePath,
|
|
221847
221950
|
canvas: canvas ?? void 0,
|
|
221848
221951
|
canvasPath: canvasKey,
|
|
221849
221952
|
basePath: (0, import_node_path12.dirname)(absolutePath),
|
|
221850
221953
|
rawContent: loaded.raw,
|
|
221851
|
-
|
|
221954
|
+
allWorkflowEvents
|
|
221852
221955
|
});
|
|
221853
|
-
const violations =
|
|
221956
|
+
const violations = workflowResult.violations.map((v) => ({
|
|
221854
221957
|
ruleId: v.ruleId,
|
|
221855
221958
|
severity: v.severity,
|
|
221856
221959
|
file: v.file,
|
|
@@ -221863,11 +221966,11 @@ function createLintCommand() {
|
|
|
221863
221966
|
}));
|
|
221864
221967
|
results.set(relativePath, {
|
|
221865
221968
|
violations,
|
|
221866
|
-
errorCount:
|
|
221867
|
-
warningCount:
|
|
221868
|
-
fixableCount:
|
|
221969
|
+
errorCount: workflowResult.errorCount,
|
|
221970
|
+
warningCount: workflowResult.warningCount,
|
|
221971
|
+
fixableCount: workflowResult.fixableCount,
|
|
221869
221972
|
byCategory: { schema: 0, reference: 0, structure: 0, pattern: 0, library: 0 },
|
|
221870
|
-
// Could categorize
|
|
221973
|
+
// Could categorize workflow rules
|
|
221871
221974
|
byRule: countByRule(violations)
|
|
221872
221975
|
});
|
|
221873
221976
|
} else {
|
|
@@ -222059,22 +222162,22 @@ function createCoverageCommand() {
|
|
|
222059
222162
|
return command;
|
|
222060
222163
|
}
|
|
222061
222164
|
|
|
222062
|
-
// src/commands/
|
|
222165
|
+
// src/commands/workflow/validate.ts
|
|
222063
222166
|
var import_node_path15 = require("node:path");
|
|
222064
222167
|
var import_node_fs12 = require("node:fs");
|
|
222065
222168
|
|
|
222066
|
-
// src/commands/
|
|
222169
|
+
// src/commands/workflow/utils.ts
|
|
222067
222170
|
var import_promises4 = require("node:fs/promises");
|
|
222068
222171
|
var import_node_path14 = require("node:path");
|
|
222069
|
-
async function
|
|
222172
|
+
async function loadWorkflow(filePath) {
|
|
222070
222173
|
try {
|
|
222071
222174
|
const content = await (0, import_promises4.readFile)(filePath, "utf-8");
|
|
222072
222175
|
return JSON.parse(content);
|
|
222073
222176
|
} catch (error) {
|
|
222074
222177
|
if (error.code === "ENOENT") {
|
|
222075
|
-
throw new Error(`
|
|
222178
|
+
throw new Error(`Workflow file not found: ${filePath}`);
|
|
222076
222179
|
}
|
|
222077
|
-
throw new Error(`Failed to parse
|
|
222180
|
+
throw new Error(`Failed to parse workflow file: ${error.message}`);
|
|
222078
222181
|
}
|
|
222079
222182
|
}
|
|
222080
222183
|
async function loadExecution(filePath) {
|
|
@@ -222191,21 +222294,21 @@ function capitalize(str3) {
|
|
|
222191
222294
|
return str3.charAt(0).toUpperCase() + str3.slice(1);
|
|
222192
222295
|
}
|
|
222193
222296
|
|
|
222194
|
-
// src/commands/
|
|
222297
|
+
// src/commands/workflow/validate.ts
|
|
222195
222298
|
function createValidateCommand2() {
|
|
222196
222299
|
const command = new Command("validate");
|
|
222197
|
-
command.description("Validate
|
|
222300
|
+
command.description("Validate workflow template syntax, schema, and references").argument("<file>", "Path to .workflow.json file").option("--canvas <path>", "Override canvas file path for validation").option("--execution <path>", "Execution file (.otel.json) for validating attribute references").option("--json", "Output violations as JSON").option("-q, --quiet", "Only show errors, suppress warnings").option("-d, --dir <path>", "Project directory (default: cwd)").action(async (file, options) => {
|
|
222198
222301
|
try {
|
|
222199
222302
|
const baseDir = options.dir || process.cwd();
|
|
222200
|
-
const
|
|
222201
|
-
const
|
|
222303
|
+
const workflowPath = resolvePath(file, baseDir);
|
|
222304
|
+
const workflow = await loadWorkflow(workflowPath);
|
|
222202
222305
|
let canvasPath;
|
|
222203
222306
|
let canvas;
|
|
222204
222307
|
if (options.canvas) {
|
|
222205
222308
|
canvasPath = resolvePath(options.canvas, baseDir);
|
|
222206
|
-
} else if (
|
|
222207
|
-
const
|
|
222208
|
-
canvasPath = (0, import_node_path15.resolve)(
|
|
222309
|
+
} else if (workflow.canvas) {
|
|
222310
|
+
const workflowDir = (0, import_node_path15.dirname)(workflowPath);
|
|
222311
|
+
canvasPath = (0, import_node_path15.resolve)(workflowDir, workflow.canvas);
|
|
222209
222312
|
}
|
|
222210
222313
|
if (canvasPath) {
|
|
222211
222314
|
try {
|
|
@@ -222241,10 +222344,10 @@ function createValidateCommand2() {
|
|
|
222241
222344
|
console.error(source_default.gray(" Attribute validation will be skipped"));
|
|
222242
222345
|
}
|
|
222243
222346
|
}
|
|
222244
|
-
const validator = new
|
|
222347
|
+
const validator = new WorkflowValidator();
|
|
222245
222348
|
const context = {
|
|
222246
|
-
|
|
222247
|
-
|
|
222349
|
+
workflow,
|
|
222350
|
+
workflowPath,
|
|
222248
222351
|
canvasPath,
|
|
222249
222352
|
canvas,
|
|
222250
222353
|
basePath: baseDir,
|
|
@@ -222271,8 +222374,8 @@ function createValidateCommand2() {
|
|
|
222271
222374
|
summary: {
|
|
222272
222375
|
errors: errors.length,
|
|
222273
222376
|
warnings: warnings.length,
|
|
222274
|
-
scenarioCount:
|
|
222275
|
-
hasDefault:
|
|
222377
|
+
scenarioCount: workflow.scenarios.length,
|
|
222378
|
+
hasDefault: workflow.scenarios.some((s) => s.condition.default),
|
|
222276
222379
|
attributeValidation: executionData ? "enabled" : "skipped"
|
|
222277
222380
|
}
|
|
222278
222381
|
};
|
|
@@ -222285,14 +222388,14 @@ Validating: ${file}
|
|
|
222285
222388
|
console.log(source_default.green("\u2713"), "Schema validation passed");
|
|
222286
222389
|
console.log(
|
|
222287
222390
|
source_default.green("\u2713"),
|
|
222288
|
-
`${
|
|
222391
|
+
`${workflow.scenarios.length} scenarios found`
|
|
222289
222392
|
);
|
|
222290
|
-
const hasDefault =
|
|
222393
|
+
const hasDefault = workflow.scenarios.some((s) => s.condition.default);
|
|
222291
222394
|
console.log(
|
|
222292
222395
|
source_default.green("\u2713"),
|
|
222293
222396
|
hasDefault ? "Default scenario present" : "No default scenario"
|
|
222294
222397
|
);
|
|
222295
|
-
const priorities =
|
|
222398
|
+
const priorities = workflow.scenarios.map((s) => s.priority);
|
|
222296
222399
|
const allUnique = new Set(priorities).size === priorities.length;
|
|
222297
222400
|
console.log(
|
|
222298
222401
|
source_default.green("\u2713"),
|
|
@@ -222301,7 +222404,7 @@ Validating: ${file}
|
|
|
222301
222404
|
if (canvasPath) {
|
|
222302
222405
|
console.log(
|
|
222303
222406
|
source_default.green("\u2713"),
|
|
222304
|
-
`Canvas: ${
|
|
222407
|
+
`Canvas: ${workflow.canvas || canvasPath} \u2713`
|
|
222305
222408
|
);
|
|
222306
222409
|
}
|
|
222307
222410
|
} else {
|
|
@@ -222333,10 +222436,10 @@ ${icon} ${severity}: ${violation.message}`);
|
|
|
222333
222436
|
console.log(source_default.green(" \u2022 0 warnings"));
|
|
222334
222437
|
}
|
|
222335
222438
|
console.log(
|
|
222336
|
-
source_default.gray(` \u2022 ${
|
|
222439
|
+
source_default.gray(` \u2022 ${workflow.scenarios.length} scenario(s)`)
|
|
222337
222440
|
);
|
|
222338
222441
|
if (canvasPath) {
|
|
222339
|
-
console.log(source_default.gray(` \u2022 Canvas: ${
|
|
222442
|
+
console.log(source_default.gray(` \u2022 Canvas: ${workflow.canvas || canvasPath}`));
|
|
222340
222443
|
}
|
|
222341
222444
|
if (executionData) {
|
|
222342
222445
|
console.log(
|
|
@@ -222362,7 +222465,7 @@ ${icon} ${severity}: ${violation.message}`);
|
|
|
222362
222465
|
return command;
|
|
222363
222466
|
}
|
|
222364
222467
|
|
|
222365
|
-
// src/commands/
|
|
222468
|
+
// src/commands/workflow/inspect.ts
|
|
222366
222469
|
function createInspectCommand() {
|
|
222367
222470
|
const command = new Command("inspect");
|
|
222368
222471
|
command.description("Inspect execution file and show available attributes for templates").argument("<execution>", "Path to .otel.json execution file").option("--events", "Show all events").option("--aggregates", "Show computed aggregates (default)", true).option("--json", "Output as JSON").option("--filter <pattern>", "Filter attributes by pattern (e.g., auth.*)").action(async (execution, options) => {
|
|
@@ -222462,12 +222565,12 @@ ${capitalize(prefix)}:`));
|
|
|
222462
222565
|
return command;
|
|
222463
222566
|
}
|
|
222464
222567
|
|
|
222465
|
-
// src/commands/
|
|
222568
|
+
// src/commands/workflow/render.ts
|
|
222466
222569
|
function createRenderCommand() {
|
|
222467
222570
|
const command = new Command("render");
|
|
222468
|
-
command.description("Render
|
|
222571
|
+
command.description("Render workflow template using execution data").argument("<workflow>", "Path to .workflow.json file").argument("<execution>", "Path to .otel.json execution file").option("--mode <mode>", "Override rendering mode: span-tree, timeline").option("--scenario <id>", "Force specific scenario (skip auto-selection)").option("--json", "Output structured result as JSON").option("--format <format>", "Output format: text (default), markdown, json", "text").option("--show-metadata", "Include rendering metadata in output").action(async (workflowPath, executionPath, options) => {
|
|
222469
222572
|
try {
|
|
222470
|
-
const
|
|
222573
|
+
const workflow = await loadWorkflow(resolvePath(workflowPath));
|
|
222471
222574
|
const executionData = await loadExecution(resolvePath(executionPath));
|
|
222472
222575
|
const events = executionToEvents(executionData);
|
|
222473
222576
|
if (options.mode) {
|
|
@@ -222477,21 +222580,21 @@ function createRenderCommand() {
|
|
|
222477
222580
|
`Invalid mode: ${options.mode}. Must be one of: ${validModes.join(", ")}`
|
|
222478
222581
|
);
|
|
222479
222582
|
}
|
|
222480
|
-
|
|
222583
|
+
workflow.mode = options.mode;
|
|
222481
222584
|
}
|
|
222482
|
-
const result =
|
|
222483
|
-
const selectedScenario =
|
|
222585
|
+
const result = renderWorkflow(workflow, events);
|
|
222586
|
+
const selectedScenario = workflow.scenarios.find((s) => s.id === result.scenarioId);
|
|
222484
222587
|
if (options.scenario) {
|
|
222485
|
-
const scenario =
|
|
222588
|
+
const scenario = workflow.scenarios.find((s) => s.id === options.scenario);
|
|
222486
222589
|
if (!scenario) {
|
|
222487
222590
|
throw new Error(`Scenario not found: ${options.scenario}`);
|
|
222488
222591
|
}
|
|
222489
222592
|
}
|
|
222490
222593
|
if (options.json) {
|
|
222491
222594
|
const output = {
|
|
222492
|
-
|
|
222595
|
+
workflow: workflowPath,
|
|
222493
222596
|
execution: executionPath,
|
|
222494
|
-
mode:
|
|
222597
|
+
mode: workflow.mode,
|
|
222495
222598
|
scenario: {
|
|
222496
222599
|
id: selectedScenario?.id,
|
|
222497
222600
|
priority: selectedScenario?.priority,
|
|
@@ -222505,9 +222608,9 @@ function createRenderCommand() {
|
|
|
222505
222608
|
console.log(JSON.stringify(output, null, 2));
|
|
222506
222609
|
} else {
|
|
222507
222610
|
if (!options.format || options.format === "text") {
|
|
222508
|
-
console.log(source_default.gray(`Rendering: ${
|
|
222611
|
+
console.log(source_default.gray(`Rendering: ${workflowPath}`));
|
|
222509
222612
|
console.log(source_default.gray(`Execution: ${executionPath}`));
|
|
222510
|
-
console.log(source_default.gray(`Mode: ${
|
|
222613
|
+
console.log(source_default.gray(`Mode: ${workflow.mode}`));
|
|
222511
222614
|
if (selectedScenario) {
|
|
222512
222615
|
console.log(
|
|
222513
222616
|
source_default.gray(
|
|
@@ -222554,16 +222657,16 @@ function createRenderCommand() {
|
|
|
222554
222657
|
return command;
|
|
222555
222658
|
}
|
|
222556
222659
|
|
|
222557
|
-
// src/commands/
|
|
222660
|
+
// src/commands/workflow/test.ts
|
|
222558
222661
|
function createTestCommand() {
|
|
222559
222662
|
const command = new Command("test");
|
|
222560
|
-
command.description("Test scenario matching and show why scenarios match or don't match").argument("<
|
|
222663
|
+
command.description("Test scenario matching and show why scenarios match or don't match").argument("<workflow>", "Path to .workflow.json file").argument("<execution>", "Path to .otel.json execution file").option("--show-all", "Show all scenarios (not just matches)").option("--show-aggregates", "Display computed aggregates").option("--json", "Output as JSON").action(async (workflowPath, executionPath, options) => {
|
|
222561
222664
|
try {
|
|
222562
|
-
const
|
|
222665
|
+
const workflow = await loadWorkflow(resolvePath(workflowPath));
|
|
222563
222666
|
const executionData = await loadExecution(resolvePath(executionPath));
|
|
222564
222667
|
const events = executionToEvents(executionData);
|
|
222565
222668
|
const aggregates = computeAggregates(events);
|
|
222566
|
-
const scenarioResults =
|
|
222669
|
+
const scenarioResults = workflow.scenarios.map((scenario) => {
|
|
222567
222670
|
const condition = scenario.condition;
|
|
222568
222671
|
const matched = matchesCondition(condition, events, aggregates);
|
|
222569
222672
|
let reason;
|
|
@@ -222604,11 +222707,11 @@ function createTestCommand() {
|
|
|
222604
222707
|
excludesResults
|
|
222605
222708
|
};
|
|
222606
222709
|
});
|
|
222607
|
-
const matchResult = selectScenario(
|
|
222710
|
+
const matchResult = selectScenario(workflow, events, aggregates);
|
|
222608
222711
|
const selectedScenario = matchResult.scenario;
|
|
222609
222712
|
if (options.json) {
|
|
222610
222713
|
const output = {
|
|
222611
|
-
|
|
222714
|
+
workflow: workflowPath,
|
|
222612
222715
|
execution: executionPath,
|
|
222613
222716
|
scenarios: scenarioResults.map((r) => ({
|
|
222614
222717
|
id: r.scenario.id,
|
|
@@ -222624,7 +222727,7 @@ function createTestCommand() {
|
|
|
222624
222727
|
console.log(JSON.stringify(output, null, 2));
|
|
222625
222728
|
} else {
|
|
222626
222729
|
console.log(source_default.bold(`
|
|
222627
|
-
Testing: ${
|
|
222730
|
+
Testing: ${workflowPath}`));
|
|
222628
222731
|
console.log(source_default.gray(`Execution: ${executionPath}
|
|
222629
222732
|
`));
|
|
222630
222733
|
console.log(source_default.bold("Scenario Matching Results:"));
|
|
@@ -222693,27 +222796,27 @@ ${icon} ${source_default.bold(result.scenario.id)} (priority: ${result.scenario.
|
|
|
222693
222796
|
return command;
|
|
222694
222797
|
}
|
|
222695
222798
|
|
|
222696
|
-
// src/commands/
|
|
222799
|
+
// src/commands/workflow/list.ts
|
|
222697
222800
|
var import_promises5 = require("node:fs/promises");
|
|
222698
222801
|
var import_node_path16 = require("node:path");
|
|
222699
222802
|
function createListCommand2() {
|
|
222700
222803
|
const command = new Command("list");
|
|
222701
|
-
command.description("List all
|
|
222804
|
+
command.description("List all workflow files in project").argument("[dir]", "Directory to search (default: .principal-views/)").option("--json", "Output as JSON").option("--show-canvas", "Show linked canvas files").action(async (dir, options) => {
|
|
222702
222805
|
try {
|
|
222703
222806
|
const searchDir = dir || ".principal-views";
|
|
222704
222807
|
const searchPath = (0, import_node_path16.resolve)(process.cwd(), searchDir);
|
|
222705
|
-
const files = await globby("**/*.
|
|
222808
|
+
const files = await globby("**/*.workflow.json", {
|
|
222706
222809
|
cwd: searchPath,
|
|
222707
222810
|
ignore: ["node_modules/**", ".git/**", "__executions__/**"]
|
|
222708
222811
|
});
|
|
222709
|
-
const
|
|
222812
|
+
const workflows = await Promise.all(
|
|
222710
222813
|
files.map(async (file) => {
|
|
222711
222814
|
const fullPath = (0, import_node_path16.join)(searchPath, file);
|
|
222712
|
-
const
|
|
222815
|
+
const workflow = await loadWorkflow(fullPath);
|
|
222713
222816
|
let canvasExists;
|
|
222714
|
-
if (options.showCanvas &&
|
|
222715
|
-
const
|
|
222716
|
-
const canvasPath = (0, import_node_path16.resolve)(
|
|
222817
|
+
if (options.showCanvas && workflow.canvas) {
|
|
222818
|
+
const workflowDir = (0, import_node_path16.dirname)(fullPath);
|
|
222819
|
+
const canvasPath = (0, import_node_path16.resolve)(workflowDir, workflow.canvas);
|
|
222717
222820
|
try {
|
|
222718
222821
|
await (0, import_promises5.access)(canvasPath);
|
|
222719
222822
|
canvasExists = true;
|
|
@@ -222721,23 +222824,23 @@ function createListCommand2() {
|
|
|
222721
222824
|
canvasExists = false;
|
|
222722
222825
|
}
|
|
222723
222826
|
}
|
|
222724
|
-
const defaultCount =
|
|
222827
|
+
const defaultCount = workflow.scenarios.filter((s) => s.condition.default).length;
|
|
222725
222828
|
return {
|
|
222726
222829
|
file: (0, import_node_path16.join)(searchDir, file),
|
|
222727
|
-
canvas:
|
|
222830
|
+
canvas: workflow.canvas,
|
|
222728
222831
|
canvasExists,
|
|
222729
|
-
scenarioCount:
|
|
222832
|
+
scenarioCount: workflow.scenarios.length,
|
|
222730
222833
|
defaultCount,
|
|
222731
|
-
mode:
|
|
222732
|
-
name:
|
|
222834
|
+
mode: workflow.mode,
|
|
222835
|
+
name: workflow.name
|
|
222733
222836
|
};
|
|
222734
222837
|
})
|
|
222735
222838
|
);
|
|
222736
222839
|
if (options.json) {
|
|
222737
222840
|
const output = {
|
|
222738
222841
|
searchDir,
|
|
222739
|
-
count:
|
|
222740
|
-
|
|
222842
|
+
count: workflows.length,
|
|
222843
|
+
workflows: workflows.map((n) => ({
|
|
222741
222844
|
file: n.file,
|
|
222742
222845
|
name: n.name,
|
|
222743
222846
|
canvas: n.canvas,
|
|
@@ -222749,36 +222852,36 @@ function createListCommand2() {
|
|
|
222749
222852
|
};
|
|
222750
222853
|
console.log(JSON.stringify(output, null, 2));
|
|
222751
222854
|
} else {
|
|
222752
|
-
console.log(source_default.bold("\
|
|
222855
|
+
console.log(source_default.bold("\nWorkflow Templates:"));
|
|
222753
222856
|
console.log("\u2501".repeat(60));
|
|
222754
|
-
if (
|
|
222857
|
+
if (workflows.length === 0) {
|
|
222755
222858
|
console.log(source_default.yellow(`
|
|
222756
|
-
No
|
|
222859
|
+
No workflow templates found in ${searchDir}`));
|
|
222757
222860
|
console.log();
|
|
222758
222861
|
return;
|
|
222759
222862
|
}
|
|
222760
|
-
for (const
|
|
222863
|
+
for (const workflow of workflows) {
|
|
222761
222864
|
console.log(source_default.bold(`
|
|
222762
|
-
${
|
|
222763
|
-
if (
|
|
222764
|
-
console.log(source_default.gray(` Name: ${
|
|
222865
|
+
${workflow.file}`));
|
|
222866
|
+
if (workflow.name) {
|
|
222867
|
+
console.log(source_default.gray(` Name: ${workflow.name}`));
|
|
222765
222868
|
}
|
|
222766
|
-
if (options.showCanvas &&
|
|
222767
|
-
const status =
|
|
222768
|
-
console.log(source_default.gray(` Canvas: ${
|
|
222769
|
-
} else if (
|
|
222770
|
-
console.log(source_default.gray(` Canvas: ${
|
|
222869
|
+
if (options.showCanvas && workflow.canvas) {
|
|
222870
|
+
const status = workflow.canvasExists ? source_default.green("\u2713") : source_default.red("\u2717");
|
|
222871
|
+
console.log(source_default.gray(` Canvas: ${workflow.canvas} ${status}`));
|
|
222872
|
+
} else if (workflow.canvas) {
|
|
222873
|
+
console.log(source_default.gray(` Canvas: ${workflow.canvas}`));
|
|
222771
222874
|
}
|
|
222772
222875
|
console.log(
|
|
222773
222876
|
source_default.gray(
|
|
222774
|
-
` Scenarios: ${
|
|
222877
|
+
` Scenarios: ${workflow.scenarioCount} (${workflow.defaultCount} default)`
|
|
222775
222878
|
)
|
|
222776
222879
|
);
|
|
222777
|
-
console.log(source_default.gray(` Mode: ${
|
|
222880
|
+
console.log(source_default.gray(` Mode: ${workflow.mode}`));
|
|
222778
222881
|
}
|
|
222779
222882
|
console.log(
|
|
222780
222883
|
source_default.bold(`
|
|
222781
|
-
Found ${
|
|
222884
|
+
Found ${workflows.length} workflow template(s)`)
|
|
222782
222885
|
);
|
|
222783
222886
|
console.log();
|
|
222784
222887
|
}
|
|
@@ -222790,10 +222893,10 @@ Found ${narratives.length} narrative template(s)`)
|
|
|
222790
222893
|
return command;
|
|
222791
222894
|
}
|
|
222792
222895
|
|
|
222793
|
-
// src/commands/
|
|
222794
|
-
function
|
|
222795
|
-
const command = new Command("
|
|
222796
|
-
command.description("Validate, test, and debug
|
|
222896
|
+
// src/commands/workflow/index.ts
|
|
222897
|
+
function createWorkflowCommand() {
|
|
222898
|
+
const command = new Command("workflow");
|
|
222899
|
+
command.description("Validate, test, and debug workflow templates").addCommand(createValidateCommand2()).addCommand(createInspectCommand()).addCommand(createRenderCommand()).addCommand(createTestCommand()).addCommand(createListCommand2());
|
|
222797
222900
|
return command;
|
|
222798
222901
|
}
|
|
222799
222902
|
|
|
@@ -222812,7 +222915,7 @@ program2.addCommand(createFormatsCommand());
|
|
|
222812
222915
|
program2.addCommand(createDoctorCommand());
|
|
222813
222916
|
program2.addCommand(createHooksCommand());
|
|
222814
222917
|
program2.addCommand(createCoverageCommand());
|
|
222815
|
-
program2.addCommand(
|
|
222918
|
+
program2.addCommand(createWorkflowCommand());
|
|
222816
222919
|
program2.parse(process.argv);
|
|
222817
222920
|
if (!process.argv.slice(2).length) {
|
|
222818
222921
|
program2.outputHelp();
|