@principal-ai/principal-view-cli 0.1.25 → 0.1.26

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":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgjCpC,wBAAgB,qBAAqB,IAAI,OAAO,CAsH/C"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4nCpC,wBAAgB,qBAAqB,IAAI,OAAO,CAsH/C"}
@@ -229,6 +229,7 @@ const ALLOWED_CANVAS_FIELDS = {
229
229
  'name',
230
230
  'description',
231
231
  'otel',
232
+ 'events',
232
233
  'shape',
233
234
  'icon',
234
235
  'fill',
@@ -345,6 +346,51 @@ function findSimilarField(field, allowedFields) {
345
346
  }
346
347
  return null;
347
348
  }
349
+ /**
350
+ * Check if a canvas has OTEL-related features
351
+ * Returns true if the canvas contains any of:
352
+ * 1. Nodes with pv.otel extension (kind, category)
353
+ * 2. Event schemas (pv.events with validation)
354
+ * 3. Canvas scope/audit config (OTEL log routing)
355
+ * 4. Resource matching for OTEL logs
356
+ */
357
+ function hasOtelFeatures(canvas) {
358
+ if (!canvas || typeof canvas !== 'object') {
359
+ return false;
360
+ }
361
+ const c = canvas;
362
+ // Check for canvas-level scope or audit config
363
+ if (c.pv && typeof c.pv === 'object') {
364
+ const pv = c.pv;
365
+ if (pv.scope !== undefined || pv.audit !== undefined) {
366
+ return true;
367
+ }
368
+ }
369
+ // Check nodes for OTEL features
370
+ if (Array.isArray(c.nodes)) {
371
+ for (const node of c.nodes) {
372
+ if (node && typeof node === 'object') {
373
+ const n = node;
374
+ if (n.pv && typeof n.pv === 'object') {
375
+ const nodePv = n.pv;
376
+ // Check for pv.otel extension
377
+ if (nodePv.otel !== undefined) {
378
+ return true;
379
+ }
380
+ // Check for event schemas (pv.events)
381
+ if (nodePv.events !== undefined) {
382
+ return true;
383
+ }
384
+ // Check for resourceMatch (OTEL log routing)
385
+ if (nodePv.resourceMatch !== undefined) {
386
+ return true;
387
+ }
388
+ }
389
+ }
390
+ }
391
+ }
392
+ return false;
393
+ }
348
394
  /**
349
395
  * Validate an ExtendedCanvas object with strict validation
350
396
  *
@@ -791,6 +837,23 @@ function validateCanvas(canvas, filePath, library) {
791
837
  }
792
838
  });
793
839
  }
840
+ // Validate OTEL canvas naming convention
841
+ const hasOtel = hasOtelFeatures(canvas);
842
+ const isOtelCanvas = filePath.endsWith('.otel.canvas');
843
+ if (hasOtel && !isOtelCanvas) {
844
+ issues.push({
845
+ type: 'error',
846
+ message: 'Canvas contains OTEL features but does not use .otel.canvas naming convention',
847
+ suggestion: 'Rename file to use .otel.canvas extension (e.g., "graph-name.otel.canvas")',
848
+ });
849
+ }
850
+ else if (!hasOtel && isOtelCanvas) {
851
+ issues.push({
852
+ type: 'warning',
853
+ message: 'Canvas uses .otel.canvas naming but does not contain any OTEL features',
854
+ suggestion: 'Either add OTEL features (pv.otel, pv.events, pv.scope, pv.audit, resourceMatch) or rename to .canvas',
855
+ });
856
+ }
794
857
  return issues;
795
858
  }
796
859
  /**
package/dist/index.cjs CHANGED
@@ -13688,6 +13688,7 @@ var ALLOWED_CANVAS_FIELDS = {
13688
13688
  "name",
13689
13689
  "description",
13690
13690
  "otel",
13691
+ "events",
13691
13692
  "shape",
13692
13693
  "icon",
13693
13694
  "fill",
@@ -13790,6 +13791,38 @@ function findSimilarField(field, allowedFields) {
13790
13791
  }
13791
13792
  return null;
13792
13793
  }
13794
+ function hasOtelFeatures(canvas) {
13795
+ if (!canvas || typeof canvas !== "object") {
13796
+ return false;
13797
+ }
13798
+ const c = canvas;
13799
+ if (c.pv && typeof c.pv === "object") {
13800
+ const pv = c.pv;
13801
+ if (pv.scope !== void 0 || pv.audit !== void 0) {
13802
+ return true;
13803
+ }
13804
+ }
13805
+ if (Array.isArray(c.nodes)) {
13806
+ for (const node of c.nodes) {
13807
+ if (node && typeof node === "object") {
13808
+ const n = node;
13809
+ if (n.pv && typeof n.pv === "object") {
13810
+ const nodePv = n.pv;
13811
+ if (nodePv.otel !== void 0) {
13812
+ return true;
13813
+ }
13814
+ if (nodePv.events !== void 0) {
13815
+ return true;
13816
+ }
13817
+ if (nodePv.resourceMatch !== void 0) {
13818
+ return true;
13819
+ }
13820
+ }
13821
+ }
13822
+ }
13823
+ }
13824
+ return false;
13825
+ }
13793
13826
  function validateCanvas(canvas, filePath, library) {
13794
13827
  const issues = [];
13795
13828
  if (!canvas || typeof canvas !== "object") {
@@ -14256,6 +14289,21 @@ function validateCanvas(canvas, filePath, library) {
14256
14289
  }
14257
14290
  });
14258
14291
  }
14292
+ const hasOtel = hasOtelFeatures(canvas);
14293
+ const isOtelCanvas = filePath.endsWith(".otel.canvas");
14294
+ if (hasOtel && !isOtelCanvas) {
14295
+ issues.push({
14296
+ type: "error",
14297
+ message: "Canvas contains OTEL features but does not use .otel.canvas naming convention",
14298
+ suggestion: 'Rename file to use .otel.canvas extension (e.g., "graph-name.otel.canvas")'
14299
+ });
14300
+ } else if (!hasOtel && isOtelCanvas) {
14301
+ issues.push({
14302
+ type: "warning",
14303
+ message: "Canvas uses .otel.canvas naming but does not contain any OTEL features",
14304
+ suggestion: "Either add OTEL features (pv.otel, pv.events, pv.scope, pv.audit, resourceMatch) or rename to .canvas"
14305
+ });
14306
+ }
14259
14307
  return issues;
14260
14308
  }
14261
14309
  function validateFile(filePath, library) {
@@ -15547,6 +15595,212 @@ function createCreateCommand() {
15547
15595
  var import_node_fs10 = require("node:fs");
15548
15596
  var import_node_path11 = require("node:path");
15549
15597
 
15598
+ // ../core/dist/codegen/type-generator.js
15599
+ var TypeScriptGenerator = class {
15600
+ constructor() {
15601
+ this.language = "typescript";
15602
+ }
15603
+ generate(canvas, options) {
15604
+ const opts = {
15605
+ readonly: options?.style?.readonly ?? false,
15606
+ strictNullChecks: options?.style?.strictNullChecks ?? true,
15607
+ includeDocComments: options?.style?.includeDocComments ?? true,
15608
+ namespace: options?.namespace
15609
+ };
15610
+ const lines = [];
15611
+ lines.push("/**");
15612
+ lines.push(` * Generated types from canvas: ${canvas.pv?.name || "Untitled"}`);
15613
+ lines.push(" *");
15614
+ lines.push(" * DO NOT EDIT MANUALLY - This file is auto-generated");
15615
+ lines.push(" * Generated by @principal-ai/principal-view-core");
15616
+ lines.push(" *");
15617
+ lines.push(` * Canvas: ${canvas.pv?.description || "No description"}`);
15618
+ lines.push(` * Version: ${canvas.pv?.version || "1.0.0"}`);
15619
+ lines.push(" */");
15620
+ lines.push("");
15621
+ if (opts.namespace) {
15622
+ lines.push(`export namespace ${opts.namespace} {`);
15623
+ }
15624
+ if (canvas.nodes) {
15625
+ for (const node of canvas.nodes) {
15626
+ if (node.pv?.events) {
15627
+ lines.push(...this.generateNodeTypes(node.id, node.pv.events, opts));
15628
+ lines.push("");
15629
+ }
15630
+ }
15631
+ }
15632
+ lines.push(...this.generateEventNameUnion(canvas, opts));
15633
+ lines.push("");
15634
+ lines.push(...this.generateEmitterTypes(canvas, opts));
15635
+ if (opts.namespace) {
15636
+ lines.push("}");
15637
+ }
15638
+ const code = lines.join("\n");
15639
+ const filename = this.generateFilename(canvas);
15640
+ return {
15641
+ code,
15642
+ extension: "ts",
15643
+ filename
15644
+ };
15645
+ }
15646
+ generateNodeTypes(nodeId, events, opts) {
15647
+ const lines = [];
15648
+ const typeName = this.nodeIdToTypeName(nodeId);
15649
+ if (opts.includeDocComments) {
15650
+ lines.push(`/**`);
15651
+ lines.push(` * Event types for node: ${nodeId}`);
15652
+ lines.push(` */`);
15653
+ }
15654
+ lines.push(`export namespace ${typeName} {`);
15655
+ for (const [eventName, eventSchema] of Object.entries(events)) {
15656
+ lines.push(...this.generateEventInterface(eventName, eventSchema, opts));
15657
+ lines.push("");
15658
+ }
15659
+ const eventNames = Object.keys(events);
15660
+ const interfaceNames = eventNames.map((name) => this.eventNameToTypeName(name));
15661
+ lines.push(" /**");
15662
+ lines.push(` * Union of all event types for ${nodeId}`);
15663
+ lines.push(" */");
15664
+ lines.push(` export type Event = ${interfaceNames.join(" | ")};`);
15665
+ lines.push("");
15666
+ lines.push(" /**");
15667
+ lines.push(` * Literal union of event names for ${nodeId}`);
15668
+ lines.push(" */");
15669
+ lines.push(` export type EventName = ${eventNames.map((n) => `'${n}'`).join(" | ")};`);
15670
+ lines.push("}");
15671
+ return lines;
15672
+ }
15673
+ generateEventInterface(eventName, schema2, opts) {
15674
+ const lines = [];
15675
+ const interfaceName = this.eventNameToTypeName(eventName);
15676
+ const readonly = opts.readonly ? "readonly " : "";
15677
+ if (opts.includeDocComments) {
15678
+ lines.push(" /**");
15679
+ lines.push(` * ${schema2.description}`);
15680
+ lines.push(" */");
15681
+ }
15682
+ lines.push(` export interface ${interfaceName} {`);
15683
+ lines.push(` ${readonly}name: '${eventName}';`);
15684
+ lines.push(` ${readonly}attributes: {`);
15685
+ for (const [fieldName, fieldSchema] of Object.entries(schema2.attributes)) {
15686
+ const optional = !fieldSchema.required && opts.strictNullChecks ? "?" : "";
15687
+ const type2 = this.fieldTypeToTsType(fieldSchema);
15688
+ if (opts.includeDocComments && fieldSchema.description) {
15689
+ lines.push(` /** ${fieldSchema.description} */`);
15690
+ }
15691
+ lines.push(` ${readonly}'${fieldName}'${optional}: ${type2};`);
15692
+ }
15693
+ lines.push(" };");
15694
+ lines.push(" }");
15695
+ return lines;
15696
+ }
15697
+ generateEventNameUnion(canvas, opts) {
15698
+ const lines = [];
15699
+ const allEventNames = /* @__PURE__ */ new Set();
15700
+ if (canvas.nodes) {
15701
+ for (const node of canvas.nodes) {
15702
+ if (node.pv?.events) {
15703
+ Object.keys(node.pv.events).forEach((name) => allEventNames.add(name));
15704
+ }
15705
+ }
15706
+ }
15707
+ if (allEventNames.size === 0) {
15708
+ return lines;
15709
+ }
15710
+ if (opts.includeDocComments) {
15711
+ lines.push("/**");
15712
+ lines.push(" * Union of all event names in the canvas");
15713
+ lines.push(" */");
15714
+ }
15715
+ lines.push(`export type AllEventNames = ${Array.from(allEventNames).map((n) => `'${n}'`).join(" | ")};`);
15716
+ return lines;
15717
+ }
15718
+ generateEmitterTypes(canvas, opts) {
15719
+ const lines = [];
15720
+ if (opts.includeDocComments) {
15721
+ lines.push("/**");
15722
+ lines.push(" * Type-safe event emitter for a specific node");
15723
+ lines.push(" *");
15724
+ lines.push(" * @example");
15725
+ lines.push(" * ```typescript");
15726
+ lines.push(" * const emit: NodeEmitter<GraphConverter.EventName, GraphConverter.Event> = ...");
15727
+ lines.push(" * emit('conversion.started', {");
15728
+ lines.push(" * name: 'conversion.started',");
15729
+ lines.push(" * attributes: { ... }");
15730
+ lines.push(" * });");
15731
+ lines.push(" * ```");
15732
+ lines.push(" */");
15733
+ }
15734
+ lines.push("export type NodeEmitter<");
15735
+ lines.push(" TEventName extends string,");
15736
+ lines.push(" TEvent extends { name: TEventName; attributes: Record<string, any> }");
15737
+ lines.push("> = (event: TEvent) => void;");
15738
+ lines.push("");
15739
+ if (opts.includeDocComments) {
15740
+ lines.push("/**");
15741
+ lines.push(" * Type-safe event emitter by event name");
15742
+ lines.push(" *");
15743
+ lines.push(" * @example");
15744
+ lines.push(" * ```typescript");
15745
+ lines.push(" * const emit: NodeEmitterByName<GraphConverter.Event> = ...");
15746
+ lines.push(" * emit('conversion.started', {");
15747
+ lines.push(" * 'config.nodeTypes': 2,");
15748
+ lines.push(" * 'config.edgeTypes': 1");
15749
+ lines.push(" * });");
15750
+ lines.push(" * ```");
15751
+ lines.push(" */");
15752
+ }
15753
+ lines.push("export type NodeEmitterByName<");
15754
+ lines.push(" TEvent extends { name: string; attributes: Record<string, any> }");
15755
+ lines.push("> = <TName extends TEvent['name']>(");
15756
+ lines.push(" eventName: TName,");
15757
+ lines.push(" attributes: Extract<TEvent, { name: TName }>['attributes']");
15758
+ lines.push(") => void;");
15759
+ return lines;
15760
+ }
15761
+ nodeIdToTypeName(nodeId) {
15762
+ return nodeId.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
15763
+ }
15764
+ eventNameToTypeName(eventName) {
15765
+ return eventName.split(".").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
15766
+ }
15767
+ fieldTypeToTsType(fieldSchema) {
15768
+ switch (fieldSchema.type) {
15769
+ case "string":
15770
+ return "string";
15771
+ case "number":
15772
+ return "number";
15773
+ case "boolean":
15774
+ return "boolean";
15775
+ case "array":
15776
+ return "any[]";
15777
+ case "object":
15778
+ return "Record<string, any>";
15779
+ default:
15780
+ return "any";
15781
+ }
15782
+ }
15783
+ generateFilename(canvas) {
15784
+ const name = canvas.pv?.name || "canvas";
15785
+ const kebab = name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
15786
+ return `${kebab}.types.ts`;
15787
+ }
15788
+ };
15789
+ var generatorRegistry = {
15790
+ generators: /* @__PURE__ */ new Map([
15791
+ ["typescript", new TypeScriptGenerator()]
15792
+ ]),
15793
+ register(generator) {
15794
+ this.generators.set(generator.language, generator);
15795
+ },
15796
+ get(language) {
15797
+ return this.generators.get(language);
15798
+ },
15799
+ list() {
15800
+ return Array.from(this.generators.keys());
15801
+ }
15802
+ };
15803
+
15550
15804
  // ../core/dist/utils/YamlParser.js
15551
15805
  function parseYaml(content, filename) {
15552
15806
  try {