@principal-ai/principal-view-core 0.26.24 → 0.26.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.
Files changed (51) hide show
  1. package/dist/codegen/type-generator.d.ts.map +1 -1
  2. package/dist/codegen/type-generator.js +45 -17
  3. package/dist/codegen/type-generator.js.map +1 -1
  4. package/dist/index.d.ts +2 -2
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +3 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/matchers/SpanMatcher.d.ts.map +1 -1
  9. package/dist/matchers/SpanMatcher.js +10 -2
  10. package/dist/matchers/SpanMatcher.js.map +1 -1
  11. package/dist/registry/EventRegistry.d.ts.map +1 -1
  12. package/dist/registry/EventRegistry.js +39 -16
  13. package/dist/registry/EventRegistry.js.map +1 -1
  14. package/dist/spans/utils.d.ts.map +1 -1
  15. package/dist/spans/utils.js +21 -0
  16. package/dist/spans/utils.js.map +1 -1
  17. package/dist/storyboard/builder.d.ts.map +1 -1
  18. package/dist/storyboard/builder.js +10 -5
  19. package/dist/storyboard/builder.js.map +1 -1
  20. package/dist/telemetry/coverage.d.ts.map +1 -1
  21. package/dist/telemetry/coverage.js +29 -15
  22. package/dist/telemetry/coverage.js.map +1 -1
  23. package/dist/telemetry/event-validator.d.ts.map +1 -1
  24. package/dist/telemetry/event-validator.js +24 -9
  25. package/dist/telemetry/event-validator.js.map +1 -1
  26. package/dist/types/canvas.d.ts +4 -6
  27. package/dist/types/canvas.d.ts.map +1 -1
  28. package/dist/types/canvas.js +8 -1
  29. package/dist/types/canvas.js.map +1 -1
  30. package/dist/types/library.d.ts +21 -0
  31. package/dist/types/library.d.ts.map +1 -1
  32. package/dist/utils/CanvasConverter.d.ts +20 -0
  33. package/dist/utils/CanvasConverter.d.ts.map +1 -1
  34. package/dist/utils/CanvasConverter.js +209 -187
  35. package/dist/utils/CanvasConverter.js.map +1 -1
  36. package/dist/workflow/edge-validation.d.ts.map +1 -1
  37. package/dist/workflow/edge-validation.js +13 -4
  38. package/dist/workflow/edge-validation.js.map +1 -1
  39. package/package.json +1 -1
  40. package/src/codegen/type-generator.ts +46 -20
  41. package/src/index.ts +2 -0
  42. package/src/matchers/SpanMatcher.ts +11 -2
  43. package/src/registry/EventRegistry.ts +41 -17
  44. package/src/spans/utils.ts +22 -0
  45. package/src/storyboard/builder.ts +11 -4
  46. package/src/telemetry/coverage.ts +28 -15
  47. package/src/telemetry/event-validator.ts +26 -11
  48. package/src/types/canvas.ts +9 -6
  49. package/src/types/library.ts +22 -0
  50. package/src/utils/CanvasConverter.ts +218 -181
  51. package/src/workflow/edge-validation.ts +13 -4
@@ -12,7 +12,8 @@
12
12
  * - Zod: runtime validation with TypeScript inference
13
13
  */
14
14
 
15
- import type { ExtendedCanvas, PVEventSchema, PVEventFieldSchema } from '../types/canvas';
15
+ import type { ExtendedCanvas, PVEventSchema, PVEventFieldSchema, ExtendedCanvasNode } from '../types/canvas';
16
+ import { isOtelEventNode, isStandardCanvasNode } from '../types/canvas';
16
17
  import type { ComponentLibrary } from '../types/library';
17
18
 
18
19
  /**
@@ -103,18 +104,32 @@ export class TypeScriptGenerator implements CodeGenerator {
103
104
  for (const node of canvas.nodes) {
104
105
  let eventSchema: PVEventSchema | undefined;
105
106
 
106
- // Check for inline event definition
107
- if (node.pv?.event) {
108
- eventSchema = node.pv.event;
107
+ // Check for OTEL event node (top-level event/eventRef fields)
108
+ if (isOtelEventNode(node)) {
109
+ if (node.event) {
110
+ eventSchema = node.event;
111
+ } else if (node.eventRef) {
112
+ eventSchema = this.resolveLibraryEvent(node.eventRef, library);
113
+ if (!eventSchema) {
114
+ console.warn(
115
+ `Node '${node.id}' references unknown library event '${node.eventRef}'`
116
+ );
117
+ continue;
118
+ }
119
+ }
109
120
  }
110
- // Check for library event reference
111
- else if (node.pv?.eventRef) {
112
- eventSchema = this.resolveLibraryEvent(node.pv.eventRef, library);
113
- if (!eventSchema) {
114
- console.warn(
115
- `Node '${node.id}' references unknown library event '${node.pv.eventRef}'`
116
- );
117
- continue;
121
+ // Check for standard node with pv.event/pv.eventRef
122
+ else if (isStandardCanvasNode(node)) {
123
+ if (node.pv?.event) {
124
+ eventSchema = node.pv.event;
125
+ } else if (node.pv?.eventRef) {
126
+ eventSchema = this.resolveLibraryEvent(node.pv.eventRef, library);
127
+ if (!eventSchema) {
128
+ console.warn(
129
+ `Node '${node.id}' references unknown library event '${node.pv.eventRef}'`
130
+ );
131
+ continue;
132
+ }
118
133
  }
119
134
  }
120
135
 
@@ -308,15 +323,26 @@ export class TypeScriptGenerator implements CodeGenerator {
308
323
 
309
324
  if (canvas.nodes) {
310
325
  for (const node of canvas.nodes) {
311
- // Check for inline event definition
312
- if (node.pv?.event?.name) {
313
- allEventNames.add(node.pv.event.name);
326
+ // Check for OTEL event node (top-level event/eventRef fields)
327
+ if (isOtelEventNode(node)) {
328
+ if (node.event?.name) {
329
+ allEventNames.add(node.event.name);
330
+ } else if (node.eventRef) {
331
+ const eventSchema = this.resolveLibraryEvent(node.eventRef, library);
332
+ if (eventSchema) {
333
+ allEventNames.add(eventSchema.name);
334
+ }
335
+ }
314
336
  }
315
- // Check for library event reference
316
- else if (node.pv?.eventRef) {
317
- const eventSchema = this.resolveLibraryEvent(node.pv.eventRef, library);
318
- if (eventSchema) {
319
- allEventNames.add(eventSchema.name);
337
+ // Check for standard node with pv.event/pv.eventRef
338
+ else if (isStandardCanvasNode(node)) {
339
+ if (node.pv?.event?.name) {
340
+ allEventNames.add(node.pv.event.name);
341
+ } else if (node.pv?.eventRef) {
342
+ const eventSchema = this.resolveLibraryEvent(node.pv.eventRef, library);
343
+ if (eventSchema) {
344
+ allEventNames.add(eventSchema.name);
345
+ }
320
346
  }
321
347
  }
322
348
  }
package/src/index.ts CHANGED
@@ -16,6 +16,7 @@ import {
16
16
  isLinkNode,
17
17
  isGroupNode,
18
18
  hasPVExtension,
19
+ isStandardCanvasNode,
19
20
  CANVAS_COLOR_PRESETS,
20
21
  resolveCanvasColor,
21
22
  } from './types/canvas';
@@ -113,6 +114,7 @@ export {
113
114
  isLinkNode,
114
115
  isGroupNode,
115
116
  hasPVExtension,
117
+ isStandardCanvasNode,
116
118
  CANVAS_COLOR_PRESETS,
117
119
  resolveCanvasColor,
118
120
  };
@@ -9,6 +9,7 @@
9
9
  */
10
10
 
11
11
  import type { ExtendedCanvas, PVOtelExtension } from '../types/canvas';
12
+ import { isOtelNode, isStandardCanvasNode } from '../types/canvas';
12
13
  import type { OtelSpanData, OtelResourceData } from '../types/otel';
13
14
  import {
14
15
  getAttributeValue,
@@ -89,9 +90,17 @@ export class SpanMatcher {
89
90
  if (!canvas.nodes) return rules;
90
91
 
91
92
  for (const node of canvas.nodes) {
92
- if (!node.pv?.otel) continue;
93
+ // Get OTEL metadata from either OTEL nodes (top-level) or standard nodes (pv.otel)
94
+ let otel: PVOtelExtension | undefined;
95
+
96
+ if (isOtelNode(node) && node.otel) {
97
+ otel = node.otel as PVOtelExtension;
98
+ } else if (isStandardCanvasNode(node) && node.pv?.otel) {
99
+ otel = node.pv.otel as PVOtelExtension;
100
+ }
101
+
102
+ if (!otel) continue;
93
103
 
94
- const otel = node.pv.otel as PVOtelExtension;
95
104
  const rule: CompiledMatchRule = {
96
105
  nodeId: node.id,
97
106
  resourceMatchers: [],
@@ -7,6 +7,7 @@
7
7
 
8
8
  import type { ComponentLibrary } from '../types/library';
9
9
  import type { ExtendedCanvas, PVEventSchema } from '../types/canvas';
10
+ import { isOtelEventNode, isStandardCanvasNode } from '../types/canvas';
10
11
 
11
12
  /**
12
13
  * Describes where an event is defined
@@ -81,28 +82,51 @@ export class EventRegistry {
81
82
  if (!canvas.nodes) continue;
82
83
 
83
84
  for (const node of canvas.nodes) {
84
- if (!node.pv) continue;
85
-
86
- // Inline event definition (pv.event)
87
- if (node.pv.event && typeof node.pv.event === 'object' && node.pv.event.name) {
88
- registry.addEvent(node.pv.event.name, {
89
- type: 'canvas',
90
- path: canvasPath,
91
- eventSchema: node.pv.event,
92
- });
93
- }
85
+ // Handle OTEL event nodes (top-level event/eventRef)
86
+ if (isOtelEventNode(node)) {
87
+ // Inline event definition
88
+ if (node.event && typeof node.event === 'object' && node.event.name) {
89
+ registry.addEvent(node.event.name, {
90
+ type: 'canvas',
91
+ path: canvasPath,
92
+ eventSchema: node.event,
93
+ });
94
+ }
94
95
 
95
- // Event reference (pv.eventRef) - note: these should resolve to library
96
- // but we track them as canvas sources too for completeness
97
- if (node.pv.eventRef && typeof node.pv.eventRef === 'string') {
98
- // Only add if not already in registry (library takes priority)
99
- if (!registry.hasEvent(node.pv.eventRef)) {
100
- registry.addEvent(node.pv.eventRef, {
96
+ // Event reference
97
+ if (node.eventRef && typeof node.eventRef === 'string') {
98
+ // Only add if not already in registry (library takes priority)
99
+ if (!registry.hasEvent(node.eventRef)) {
100
+ registry.addEvent(node.eventRef, {
101
+ type: 'canvas',
102
+ path: canvasPath,
103
+ // No schema available - it's just a reference
104
+ });
105
+ }
106
+ }
107
+ }
108
+ // Handle standard nodes with pv.event/pv.eventRef
109
+ else if (isStandardCanvasNode(node) && node.pv) {
110
+ // Inline event definition (pv.event)
111
+ if (node.pv.event && typeof node.pv.event === 'object' && node.pv.event.name) {
112
+ registry.addEvent(node.pv.event.name, {
101
113
  type: 'canvas',
102
114
  path: canvasPath,
103
- // No schema available - it's just a reference
115
+ eventSchema: node.pv.event,
104
116
  });
105
117
  }
118
+
119
+ // Event reference (pv.eventRef)
120
+ if (node.pv.eventRef && typeof node.pv.eventRef === 'string') {
121
+ // Only add if not already in registry (library takes priority)
122
+ if (!registry.hasEvent(node.pv.eventRef)) {
123
+ registry.addEvent(node.pv.eventRef, {
124
+ type: 'canvas',
125
+ path: canvasPath,
126
+ // No schema available - it's just a reference
127
+ });
128
+ }
129
+ }
106
130
  }
107
131
  }
108
132
  }
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import type { ExtendedCanvas, ExtendedCanvasNode } from '../types/canvas';
9
+ import { isOtelSpanConventionNode, isStandardCanvasNode } from '../types/canvas';
9
10
 
10
11
  /** Default color for spans without a defined color */
11
12
  export const DEFAULT_SPAN_COLOR = '#9CA3AF'; // gray-400
@@ -32,6 +33,27 @@ export interface NormalizedSpanConvention {
32
33
  * Extract span convention from a canvas node
33
34
  */
34
35
  export function extractSpanConvention(node: ExtendedCanvasNode): NormalizedSpanConvention | null {
36
+ // Handle OTEL span convention nodes (top-level otel field)
37
+ if (isOtelSpanConventionNode(node)) {
38
+ const spanPattern = node.otel?.spanPattern;
39
+ if (!spanPattern) return null;
40
+
41
+ const color = node.color as string | undefined;
42
+ if (!color) return null;
43
+
44
+ return {
45
+ id: node.id,
46
+ spanPattern,
47
+ color,
48
+ icon: node.icon,
49
+ description: node.description,
50
+ status: node.otel?.status,
51
+ };
52
+ }
53
+
54
+ // Handle standard nodes with pv.nodeType === 'span-convention'
55
+ if (!isStandardCanvasNode(node)) return null;
56
+
35
57
  const pv = node.pv;
36
58
  if (!pv) return null;
37
59
 
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import type { ExtendedCanvas, ExtendedCanvasNode } from '../types/canvas';
9
+ import { isOtelEventNode, isStandardCanvasNode } from '../types/canvas';
9
10
  import type { WorkflowTemplate, WorkflowScenario } from '../workflow/types';
10
11
  import type {
11
12
  StoryboardReference,
@@ -102,11 +103,17 @@ export function getNodeEventName(node: ExtendedCanvasNode): string | undefined {
102
103
  const topLevelEvent = (node as { event?: { name?: string } }).event?.name;
103
104
  if (topLevelEvent) return topLevelEvent;
104
105
 
105
- const topLevelEventRef = (node as { eventRef?: string }).eventRef;
106
- if (topLevelEventRef) return topLevelEventRef;
106
+ // Check OTEL event node (top-level event/eventRef)
107
+ if (isOtelEventNode(node)) {
108
+ return node.event?.name || node.eventRef;
109
+ }
110
+
111
+ // Check standard node with pv.event/pv.eventRef
112
+ if (isStandardCanvasNode(node)) {
113
+ return node.pv?.event?.name || node.pv?.eventRef;
114
+ }
107
115
 
108
- // 2. PVNodeExtension format (inside node.pv)
109
- return node.pv?.event?.name || node.pv?.eventRef;
116
+ return undefined;
110
117
  }
111
118
 
112
119
  /**
@@ -12,6 +12,7 @@ import type { FileTree } from '@principal-ai/repository-abstraction';
12
12
  import { CanvasDiscovery } from '../discovery/CanvasDiscovery';
13
13
  import type { DiscoveredCanvasWithContent } from '../discovery/types';
14
14
  import type { ExtendedCanvasNode } from '../types/canvas';
15
+ import { isOtelNode, isStandardCanvasNode } from '../types/canvas';
15
16
  import { getNodeEventName } from '../storyboard/builder';
16
17
  import {
17
18
  ImplementationFileLayerModule,
@@ -108,13 +109,15 @@ function getEventName(node: ExtendedCanvasNode): string | null {
108
109
  * Supports both new format (node.otel.files) and legacy format (pv.otel.files)
109
110
  */
110
111
  function getInstrumentationFiles(node: ExtendedCanvasNode): string[] {
111
- // Check new format first (otel-event nodes)
112
- const otelNode = node as { otel?: { files?: string[] } };
113
- if (otelNode.otel?.files) {
114
- return otelNode.otel.files;
112
+ // Check OTEL nodes (top-level otel field)
113
+ if (isOtelNode(node) && node.otel?.files) {
114
+ return node.otel.files;
115
115
  }
116
- // Fallback to legacy format (pv.otel.files)
117
- return node.pv?.otel?.files || [];
116
+ // Check standard nodes (pv.otel.files)
117
+ if (isStandardCanvasNode(node) && node.pv?.otel?.files) {
118
+ return node.pv.otel.files;
119
+ }
120
+ return [];
118
121
  }
119
122
 
120
123
  /**
@@ -138,13 +141,15 @@ async function fileContainsEvent(
138
141
  * Supports both new format (node.otel.status) and legacy format (pv.status)
139
142
  */
140
143
  function getNodeStatus(node: ExtendedCanvasNode): 'draft' | 'approved' | 'implemented' | undefined {
141
- // Check new format first (otel-event nodes)
142
- const otelNode = node as { otel?: { status?: 'draft' | 'approved' | 'implemented' } };
143
- if (otelNode.otel?.status) {
144
- return otelNode.otel.status;
144
+ // Check OTEL nodes (otel.status)
145
+ if (isOtelNode(node) && node.otel?.status) {
146
+ return node.otel.status;
147
+ }
148
+ // Check standard nodes (pv.status)
149
+ if (isStandardCanvasNode(node) && node.pv?.status) {
150
+ return node.pv.status;
145
151
  }
146
- // Fallback to legacy format (pv.status)
147
- return node.pv?.status;
152
+ return undefined;
148
153
  }
149
154
 
150
155
  /**
@@ -234,7 +239,12 @@ function validateNodes(
234
239
  }
235
240
 
236
241
  // Get references for grounding validation
237
- const references = node.pv?.references || [];
242
+ let references: string[] = [];
243
+ if (isOtelNode(node) && node.otel?.references) {
244
+ references = node.otel.references;
245
+ } else if (isStandardCanvasNode(node) && node.pv?.references) {
246
+ references = node.pv.references;
247
+ }
238
248
  const hasReferences = references.length > 0;
239
249
 
240
250
  // Count by status
@@ -271,8 +281,11 @@ function validateNodes(
271
281
  });
272
282
  }
273
283
 
274
- // Error if using deprecated pv.otel.scope
275
- const legacyScope = node.pv?.otel?.scope;
284
+ // Error if using deprecated pv.otel.scope (only for standard nodes)
285
+ let legacyScope: string | undefined;
286
+ if (isStandardCanvasNode(node)) {
287
+ legacyScope = node.pv?.otel?.scope;
288
+ }
276
289
  if (legacyScope) {
277
290
  errors.push({
278
291
  nodeId: node.id,
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import type { ExtendedCanvas, PVEventSchema } from '../types/canvas';
9
+ import { isOtelEventNode, isStandardCanvasNode } from '../types/canvas';
9
10
  import type { ComponentLibrary } from '../types/library';
10
11
  import type { JsonValue, JsonObject } from '../types';
11
12
 
@@ -54,18 +55,32 @@ export class EventValidator {
54
55
  for (const node of canvas.nodes) {
55
56
  let eventSchema: PVEventSchema | undefined;
56
57
 
57
- // Check for inline event definition
58
- if (node.pv?.event) {
59
- eventSchema = node.pv.event;
58
+ // Check OTEL event node (top-level event/eventRef)
59
+ if (isOtelEventNode(node)) {
60
+ if (node.event) {
61
+ eventSchema = node.event;
62
+ } else if (node.eventRef) {
63
+ eventSchema = this.resolveLibraryEvent(node.eventRef);
64
+ if (!eventSchema) {
65
+ console.warn(
66
+ `Node '${node.id}' references unknown library event '${node.eventRef}'`
67
+ );
68
+ continue;
69
+ }
70
+ }
60
71
  }
61
- // Check for library event reference
62
- else if (node.pv?.eventRef) {
63
- eventSchema = this.resolveLibraryEvent(node.pv.eventRef);
64
- if (!eventSchema) {
65
- console.warn(
66
- `Node '${node.id}' references unknown library event '${node.pv.eventRef}'`
67
- );
68
- continue;
72
+ // Check standard node (pv.event/pv.eventRef)
73
+ else if (isStandardCanvasNode(node)) {
74
+ if (node.pv?.event) {
75
+ eventSchema = node.pv.event;
76
+ } else if (node.pv?.eventRef) {
77
+ eventSchema = this.resolveLibraryEvent(node.pv.eventRef);
78
+ if (!eventSchema) {
79
+ console.warn(
80
+ `Node '${node.id}' references unknown library event '${node.pv.eventRef}'`
81
+ );
82
+ continue;
83
+ }
69
84
  }
70
85
  }
71
86
 
@@ -911,12 +911,6 @@ export interface OtelNodeBase extends CanvasNodeBase {
911
911
  stroke?: string;
912
912
  /** Visual shape */
913
913
  shape?: PVNodeShape;
914
- /**
915
- * Legacy PV extension field for backward compatibility during migration.
916
- * New OTEL nodes should use top-level fields instead.
917
- * @deprecated Use top-level fields (label, icon, etc.) instead
918
- */
919
- pv?: PVNodeExtension;
920
914
  }
921
915
 
922
916
  /**
@@ -1302,6 +1296,15 @@ export function isOtelNode(node: ExtendedCanvasNode): node is OtelNode {
1302
1296
  );
1303
1297
  }
1304
1298
 
1299
+ /**
1300
+ * Type guard for standard canvas nodes (that may have pv extensions)
1301
+ */
1302
+ export function isStandardCanvasNode(
1303
+ node: ExtendedCanvasNode
1304
+ ): node is ExtendedCanvasTextNode | ExtendedCanvasFileNode | ExtendedCanvasLinkNode | ExtendedCanvasGroupNode {
1305
+ return !isOtelNode(node);
1306
+ }
1307
+
1305
1308
  /**
1306
1309
  * Get the identifier for an OTEL node (shown below the label)
1307
1310
  */
@@ -398,6 +398,28 @@ export interface ComponentLibrary {
398
398
 
399
399
  /** Optional connection rules (which nodes can connect via which edges) */
400
400
  connectionRules?: LibraryConnectionRule[];
401
+
402
+ /**
403
+ * Global state definitions for OTEL nodes
404
+ *
405
+ * Defines reusable states that can be applied to OTEL event and span nodes.
406
+ * States provide visual indicators (colors) for different statuses.
407
+ *
408
+ * @example
409
+ * ```yaml
410
+ * states:
411
+ * draft:
412
+ * color: "#f59e0b"
413
+ * label: "Draft"
414
+ * approved:
415
+ * color: "#10b981"
416
+ * label: "Approved"
417
+ * implemented:
418
+ * color: "#6366f1"
419
+ * label: "Implemented"
420
+ * ```
421
+ */
422
+ states?: Record<string, PVNodeState>;
401
423
  }
402
424
 
403
425
  // ============================================================================