@principal-ai/principal-view-cli 0.3.8 → 0.4.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"formats.d.ts","sourceRoot":"","sources":["../../src/commands/formats.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAycpC,wBAAgB,oBAAoB,IAAI,OAAO,CA6B9C"}
1
+ {"version":3,"file":"formats.d.ts","sourceRoot":"","sources":["../../src/commands/formats.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+fpC,wBAAgB,oBAAoB,IAAI,OAAO,CA6B9C"}
@@ -48,13 +48,18 @@ ${chalk.dim('│')} ${chalk.yellow('"type"')}: "text",
48
48
  ${chalk.dim('│')} ${chalk.yellow('"text"')}: "# Event Name", ${chalk.dim('// Markdown description')} ${chalk.dim('│')}
49
49
  ${chalk.dim('│')} ${chalk.yellow('"x"')}: 0, ${chalk.yellow('"y"')}: 0, ${chalk.yellow('"width"')}: 200, ${chalk.yellow('"height"')}: 100, ${chalk.dim('│')}
50
50
  ${chalk.dim('│')} ${chalk.green('"pv"')}: { ${chalk.dim('│')}
51
- ${chalk.dim('│')} ${chalk.cyan('"otelEvent"')}: { ${chalk.dim('// OTEL event definition')} ${chalk.dim('│')}
52
- ${chalk.dim('│')} ${chalk.yellow('"name"')}: "feature.event.name", ${chalk.dim('│')}
53
- ${chalk.dim('│')} ${chalk.cyan('"attributes"')}: { ${chalk.dim('// Required & optional attrs')} ${chalk.dim('│')}
54
- ${chalk.dim('│')} ${chalk.green('"required"')}: ["attr.name", ...], ${chalk.dim('│')}
55
- ${chalk.dim('│')} ${chalk.green('"optional"')}: ["attr.name", ...] ${chalk.dim('│')}
56
- ${chalk.dim('│')} } ${chalk.dim('│')}
57
- ${chalk.dim('│')} } ${chalk.dim('│')}
51
+ ${chalk.dim('│')} ${chalk.cyan('"event"')}: "feature.event.name", ${chalk.dim('// Event name')} ${chalk.dim('│')}
52
+ ${chalk.dim('│')} ${chalk.cyan('"sources"')}: ["src/file.ts"], ${chalk.dim('// Source files')} ${chalk.dim('│')}
53
+ ${chalk.dim('│')} ${chalk.cyan('"otel"')}: { ${chalk.dim('// OTEL metadata')} ${chalk.dim('│')}
54
+ ${chalk.dim('│')} ${chalk.yellow('"kind"')}: "event", ${chalk.dim('│')}
55
+ ${chalk.dim('│')} ${chalk.yellow('"category"')}: "lifecycle" ${chalk.dim('│')}
56
+ ${chalk.dim('│')} }, ${chalk.dim('│')}
57
+ ${chalk.dim('│')} ${chalk.cyan('"dataSchema"')}: { ${chalk.dim('// Attribute definitions')} ${chalk.dim('│')}
58
+ ${chalk.dim('│')} ${chalk.yellow('"attr.name"')}: { ${chalk.dim('│')}
59
+ ${chalk.dim('│')} ${chalk.green('"type"')}: "string", ${chalk.dim('│')}
60
+ ${chalk.dim('│')} ${chalk.green('"required"')}: true ${chalk.dim('│')}
61
+ ${chalk.dim('│')} } ${chalk.dim('│')}
62
+ ${chalk.dim('│')} } ${chalk.dim('│')}
58
63
  ${chalk.dim('│')} } ${chalk.dim('│')}
59
64
  ${chalk.dim('│')} } ${chalk.dim('│')}
60
65
  ${chalk.dim('│')} ], ${chalk.dim('│')}
@@ -161,12 +166,26 @@ ${chalk.cyan('2. Standard scenario set:')}
161
166
  - ${chalk.yellow('Failure')} (priority 2): Feature encountered error
162
167
  - ${chalk.dim('Fallback')} (priority 999): Generic execution captured
163
168
 
164
- ${chalk.cyan('3. Template interpolation:')}
165
- Use {{path.to.value}} to reference event attributes
166
- Examples:
167
- - {{record.count}}
168
- - {{error.message}}
169
- - {{result.invalidCount}}
169
+ ${chalk.cyan('3. Template syntax (Handlebars):')}
170
+ Templates use Handlebars syntax for dynamic content:
171
+
172
+ ${chalk.bold('Variables:')}
173
+ - {{variable}} Simple variable
174
+ - {{result.count}} Nested property
175
+ - {{error.message}} Deeply nested
176
+
177
+ ${chalk.bold('Conditionals:')}
178
+ - {{#if condition}}...{{/if}} If block
179
+ - {{#if condition}}...{{else}}...{{/if}} If-else
180
+ - {{#if (eq status "ok")}}✅{{else}}❌{{/if}} Comparison
181
+
182
+ ${chalk.bold('Loops:')}
183
+ - {{#each items}}{{this}}{{/each}} Iterate array
184
+ - {{#each items}}{{@index}}: {{this}}{{/each}} With index
185
+
186
+ ${chalk.bold('Comparison helpers:')}
187
+ - eq, ne, lt, gt, lte, gte, and, or, not
188
+ - Example: {{#if (gt count 10)}}Many{{/if}}
170
189
 
171
190
  ${chalk.cyan('4. Template style:')}
172
191
  - Clear, concise summary line
@@ -292,11 +311,20 @@ ${chalk.yellow('.principal-views/data-validator.otel.canvas')}
292
311
  "text": "# validation.started\\n\\nEmitted when validation begins",
293
312
  "x": 0, "y": 0, "width": 200, "height": 100,
294
313
  "pv": {
295
- "otelEvent": {
296
- "name": "validation.started",
297
- "attributes": {
298
- "required": ["input.recordCount"],
299
- "optional": ["input.source"]
314
+ "event": "validation.started",
315
+ "sources": ["src/validator.ts"],
316
+ "otel": {
317
+ "kind": "event",
318
+ "category": "lifecycle"
319
+ },
320
+ "dataSchema": {
321
+ "input.recordCount": {
322
+ "type": "number",
323
+ "required": true
324
+ },
325
+ "input.source": {
326
+ "type": "string",
327
+ "required": false
300
328
  }
301
329
  }
302
330
  }
@@ -307,11 +335,24 @@ ${chalk.yellow('.principal-views/data-validator.otel.canvas')}
307
335
  "text": "# validation.complete\\n\\nEmitted when validation succeeds",
308
336
  "x": 250, "y": 0, "width": 200, "height": 100,
309
337
  "pv": {
310
- "otelEvent": {
311
- "name": "validation.complete",
312
- "attributes": {
313
- "required": ["result.validCount", "result.invalidCount"],
314
- "optional": ["duration.ms"]
338
+ "event": "validation.complete",
339
+ "sources": ["src/validator.ts"],
340
+ "otel": {
341
+ "kind": "event",
342
+ "category": "lifecycle"
343
+ },
344
+ "dataSchema": {
345
+ "result.validCount": {
346
+ "type": "number",
347
+ "required": true
348
+ },
349
+ "result.invalidCount": {
350
+ "type": "number",
351
+ "required": true
352
+ },
353
+ "duration.ms": {
354
+ "type": "number",
355
+ "required": false
315
356
  }
316
357
  }
317
358
  }
@@ -322,11 +363,24 @@ ${chalk.yellow('.principal-views/data-validator.otel.canvas')}
322
363
  "text": "# validation.error\\n\\nEmitted when validation fails",
323
364
  "x": 500, "y": 0, "width": 200, "height": 100,
324
365
  "pv": {
325
- "otelEvent": {
326
- "name": "validation.error",
327
- "attributes": {
328
- "required": ["error.type", "error.message"],
329
- "optional": ["error.stage"]
366
+ "event": "validation.error",
367
+ "sources": ["src/validator.ts"],
368
+ "otel": {
369
+ "kind": "event",
370
+ "category": "error"
371
+ },
372
+ "dataSchema": {
373
+ "error.type": {
374
+ "type": "string",
375
+ "required": true
376
+ },
377
+ "error.message": {
378
+ "type": "string",
379
+ "required": true
380
+ },
381
+ "error.stage": {
382
+ "type": "string",
383
+ "required": false
330
384
  }
331
385
  }
332
386
  }
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/commands/narrative/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAepC,wBAAgB,qBAAqB,IAAI,OAAO,CA0K/C"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/commands/narrative/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,wBAAgB,qBAAqB,IAAI,OAAO,CA6N/C"}
@@ -2,14 +2,15 @@ import { Command } from 'commander';
2
2
  import chalk from 'chalk';
3
3
  import { resolve, dirname } from 'node:path';
4
4
  import { readFileSync } from 'node:fs';
5
- import { NarrativeValidator } from '@principal-ai/principal-view-core';
6
- import { loadNarrative, resolvePath } from './utils.js';
5
+ import { NarrativeValidator, computeAggregates } from '@principal-ai/principal-view-core';
6
+ import { loadNarrative, resolvePath, loadExecution, executionToEvents } from './utils.js';
7
7
  export function createValidateCommand() {
8
8
  const command = new Command('validate');
9
9
  command
10
10
  .description('Validate narrative template syntax, schema, and references')
11
11
  .argument('<file>', 'Path to .narrative.json file')
12
12
  .option('--canvas <path>', 'Override canvas file path for validation')
13
+ .option('--execution <path>', 'Execution file (.otel.json) for validating attribute references')
13
14
  .option('--json', 'Output violations as JSON')
14
15
  .option('-q, --quiet', 'Only show errors, suppress warnings')
15
16
  .option('-d, --dir <path>', 'Project directory (default: cwd)')
@@ -40,6 +41,33 @@ export function createValidateCommand() {
40
41
  canvas = undefined;
41
42
  }
42
43
  }
44
+ // Load execution data if provided
45
+ let executionData;
46
+ if (options.execution) {
47
+ try {
48
+ const executionPath = resolvePath(options.execution, baseDir);
49
+ const execution = await loadExecution(executionPath);
50
+ const events = executionToEvents(execution);
51
+ const aggregates = computeAggregates(events);
52
+ // Build event-specific attribute map
53
+ const eventAttributes = new Map();
54
+ for (const event of events) {
55
+ if (!eventAttributes.has(event.name)) {
56
+ eventAttributes.set(event.name, {});
57
+ }
58
+ const attrs = eventAttributes.get(event.name);
59
+ // Merge attributes from this event occurrence
60
+ if (event.attributes) {
61
+ Object.assign(attrs, event.attributes);
62
+ }
63
+ }
64
+ executionData = { aggregates, eventAttributes };
65
+ }
66
+ catch (error) {
67
+ console.error(chalk.yellow('Warning:'), `Failed to load execution file: ${error.message}`);
68
+ console.error(chalk.gray(' Attribute validation will be skipped'));
69
+ }
70
+ }
43
71
  // Create validator
44
72
  const validator = new NarrativeValidator();
45
73
  // Validate
@@ -49,6 +77,7 @@ export function createValidateCommand() {
49
77
  canvasPath,
50
78
  canvas,
51
79
  basePath: baseDir,
80
+ executionData,
52
81
  };
53
82
  const result = await validator.validate(context);
54
83
  // Filter violations if quiet mode
@@ -77,6 +106,7 @@ export function createValidateCommand() {
77
106
  warnings: warnings.length,
78
107
  scenarioCount: narrative.scenarios.length,
79
108
  hasDefault: narrative.scenarios.some((s) => s.condition.default),
109
+ attributeValidation: executionData ? 'enabled' : 'skipped',
80
110
  },
81
111
  };
82
112
  console.log(JSON.stringify(output, null, 2));
@@ -133,6 +163,12 @@ export function createValidateCommand() {
133
163
  if (canvasPath) {
134
164
  console.log(chalk.gray(` • Canvas: ${narrative.canvas || canvasPath}`));
135
165
  }
166
+ if (executionData) {
167
+ console.log(chalk.gray(' • Attribute validation:'), chalk.green('enabled'));
168
+ }
169
+ else {
170
+ console.log(chalk.gray(' • Attribute validation:'), chalk.gray('skipped (use --execution to enable)'));
171
+ }
136
172
  console.log();
137
173
  }
138
174
  // Exit with error code if validation failed