@principal-ai/principal-view-cli 0.1.18 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +7 -7
- package/dist/commands/hooks.d.ts.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +4 -2
- package/dist/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +14 -9
- package/dist/commands/schema.d.ts.map +1 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +174 -34
- package/dist/index.cjs +456 -97
- package/dist/index.cjs.map +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -13484,31 +13484,65 @@ function validateLibrary(library) {
|
|
|
13484
13484
|
for (const [compId, compDef] of Object.entries(lib.nodeComponents)) {
|
|
13485
13485
|
if (compDef && typeof compDef === "object") {
|
|
13486
13486
|
const comp = compDef;
|
|
13487
|
-
checkUnknownFields(
|
|
13487
|
+
checkUnknownFields(
|
|
13488
|
+
comp,
|
|
13489
|
+
ALLOWED_LIBRARY_FIELDS.nodeComponent,
|
|
13490
|
+
`nodeComponents.${compId}`,
|
|
13491
|
+
issues
|
|
13492
|
+
);
|
|
13488
13493
|
if (comp.size && typeof comp.size === "object") {
|
|
13489
|
-
checkUnknownFields(
|
|
13494
|
+
checkUnknownFields(
|
|
13495
|
+
comp.size,
|
|
13496
|
+
ALLOWED_LIBRARY_FIELDS.nodeComponentSize,
|
|
13497
|
+
`nodeComponents.${compId}.size`,
|
|
13498
|
+
issues
|
|
13499
|
+
);
|
|
13490
13500
|
}
|
|
13491
13501
|
if (comp.states && typeof comp.states === "object") {
|
|
13492
|
-
for (const [stateId, stateDef] of Object.entries(
|
|
13502
|
+
for (const [stateId, stateDef] of Object.entries(
|
|
13503
|
+
comp.states
|
|
13504
|
+
)) {
|
|
13493
13505
|
if (stateDef && typeof stateDef === "object") {
|
|
13494
|
-
checkUnknownFields(
|
|
13506
|
+
checkUnknownFields(
|
|
13507
|
+
stateDef,
|
|
13508
|
+
ALLOWED_LIBRARY_FIELDS.nodeComponentState,
|
|
13509
|
+
`nodeComponents.${compId}.states.${stateId}`,
|
|
13510
|
+
issues
|
|
13511
|
+
);
|
|
13495
13512
|
}
|
|
13496
13513
|
}
|
|
13497
13514
|
}
|
|
13498
13515
|
if (comp.dataSchema && typeof comp.dataSchema === "object") {
|
|
13499
|
-
for (const [fieldName, fieldDef] of Object.entries(
|
|
13516
|
+
for (const [fieldName, fieldDef] of Object.entries(
|
|
13517
|
+
comp.dataSchema
|
|
13518
|
+
)) {
|
|
13500
13519
|
if (fieldDef && typeof fieldDef === "object") {
|
|
13501
|
-
checkUnknownFields(
|
|
13520
|
+
checkUnknownFields(
|
|
13521
|
+
fieldDef,
|
|
13522
|
+
ALLOWED_LIBRARY_FIELDS.nodeComponentDataSchemaField,
|
|
13523
|
+
`nodeComponents.${compId}.dataSchema.${fieldName}`,
|
|
13524
|
+
issues
|
|
13525
|
+
);
|
|
13502
13526
|
}
|
|
13503
13527
|
}
|
|
13504
13528
|
}
|
|
13505
13529
|
if (comp.layout && typeof comp.layout === "object") {
|
|
13506
|
-
checkUnknownFields(
|
|
13530
|
+
checkUnknownFields(
|
|
13531
|
+
comp.layout,
|
|
13532
|
+
ALLOWED_LIBRARY_FIELDS.nodeComponentLayout,
|
|
13533
|
+
`nodeComponents.${compId}.layout`,
|
|
13534
|
+
issues
|
|
13535
|
+
);
|
|
13507
13536
|
}
|
|
13508
13537
|
if (Array.isArray(comp.actions)) {
|
|
13509
13538
|
comp.actions.forEach((action, actionIndex) => {
|
|
13510
13539
|
if (action && typeof action === "object") {
|
|
13511
|
-
checkUnknownFields(
|
|
13540
|
+
checkUnknownFields(
|
|
13541
|
+
action,
|
|
13542
|
+
ALLOWED_LIBRARY_FIELDS.nodeComponentAction,
|
|
13543
|
+
`nodeComponents.${compId}.actions[${actionIndex}]`,
|
|
13544
|
+
issues
|
|
13545
|
+
);
|
|
13512
13546
|
}
|
|
13513
13547
|
});
|
|
13514
13548
|
}
|
|
@@ -13519,12 +13553,27 @@ function validateLibrary(library) {
|
|
|
13519
13553
|
for (const [compId, compDef] of Object.entries(lib.edgeComponents)) {
|
|
13520
13554
|
if (compDef && typeof compDef === "object") {
|
|
13521
13555
|
const comp = compDef;
|
|
13522
|
-
checkUnknownFields(
|
|
13556
|
+
checkUnknownFields(
|
|
13557
|
+
comp,
|
|
13558
|
+
ALLOWED_LIBRARY_FIELDS.edgeComponent,
|
|
13559
|
+
`edgeComponents.${compId}`,
|
|
13560
|
+
issues
|
|
13561
|
+
);
|
|
13523
13562
|
if (comp.animation && typeof comp.animation === "object") {
|
|
13524
|
-
checkUnknownFields(
|
|
13563
|
+
checkUnknownFields(
|
|
13564
|
+
comp.animation,
|
|
13565
|
+
ALLOWED_LIBRARY_FIELDS.edgeComponentAnimation,
|
|
13566
|
+
`edgeComponents.${compId}.animation`,
|
|
13567
|
+
issues
|
|
13568
|
+
);
|
|
13525
13569
|
}
|
|
13526
13570
|
if (comp.label && typeof comp.label === "object") {
|
|
13527
|
-
checkUnknownFields(
|
|
13571
|
+
checkUnknownFields(
|
|
13572
|
+
comp.label,
|
|
13573
|
+
ALLOWED_LIBRARY_FIELDS.edgeComponentLabel,
|
|
13574
|
+
`edgeComponents.${compId}.label`,
|
|
13575
|
+
issues
|
|
13576
|
+
);
|
|
13528
13577
|
}
|
|
13529
13578
|
}
|
|
13530
13579
|
}
|
|
@@ -13533,9 +13582,19 @@ function validateLibrary(library) {
|
|
|
13533
13582
|
lib.connectionRules.forEach((rule, ruleIndex) => {
|
|
13534
13583
|
if (rule && typeof rule === "object") {
|
|
13535
13584
|
const r = rule;
|
|
13536
|
-
checkUnknownFields(
|
|
13585
|
+
checkUnknownFields(
|
|
13586
|
+
r,
|
|
13587
|
+
ALLOWED_LIBRARY_FIELDS.connectionRule,
|
|
13588
|
+
`connectionRules[${ruleIndex}]`,
|
|
13589
|
+
issues
|
|
13590
|
+
);
|
|
13537
13591
|
if (r.constraints && typeof r.constraints === "object") {
|
|
13538
|
-
checkUnknownFields(
|
|
13592
|
+
checkUnknownFields(
|
|
13593
|
+
r.constraints,
|
|
13594
|
+
ALLOWED_LIBRARY_FIELDS.connectionRuleConstraints,
|
|
13595
|
+
`connectionRules[${ruleIndex}].constraints`,
|
|
13596
|
+
issues
|
|
13597
|
+
);
|
|
13539
13598
|
}
|
|
13540
13599
|
}
|
|
13541
13600
|
});
|
|
@@ -13547,12 +13606,27 @@ var VALID_NODE_SHAPES = ["circle", "rectangle", "hexagon", "diamond", "custom"];
|
|
|
13547
13606
|
var ALLOWED_CANVAS_FIELDS = {
|
|
13548
13607
|
root: ["nodes", "edges", "pv"],
|
|
13549
13608
|
pv: ["version", "name", "description", "nodeTypes", "edgeTypes", "pathConfig", "display"],
|
|
13550
|
-
pvPathConfig: [
|
|
13609
|
+
pvPathConfig: [
|
|
13610
|
+
"projectRoot",
|
|
13611
|
+
"captureSource",
|
|
13612
|
+
"enableActionPatterns",
|
|
13613
|
+
"logLevel",
|
|
13614
|
+
"ignoreUnsourced"
|
|
13615
|
+
],
|
|
13551
13616
|
pvDisplay: ["layout", "theme", "animations"],
|
|
13552
13617
|
pvDisplayTheme: ["primary", "success", "warning", "danger", "info"],
|
|
13553
13618
|
pvDisplayAnimations: ["enabled", "speed"],
|
|
13554
13619
|
pvNodeType: ["label", "description", "color", "icon", "shape"],
|
|
13555
|
-
pvEdgeType: [
|
|
13620
|
+
pvEdgeType: [
|
|
13621
|
+
"label",
|
|
13622
|
+
"style",
|
|
13623
|
+
"color",
|
|
13624
|
+
"width",
|
|
13625
|
+
"directed",
|
|
13626
|
+
"animation",
|
|
13627
|
+
"labelConfig",
|
|
13628
|
+
"activatedBy"
|
|
13629
|
+
],
|
|
13556
13630
|
pvEdgeTypeAnimation: ["type", "duration", "color"],
|
|
13557
13631
|
pvEdgeTypeLabelConfig: ["field", "position"],
|
|
13558
13632
|
// Base node fields from JSON Canvas spec
|
|
@@ -13563,26 +13637,71 @@ var ALLOWED_CANVAS_FIELDS = {
|
|
|
13563
13637
|
nodeLink: ["url"],
|
|
13564
13638
|
nodeGroup: ["label", "background", "backgroundStyle"],
|
|
13565
13639
|
// Node pv extension
|
|
13566
|
-
nodePv: [
|
|
13640
|
+
nodePv: [
|
|
13641
|
+
"nodeType",
|
|
13642
|
+
"description",
|
|
13643
|
+
"shape",
|
|
13644
|
+
"icon",
|
|
13645
|
+
"fill",
|
|
13646
|
+
"stroke",
|
|
13647
|
+
"states",
|
|
13648
|
+
"sources",
|
|
13649
|
+
"actions",
|
|
13650
|
+
"dataSchema",
|
|
13651
|
+
"layout"
|
|
13652
|
+
],
|
|
13567
13653
|
nodePvState: ["color", "icon", "label"],
|
|
13568
13654
|
nodePvAction: ["pattern", "event", "state", "metadata", "triggerEdges"],
|
|
13569
13655
|
nodePvDataSchemaField: ["type", "required", "displayInLabel"],
|
|
13570
13656
|
nodePvLayout: ["layer", "cluster"],
|
|
13571
13657
|
// Edge fields
|
|
13572
|
-
edge: [
|
|
13658
|
+
edge: [
|
|
13659
|
+
"id",
|
|
13660
|
+
"fromNode",
|
|
13661
|
+
"toNode",
|
|
13662
|
+
"fromSide",
|
|
13663
|
+
"toSide",
|
|
13664
|
+
"fromEnd",
|
|
13665
|
+
"toEnd",
|
|
13666
|
+
"color",
|
|
13667
|
+
"label",
|
|
13668
|
+
"pv"
|
|
13669
|
+
],
|
|
13573
13670
|
edgePv: ["edgeType", "style", "width", "animation", "activatedBy"],
|
|
13574
13671
|
edgePvAnimation: ["type", "duration", "color"],
|
|
13575
13672
|
edgePvActivatedBy: ["action", "animation", "direction", "duration"]
|
|
13576
13673
|
};
|
|
13577
13674
|
var ALLOWED_LIBRARY_FIELDS = {
|
|
13578
13675
|
root: ["version", "name", "description", "nodeComponents", "edgeComponents", "connectionRules"],
|
|
13579
|
-
nodeComponent: [
|
|
13676
|
+
nodeComponent: [
|
|
13677
|
+
"description",
|
|
13678
|
+
"tags",
|
|
13679
|
+
"defaultLabel",
|
|
13680
|
+
"shape",
|
|
13681
|
+
"icon",
|
|
13682
|
+
"color",
|
|
13683
|
+
"size",
|
|
13684
|
+
"states",
|
|
13685
|
+
"sources",
|
|
13686
|
+
"actions",
|
|
13687
|
+
"dataSchema",
|
|
13688
|
+
"layout"
|
|
13689
|
+
],
|
|
13580
13690
|
nodeComponentSize: ["width", "height"],
|
|
13581
13691
|
nodeComponentState: ["color", "icon", "label"],
|
|
13582
13692
|
nodeComponentAction: ["pattern", "event", "state", "metadata", "triggerEdges"],
|
|
13583
13693
|
nodeComponentDataSchemaField: ["type", "required", "displayInLabel", "label", "displayInInfo"],
|
|
13584
13694
|
nodeComponentLayout: ["layer", "cluster"],
|
|
13585
|
-
edgeComponent: [
|
|
13695
|
+
edgeComponent: [
|
|
13696
|
+
"description",
|
|
13697
|
+
"tags",
|
|
13698
|
+
"style",
|
|
13699
|
+
"color",
|
|
13700
|
+
"width",
|
|
13701
|
+
"directed",
|
|
13702
|
+
"animation",
|
|
13703
|
+
"label"
|
|
13704
|
+
],
|
|
13586
13705
|
edgeComponentAnimation: ["type", "duration", "color"],
|
|
13587
13706
|
edgeComponentLabel: ["field", "position"],
|
|
13588
13707
|
connectionRule: ["from", "to", "via", "constraints"],
|
|
@@ -13661,23 +13780,43 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13661
13780
|
});
|
|
13662
13781
|
}
|
|
13663
13782
|
if (pv.pathConfig && typeof pv.pathConfig === "object") {
|
|
13664
|
-
checkUnknownFields(
|
|
13783
|
+
checkUnknownFields(
|
|
13784
|
+
pv.pathConfig,
|
|
13785
|
+
ALLOWED_CANVAS_FIELDS.pvPathConfig,
|
|
13786
|
+
"pv.pathConfig",
|
|
13787
|
+
issues
|
|
13788
|
+
);
|
|
13665
13789
|
}
|
|
13666
13790
|
if (pv.display && typeof pv.display === "object") {
|
|
13667
13791
|
const display = pv.display;
|
|
13668
13792
|
checkUnknownFields(display, ALLOWED_CANVAS_FIELDS.pvDisplay, "pv.display", issues);
|
|
13669
13793
|
if (display.theme && typeof display.theme === "object") {
|
|
13670
|
-
checkUnknownFields(
|
|
13794
|
+
checkUnknownFields(
|
|
13795
|
+
display.theme,
|
|
13796
|
+
ALLOWED_CANVAS_FIELDS.pvDisplayTheme,
|
|
13797
|
+
"pv.display.theme",
|
|
13798
|
+
issues
|
|
13799
|
+
);
|
|
13671
13800
|
}
|
|
13672
13801
|
if (display.animations && typeof display.animations === "object") {
|
|
13673
|
-
checkUnknownFields(
|
|
13802
|
+
checkUnknownFields(
|
|
13803
|
+
display.animations,
|
|
13804
|
+
ALLOWED_CANVAS_FIELDS.pvDisplayAnimations,
|
|
13805
|
+
"pv.display.animations",
|
|
13806
|
+
issues
|
|
13807
|
+
);
|
|
13674
13808
|
}
|
|
13675
13809
|
}
|
|
13676
13810
|
if (pv.nodeTypes && typeof pv.nodeTypes === "object") {
|
|
13677
13811
|
canvasNodeTypes = Object.keys(pv.nodeTypes);
|
|
13678
13812
|
for (const [typeId, typeDef] of Object.entries(pv.nodeTypes)) {
|
|
13679
13813
|
if (typeDef && typeof typeDef === "object") {
|
|
13680
|
-
checkUnknownFields(
|
|
13814
|
+
checkUnknownFields(
|
|
13815
|
+
typeDef,
|
|
13816
|
+
ALLOWED_CANVAS_FIELDS.pvNodeType,
|
|
13817
|
+
`pv.nodeTypes.${typeId}`,
|
|
13818
|
+
issues
|
|
13819
|
+
);
|
|
13681
13820
|
}
|
|
13682
13821
|
}
|
|
13683
13822
|
}
|
|
@@ -13686,12 +13825,27 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13686
13825
|
for (const [typeId, typeDef] of Object.entries(pv.edgeTypes)) {
|
|
13687
13826
|
if (typeDef && typeof typeDef === "object") {
|
|
13688
13827
|
const edgeTypeDef = typeDef;
|
|
13689
|
-
checkUnknownFields(
|
|
13828
|
+
checkUnknownFields(
|
|
13829
|
+
edgeTypeDef,
|
|
13830
|
+
ALLOWED_CANVAS_FIELDS.pvEdgeType,
|
|
13831
|
+
`pv.edgeTypes.${typeId}`,
|
|
13832
|
+
issues
|
|
13833
|
+
);
|
|
13690
13834
|
if (edgeTypeDef.animation && typeof edgeTypeDef.animation === "object") {
|
|
13691
|
-
checkUnknownFields(
|
|
13835
|
+
checkUnknownFields(
|
|
13836
|
+
edgeTypeDef.animation,
|
|
13837
|
+
ALLOWED_CANVAS_FIELDS.pvEdgeTypeAnimation,
|
|
13838
|
+
`pv.edgeTypes.${typeId}.animation`,
|
|
13839
|
+
issues
|
|
13840
|
+
);
|
|
13692
13841
|
}
|
|
13693
13842
|
if (edgeTypeDef.labelConfig && typeof edgeTypeDef.labelConfig === "object") {
|
|
13694
|
-
checkUnknownFields(
|
|
13843
|
+
checkUnknownFields(
|
|
13844
|
+
edgeTypeDef.labelConfig,
|
|
13845
|
+
ALLOWED_CANVAS_FIELDS.pvEdgeTypeLabelConfig,
|
|
13846
|
+
`pv.edgeTypes.${typeId}.labelConfig`,
|
|
13847
|
+
issues
|
|
13848
|
+
);
|
|
13695
13849
|
}
|
|
13696
13850
|
}
|
|
13697
13851
|
}
|
|
@@ -13704,7 +13858,11 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13704
13858
|
} else {
|
|
13705
13859
|
c.nodes.forEach((node, index) => {
|
|
13706
13860
|
if (!node || typeof node !== "object") {
|
|
13707
|
-
issues.push({
|
|
13861
|
+
issues.push({
|
|
13862
|
+
type: "error",
|
|
13863
|
+
message: `Node at index ${index} must be an object`,
|
|
13864
|
+
path: `nodes[${index}]`
|
|
13865
|
+
});
|
|
13708
13866
|
return;
|
|
13709
13867
|
}
|
|
13710
13868
|
const n = node;
|
|
@@ -13723,31 +13881,83 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13723
13881
|
}
|
|
13724
13882
|
checkUnknownFields(n, allowedNodeFields, nodePath2, issues);
|
|
13725
13883
|
if (typeof n.id !== "string" || !n.id) {
|
|
13726
|
-
issues.push({
|
|
13884
|
+
issues.push({
|
|
13885
|
+
type: "error",
|
|
13886
|
+
message: `Node at index ${index} must have a string "id"`,
|
|
13887
|
+
path: `${nodePath2}.id`
|
|
13888
|
+
});
|
|
13727
13889
|
}
|
|
13728
13890
|
if (typeof n.type !== "string") {
|
|
13729
|
-
issues.push({
|
|
13891
|
+
issues.push({
|
|
13892
|
+
type: "error",
|
|
13893
|
+
message: `Node "${nodeLabel}" must have a string "type"`,
|
|
13894
|
+
path: `${nodePath2}.type`
|
|
13895
|
+
});
|
|
13730
13896
|
}
|
|
13731
13897
|
if (typeof n.x !== "number") {
|
|
13732
|
-
issues.push({
|
|
13898
|
+
issues.push({
|
|
13899
|
+
type: "error",
|
|
13900
|
+
message: `Node "${nodeLabel}" must have a numeric "x" position`,
|
|
13901
|
+
path: `${nodePath2}.x`
|
|
13902
|
+
});
|
|
13733
13903
|
}
|
|
13734
13904
|
if (typeof n.y !== "number") {
|
|
13735
|
-
issues.push({
|
|
13905
|
+
issues.push({
|
|
13906
|
+
type: "error",
|
|
13907
|
+
message: `Node "${nodeLabel}" must have a numeric "y" position`,
|
|
13908
|
+
path: `${nodePath2}.y`
|
|
13909
|
+
});
|
|
13736
13910
|
}
|
|
13737
13911
|
if (typeof n.width !== "number") {
|
|
13738
|
-
issues.push({
|
|
13912
|
+
issues.push({
|
|
13913
|
+
type: "error",
|
|
13914
|
+
message: `Node "${nodeLabel}" must have a numeric "width"`,
|
|
13915
|
+
path: `${nodePath2}.width`
|
|
13916
|
+
});
|
|
13739
13917
|
}
|
|
13740
13918
|
if (typeof n.height !== "number") {
|
|
13741
|
-
issues.push({
|
|
13919
|
+
issues.push({
|
|
13920
|
+
type: "error",
|
|
13921
|
+
message: `Node "${nodeLabel}" must have a numeric "height"`,
|
|
13922
|
+
path: `${nodePath2}.height`
|
|
13923
|
+
});
|
|
13924
|
+
}
|
|
13925
|
+
if (nodeType === "text" && (typeof n.text !== "string" || !n.text)) {
|
|
13926
|
+
issues.push({
|
|
13927
|
+
type: "error",
|
|
13928
|
+
message: `Node "${nodeLabel}" has type "text" but is missing required "text" field`,
|
|
13929
|
+
path: `${nodePath2}.text`,
|
|
13930
|
+
suggestion: 'Add a "text" field with markdown content, or change the node type'
|
|
13931
|
+
});
|
|
13742
13932
|
}
|
|
13743
|
-
|
|
13933
|
+
if (nodeType === "file" && (typeof n.file !== "string" || !n.file)) {
|
|
13934
|
+
issues.push({
|
|
13935
|
+
type: "error",
|
|
13936
|
+
message: `Node "${nodeLabel}" has type "file" but is missing required "file" field`,
|
|
13937
|
+
path: `${nodePath2}.file`,
|
|
13938
|
+
suggestion: 'Add a "file" field with a file path, or change the node type'
|
|
13939
|
+
});
|
|
13940
|
+
}
|
|
13941
|
+
if (nodeType === "link" && (typeof n.url !== "string" || !n.url)) {
|
|
13942
|
+
issues.push({
|
|
13943
|
+
type: "error",
|
|
13944
|
+
message: `Node "${nodeLabel}" has type "link" but is missing required "url" field`,
|
|
13945
|
+
path: `${nodePath2}.url`,
|
|
13946
|
+
suggestion: 'Add a "url" field with a URL, or change the node type'
|
|
13947
|
+
});
|
|
13948
|
+
}
|
|
13949
|
+
const isStandardType = STANDARD_CANVAS_TYPES.includes(
|
|
13950
|
+
nodeType
|
|
13951
|
+
);
|
|
13744
13952
|
if (!isStandardType) {
|
|
13745
13953
|
if (!n.pv || typeof n.pv !== "object") {
|
|
13746
13954
|
issues.push({
|
|
13747
13955
|
type: "error",
|
|
13748
13956
|
message: `Node "${n.id || index}" uses custom type "${nodeType}" but has no "pv" extension`,
|
|
13749
13957
|
path: `nodes[${index}].pv`,
|
|
13750
|
-
suggestion: `Use a standard type (${STANDARD_CANVAS_TYPES.join(
|
|
13958
|
+
suggestion: `Use a standard type (${STANDARD_CANVAS_TYPES.join(
|
|
13959
|
+
", "
|
|
13960
|
+
)}) or add pv.nodeType and pv.shape`
|
|
13751
13961
|
});
|
|
13752
13962
|
} else {
|
|
13753
13963
|
const nodePv = n.pv;
|
|
@@ -13772,26 +13982,50 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13772
13982
|
const nodePv = n.pv;
|
|
13773
13983
|
checkUnknownFields(nodePv, ALLOWED_CANVAS_FIELDS.nodePv, `${nodePath2}.pv`, issues);
|
|
13774
13984
|
if (nodePv.states && typeof nodePv.states === "object") {
|
|
13775
|
-
for (const [stateId, stateDef] of Object.entries(
|
|
13985
|
+
for (const [stateId, stateDef] of Object.entries(
|
|
13986
|
+
nodePv.states
|
|
13987
|
+
)) {
|
|
13776
13988
|
if (stateDef && typeof stateDef === "object") {
|
|
13777
|
-
checkUnknownFields(
|
|
13989
|
+
checkUnknownFields(
|
|
13990
|
+
stateDef,
|
|
13991
|
+
ALLOWED_CANVAS_FIELDS.nodePvState,
|
|
13992
|
+
`${nodePath2}.pv.states.${stateId}`,
|
|
13993
|
+
issues
|
|
13994
|
+
);
|
|
13778
13995
|
}
|
|
13779
13996
|
}
|
|
13780
13997
|
}
|
|
13781
13998
|
if (nodePv.dataSchema && typeof nodePv.dataSchema === "object") {
|
|
13782
|
-
for (const [fieldName, fieldDef] of Object.entries(
|
|
13999
|
+
for (const [fieldName, fieldDef] of Object.entries(
|
|
14000
|
+
nodePv.dataSchema
|
|
14001
|
+
)) {
|
|
13783
14002
|
if (fieldDef && typeof fieldDef === "object") {
|
|
13784
|
-
checkUnknownFields(
|
|
14003
|
+
checkUnknownFields(
|
|
14004
|
+
fieldDef,
|
|
14005
|
+
ALLOWED_CANVAS_FIELDS.nodePvDataSchemaField,
|
|
14006
|
+
`${nodePath2}.pv.dataSchema.${fieldName}`,
|
|
14007
|
+
issues
|
|
14008
|
+
);
|
|
13785
14009
|
}
|
|
13786
14010
|
}
|
|
13787
14011
|
}
|
|
13788
14012
|
if (nodePv.layout && typeof nodePv.layout === "object") {
|
|
13789
|
-
checkUnknownFields(
|
|
14013
|
+
checkUnknownFields(
|
|
14014
|
+
nodePv.layout,
|
|
14015
|
+
ALLOWED_CANVAS_FIELDS.nodePvLayout,
|
|
14016
|
+
`${nodePath2}.pv.layout`,
|
|
14017
|
+
issues
|
|
14018
|
+
);
|
|
13790
14019
|
}
|
|
13791
14020
|
if (Array.isArray(nodePv.actions)) {
|
|
13792
14021
|
nodePv.actions.forEach((action, actionIndex) => {
|
|
13793
14022
|
if (action && typeof action === "object") {
|
|
13794
|
-
checkUnknownFields(
|
|
14023
|
+
checkUnknownFields(
|
|
14024
|
+
action,
|
|
14025
|
+
ALLOWED_CANVAS_FIELDS.nodePvAction,
|
|
14026
|
+
`${nodePath2}.pv.actions[${actionIndex}]`,
|
|
14027
|
+
issues
|
|
14028
|
+
);
|
|
13795
14029
|
}
|
|
13796
14030
|
});
|
|
13797
14031
|
}
|
|
@@ -13829,7 +14063,11 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13829
14063
|
const nodeIds = new Set(c.nodes?.map((n) => n.id) || []);
|
|
13830
14064
|
c.edges.forEach((edge, index) => {
|
|
13831
14065
|
if (!edge || typeof edge !== "object") {
|
|
13832
|
-
issues.push({
|
|
14066
|
+
issues.push({
|
|
14067
|
+
type: "error",
|
|
14068
|
+
message: `Edge at index ${index} must be an object`,
|
|
14069
|
+
path: `edges[${index}]`
|
|
14070
|
+
});
|
|
13833
14071
|
return;
|
|
13834
14072
|
}
|
|
13835
14073
|
const e = edge;
|
|
@@ -13837,28 +14075,58 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13837
14075
|
const edgeLabel = e.id || index;
|
|
13838
14076
|
checkUnknownFields(e, ALLOWED_CANVAS_FIELDS.edge, edgePath, issues);
|
|
13839
14077
|
if (typeof e.id !== "string" || !e.id) {
|
|
13840
|
-
issues.push({
|
|
14078
|
+
issues.push({
|
|
14079
|
+
type: "error",
|
|
14080
|
+
message: `Edge at index ${index} must have a string "id"`,
|
|
14081
|
+
path: `${edgePath}.id`
|
|
14082
|
+
});
|
|
13841
14083
|
}
|
|
13842
14084
|
if (typeof e.fromNode !== "string") {
|
|
13843
|
-
issues.push({
|
|
14085
|
+
issues.push({
|
|
14086
|
+
type: "error",
|
|
14087
|
+
message: `Edge "${edgeLabel}" must have a string "fromNode"`,
|
|
14088
|
+
path: `${edgePath}.fromNode`
|
|
14089
|
+
});
|
|
13844
14090
|
} else if (!nodeIds.has(e.fromNode)) {
|
|
13845
|
-
issues.push({
|
|
14091
|
+
issues.push({
|
|
14092
|
+
type: "error",
|
|
14093
|
+
message: `Edge "${edgeLabel}" references unknown node "${e.fromNode}"`,
|
|
14094
|
+
path: `${edgePath}.fromNode`
|
|
14095
|
+
});
|
|
13846
14096
|
}
|
|
13847
14097
|
if (typeof e.toNode !== "string") {
|
|
13848
|
-
issues.push({
|
|
14098
|
+
issues.push({
|
|
14099
|
+
type: "error",
|
|
14100
|
+
message: `Edge "${edgeLabel}" must have a string "toNode"`,
|
|
14101
|
+
path: `${edgePath}.toNode`
|
|
14102
|
+
});
|
|
13849
14103
|
} else if (!nodeIds.has(e.toNode)) {
|
|
13850
|
-
issues.push({
|
|
14104
|
+
issues.push({
|
|
14105
|
+
type: "error",
|
|
14106
|
+
message: `Edge "${edgeLabel}" references unknown node "${e.toNode}"`,
|
|
14107
|
+
path: `${edgePath}.toNode`
|
|
14108
|
+
});
|
|
13851
14109
|
}
|
|
13852
14110
|
if (e.pv && typeof e.pv === "object") {
|
|
13853
14111
|
const edgePv = e.pv;
|
|
13854
14112
|
checkUnknownFields(edgePv, ALLOWED_CANVAS_FIELDS.edgePv, `${edgePath}.pv`, issues);
|
|
13855
14113
|
if (edgePv.animation && typeof edgePv.animation === "object") {
|
|
13856
|
-
checkUnknownFields(
|
|
14114
|
+
checkUnknownFields(
|
|
14115
|
+
edgePv.animation,
|
|
14116
|
+
ALLOWED_CANVAS_FIELDS.edgePvAnimation,
|
|
14117
|
+
`${edgePath}.pv.animation`,
|
|
14118
|
+
issues
|
|
14119
|
+
);
|
|
13857
14120
|
}
|
|
13858
14121
|
if (Array.isArray(edgePv.activatedBy)) {
|
|
13859
14122
|
edgePv.activatedBy.forEach((trigger, triggerIndex) => {
|
|
13860
14123
|
if (trigger && typeof trigger === "object") {
|
|
13861
|
-
checkUnknownFields(
|
|
14124
|
+
checkUnknownFields(
|
|
14125
|
+
trigger,
|
|
14126
|
+
ALLOWED_CANVAS_FIELDS.edgePvActivatedBy,
|
|
14127
|
+
`${edgePath}.pv.activatedBy[${triggerIndex}]`,
|
|
14128
|
+
issues
|
|
14129
|
+
);
|
|
13862
14130
|
}
|
|
13863
14131
|
});
|
|
13864
14132
|
}
|
|
@@ -13923,7 +14191,10 @@ function validateFile(filePath, library) {
|
|
|
13923
14191
|
}
|
|
13924
14192
|
function createValidateCommand() {
|
|
13925
14193
|
const command = new Command("validate");
|
|
13926
|
-
command.description("Validate .canvas configuration files").argument(
|
|
14194
|
+
command.description("Validate .canvas configuration files").argument(
|
|
14195
|
+
"[files...]",
|
|
14196
|
+
"Files or glob patterns to validate (defaults to .principal-views/*.canvas)"
|
|
14197
|
+
).option("-q, --quiet", "Only output errors").option("--json", "Output results as JSON").action(async (files, options) => {
|
|
13927
14198
|
try {
|
|
13928
14199
|
const patterns = files.length > 0 ? files : [".principal-views/*.canvas"];
|
|
13929
14200
|
const matchedFiles = await globby(patterns, {
|
|
@@ -13956,10 +14227,16 @@ function createValidateCommand() {
|
|
|
13956
14227
|
const validCount = allResults.filter((r) => r.isValid).length;
|
|
13957
14228
|
const invalidCount = allResults.length - validCount;
|
|
13958
14229
|
if (options.json) {
|
|
13959
|
-
console.log(
|
|
13960
|
-
|
|
13961
|
-
|
|
13962
|
-
|
|
14230
|
+
console.log(
|
|
14231
|
+
JSON.stringify(
|
|
14232
|
+
{
|
|
14233
|
+
files: allResults,
|
|
14234
|
+
summary: { total: allResults.length, valid: validCount, invalid: invalidCount }
|
|
14235
|
+
},
|
|
14236
|
+
null,
|
|
14237
|
+
2
|
|
14238
|
+
)
|
|
14239
|
+
);
|
|
13963
14240
|
} else {
|
|
13964
14241
|
if (!options.quiet) {
|
|
13965
14242
|
const fileCount = libraryResult ? `${results.length} canvas file(s) + library` : `${results.length} canvas file(s)`;
|
|
@@ -13994,7 +14271,9 @@ Validating ${fileCount}...
|
|
|
13994
14271
|
if (invalidCount === 0) {
|
|
13995
14272
|
console.log(source_default.green(`\u2713 All ${validCount} file(s) are valid`));
|
|
13996
14273
|
} else {
|
|
13997
|
-
console.log(
|
|
14274
|
+
console.log(
|
|
14275
|
+
source_default.red(`\u2717 ${invalidCount} of ${allResults.length} file(s) failed validation`)
|
|
14276
|
+
);
|
|
13998
14277
|
process.exit(1);
|
|
13999
14278
|
}
|
|
14000
14279
|
}
|
|
@@ -14109,7 +14388,9 @@ function createInitCommand() {
|
|
|
14109
14388
|
console.log(source_default.green(`Created directory: .principal-views/`));
|
|
14110
14389
|
}
|
|
14111
14390
|
if ((0, import_node_fs5.existsSync)(canvasFile) && !options.force) {
|
|
14112
|
-
console.log(
|
|
14391
|
+
console.log(
|
|
14392
|
+
source_default.yellow(`Canvas file already exists: .principal-views/${options.name}.canvas`)
|
|
14393
|
+
);
|
|
14113
14394
|
} else {
|
|
14114
14395
|
(0, import_node_fs5.writeFileSync)(canvasFile, JSON.stringify(TEMPLATE_CANVAS, null, 2));
|
|
14115
14396
|
console.log(source_default.green(`Created canvas file: .principal-views/${options.name}.canvas`));
|
|
@@ -14150,11 +14431,15 @@ edgeComponents: {}
|
|
|
14150
14431
|
if ((0, import_node_fs5.existsSync)(preCommitFile)) {
|
|
14151
14432
|
const existingContent = (0, import_node_fs5.readFileSync)(preCommitFile, "utf8");
|
|
14152
14433
|
if (existingContent.includes("principal-view-cli lint") || existingContent.includes("privu lint")) {
|
|
14153
|
-
console.log(
|
|
14434
|
+
console.log(
|
|
14435
|
+
source_default.yellow(`Husky pre-commit hook already includes principal view linting`)
|
|
14436
|
+
);
|
|
14154
14437
|
} else {
|
|
14155
14438
|
const updatedContent = existingContent.trimEnd() + "\n\n# Run principal view linting\nnpx @principal-ai/principal-view-cli lint --quiet\n";
|
|
14156
14439
|
(0, import_node_fs5.writeFileSync)(preCommitFile, updatedContent);
|
|
14157
|
-
console.log(
|
|
14440
|
+
console.log(
|
|
14441
|
+
source_default.green(`Updated Husky pre-commit hook with principal view linting`)
|
|
14442
|
+
);
|
|
14158
14443
|
huskySetup = true;
|
|
14159
14444
|
}
|
|
14160
14445
|
} else {
|
|
@@ -14184,8 +14469,16 @@ edgeComponents: {}
|
|
|
14184
14469
|
console.log(source_default.green(`Installed Husky and created pre-commit hook`));
|
|
14185
14470
|
huskySetup = true;
|
|
14186
14471
|
} catch (installError) {
|
|
14187
|
-
console.log(
|
|
14188
|
-
|
|
14472
|
+
console.log(
|
|
14473
|
+
source_default.yellow(
|
|
14474
|
+
`Could not install Husky automatically: ${installError.message}`
|
|
14475
|
+
)
|
|
14476
|
+
);
|
|
14477
|
+
console.log(
|
|
14478
|
+
source_default.dim(
|
|
14479
|
+
` You can install it manually: ${pm} add --dev husky && npx husky init`
|
|
14480
|
+
)
|
|
14481
|
+
);
|
|
14189
14482
|
}
|
|
14190
14483
|
}
|
|
14191
14484
|
}
|
|
@@ -14196,8 +14489,12 @@ edgeComponents: {}
|
|
|
14196
14489
|
console.log(source_default.bold("Setup complete!"));
|
|
14197
14490
|
console.log("");
|
|
14198
14491
|
console.log(source_default.bold("Files created:"));
|
|
14199
|
-
console.log(
|
|
14200
|
-
|
|
14492
|
+
console.log(
|
|
14493
|
+
` \u2022 ${source_default.cyan(".principal-views/library.yaml")} - Component library definitions`
|
|
14494
|
+
);
|
|
14495
|
+
console.log(
|
|
14496
|
+
` \u2022 ${source_default.cyan(`.principal-views/${options.name}.canvas`)} - Graph canvas file`
|
|
14497
|
+
);
|
|
14201
14498
|
if (options.lintConfig !== false) {
|
|
14202
14499
|
console.log(` \u2022 ${source_default.cyan(".privurc.yaml")} - Lint configuration`);
|
|
14203
14500
|
}
|
|
@@ -14207,7 +14504,9 @@ edgeComponents: {}
|
|
|
14207
14504
|
console.log("");
|
|
14208
14505
|
console.log(source_default.bold("Next steps:"));
|
|
14209
14506
|
console.log(` 1. Define components in ${source_default.cyan(".principal-views/library.yaml")}`);
|
|
14210
|
-
console.log(
|
|
14507
|
+
console.log(
|
|
14508
|
+
` 2. Build your graph in ${source_default.cyan(`.principal-views/${options.name}.canvas`)}`
|
|
14509
|
+
);
|
|
14211
14510
|
console.log(` 3. Run ${source_default.cyan("privu lint")} to validate your configuration`);
|
|
14212
14511
|
if (huskySetup) {
|
|
14213
14512
|
console.log(` 4. Commits will now automatically lint .principal-views files`);
|
|
@@ -14303,11 +14602,21 @@ with standard canvas tools like Obsidian.
|
|
|
14303
14602
|
${source_default.bold("Required Structure:")}
|
|
14304
14603
|
${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\u2510")}
|
|
14305
14604
|
${source_default.dim("\u2502")} { ${source_default.dim("\u2502")}
|
|
14306
|
-
${source_default.dim("\u2502")} ${source_default.green('"nodes"')}: [...], ${source_default.dim(
|
|
14307
|
-
|
|
14308
|
-
|
|
14309
|
-
${source_default.dim("\u2502")}
|
|
14310
|
-
|
|
14605
|
+
${source_default.dim("\u2502")} ${source_default.green('"nodes"')}: [...], ${source_default.dim(
|
|
14606
|
+
"// Required: array of nodes"
|
|
14607
|
+
)} ${source_default.dim("\u2502")}
|
|
14608
|
+
${source_default.dim("\u2502")} ${source_default.green('"edges"')}: [...], ${source_default.dim(
|
|
14609
|
+
"// Optional: array of edges"
|
|
14610
|
+
)} ${source_default.dim("\u2502")}
|
|
14611
|
+
${source_default.dim("\u2502")} ${source_default.green('"pv"')}: { ${source_default.dim(
|
|
14612
|
+
"// Required: PV extension"
|
|
14613
|
+
)} ${source_default.dim("\u2502")}
|
|
14614
|
+
${source_default.dim("\u2502")} ${source_default.yellow('"name"')}: "...", ${source_default.dim(
|
|
14615
|
+
"// Required: graph name"
|
|
14616
|
+
)} ${source_default.dim("\u2502")}
|
|
14617
|
+
${source_default.dim("\u2502")} ${source_default.yellow('"version"')}: "..." ${source_default.dim(
|
|
14618
|
+
"// Required: schema version"
|
|
14619
|
+
)} ${source_default.dim("\u2502")}
|
|
14311
14620
|
${source_default.dim("\u2502")} } ${source_default.dim("\u2502")}
|
|
14312
14621
|
${source_default.dim("\u2502")} } ${source_default.dim("\u2502")}
|
|
14313
14622
|
${source_default.dim("\u2514\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\u2518")}
|
|
@@ -14338,7 +14647,9 @@ ${source_default.bold("Standard Node Types:")}
|
|
|
14338
14647
|
Requires: ${source_default.dim("text")} (string)
|
|
14339
14648
|
|
|
14340
14649
|
${source_default.yellow("group")} Visual container for other nodes
|
|
14341
|
-
Optional: ${source_default.dim("label")}, ${source_default.dim("background")}, ${source_default.dim(
|
|
14650
|
+
Optional: ${source_default.dim("label")}, ${source_default.dim("background")}, ${source_default.dim(
|
|
14651
|
+
"backgroundStyle"
|
|
14652
|
+
)}
|
|
14342
14653
|
|
|
14343
14654
|
${source_default.yellow("file")} Reference to external file
|
|
14344
14655
|
Requires: ${source_default.dim("file")} (path string)
|
|
@@ -14409,7 +14720,9 @@ ${source_default.bold("Defining Edge Types (in canvas vv):")}
|
|
|
14409
14720
|
"version": "1.0.0",
|
|
14410
14721
|
${source_default.yellow('"edgeTypes"')}: {
|
|
14411
14722
|
"query": {
|
|
14412
|
-
${source_default.cyan('"style"')}: "solid", ${source_default.dim(
|
|
14723
|
+
${source_default.cyan('"style"')}: "solid", ${source_default.dim(
|
|
14724
|
+
"// solid, dashed, dotted, animated"
|
|
14725
|
+
)}
|
|
14413
14726
|
${source_default.cyan('"color"')}: "#64748b", ${source_default.dim("// Hex color")}
|
|
14414
14727
|
${source_default.cyan('"width"')}: 2, ${source_default.dim("// Line width in pixels")}
|
|
14415
14728
|
${source_default.cyan('"directed"')}: true, ${source_default.dim("// Show arrow")}
|
|
@@ -14463,7 +14776,9 @@ ${source_default.bold("Node-Level pv (for custom types):")}
|
|
|
14463
14776
|
${source_default.yellow('"nodeType"')}: "service", ${source_default.dim("// Required: Type identifier")}
|
|
14464
14777
|
${source_default.yellow('"shape"')}: "rectangle", ${source_default.dim("// Required: Visual shape")}
|
|
14465
14778
|
${source_default.cyan('"fill"')}: "#3b82f6", ${source_default.dim("// Optional: Fill color (hex)")}
|
|
14466
|
-
${source_default.cyan('"stroke"')}: "#1d4ed8", ${source_default.dim(
|
|
14779
|
+
${source_default.cyan('"stroke"')}: "#1d4ed8", ${source_default.dim(
|
|
14780
|
+
"// Optional: Border color (hex)"
|
|
14781
|
+
)}
|
|
14467
14782
|
${source_default.cyan('"icon"')}: "Server", ${source_default.dim("// Optional: Lucide icon name")}
|
|
14468
14783
|
${source_default.cyan('"sources"')}: ["src/**/*.ts"], ${source_default.dim("// Optional: Source patterns")}
|
|
14469
14784
|
${source_default.cyan('"states"')}: { ${source_default.dim("// Optional: State definitions")}
|
|
@@ -14705,7 +15020,9 @@ async function checkConfig(configPath, projectRoot) {
|
|
|
14705
15020
|
type: "warning",
|
|
14706
15021
|
configFile: relativePath,
|
|
14707
15022
|
nodeType: nodeTypeName,
|
|
14708
|
-
message: `Config may be stale: "${newestFile}" was modified ${formatTimeDiff(
|
|
15023
|
+
message: `Config may be stale: "${newestFile}" was modified ${formatTimeDiff(
|
|
15024
|
+
timeDiff
|
|
15025
|
+
)} after the config`,
|
|
14709
15026
|
details: `Pattern: ${pattern} (matched ${matchedFiles.length} file${matchedFiles.length > 1 ? "s" : ""})`
|
|
14710
15027
|
});
|
|
14711
15028
|
}
|
|
@@ -14729,7 +15046,9 @@ function createDoctorCommand() {
|
|
|
14729
15046
|
const vgcDir = (0, import_node_path8.resolve)(projectRoot, ".principal-views");
|
|
14730
15047
|
if (!(0, import_node_fs7.existsSync)(vgcDir)) {
|
|
14731
15048
|
if (options.json) {
|
|
14732
|
-
console.log(
|
|
15049
|
+
console.log(
|
|
15050
|
+
JSON.stringify({ error: "No .principal-views directory found", results: [] })
|
|
15051
|
+
);
|
|
14733
15052
|
} else {
|
|
14734
15053
|
console.log(source_default.yellow("No .principal-views directory found."));
|
|
14735
15054
|
console.log(source_default.dim('Run "privu init" to create a configuration.'));
|
|
@@ -14743,7 +15062,9 @@ function createDoctorCommand() {
|
|
|
14743
15062
|
});
|
|
14744
15063
|
if (configFiles.length === 0) {
|
|
14745
15064
|
if (options.json) {
|
|
14746
|
-
console.log(
|
|
15065
|
+
console.log(
|
|
15066
|
+
JSON.stringify({ error: "No config files found in .principal-views", results: [] })
|
|
15067
|
+
);
|
|
14747
15068
|
} else {
|
|
14748
15069
|
console.log(source_default.yellow("No configuration files found in .principal-views/"));
|
|
14749
15070
|
}
|
|
@@ -14803,7 +15124,9 @@ Checking ${results.length} configuration file(s)...
|
|
|
14803
15124
|
for (const result of results) {
|
|
14804
15125
|
const issues = filterIssues(result.issues);
|
|
14805
15126
|
if (issues.length === 0 && !options.quiet && !options.errorsOnly) {
|
|
14806
|
-
console.log(
|
|
15127
|
+
console.log(
|
|
15128
|
+
source_default.green(`\u2713 ${result.configFile}`) + source_default.dim(` (${result.configName})`)
|
|
15129
|
+
);
|
|
14807
15130
|
continue;
|
|
14808
15131
|
}
|
|
14809
15132
|
if (issues.length > 0) {
|
|
@@ -14923,7 +15246,9 @@ function initializeHusky(repoPath) {
|
|
|
14923
15246
|
}
|
|
14924
15247
|
console.log("\u2705 Husky installed and initialized");
|
|
14925
15248
|
} catch (error) {
|
|
14926
|
-
throw new Error(
|
|
15249
|
+
throw new Error(
|
|
15250
|
+
`Failed to initialize husky: ${error instanceof Error ? error.message : String(error)}`
|
|
15251
|
+
);
|
|
14927
15252
|
}
|
|
14928
15253
|
}
|
|
14929
15254
|
}
|
|
@@ -15055,7 +15380,9 @@ function createHooksCommand() {
|
|
|
15055
15380
|
console.log(source_default.bold("\nPrincipal View Hooks Status\n"));
|
|
15056
15381
|
console.log(`Repository: ${repoPath}`);
|
|
15057
15382
|
console.log(`Husky: ${source_default.green("installed")}`);
|
|
15058
|
-
console.log(
|
|
15383
|
+
console.log(
|
|
15384
|
+
`PV Hooks: ${hasHook ? source_default.green("configured") : source_default.yellow("not configured")}`
|
|
15385
|
+
);
|
|
15059
15386
|
if (hasHook) {
|
|
15060
15387
|
console.log("\nUse --remove to remove or --check to verify");
|
|
15061
15388
|
} else {
|
|
@@ -15079,7 +15406,10 @@ var TEMPLATE_CANVAS2 = {
|
|
|
15079
15406
|
};
|
|
15080
15407
|
function createCreateCommand() {
|
|
15081
15408
|
const command = new Command("create");
|
|
15082
|
-
command.description("Create a new canvas file in the .principal-views folder").requiredOption(
|
|
15409
|
+
command.description("Create a new canvas file in the .principal-views folder").requiredOption(
|
|
15410
|
+
"-n, --name <name>",
|
|
15411
|
+
'Name for the canvas file (e.g., "cache-sync-architecture")'
|
|
15412
|
+
).option("-f, --force", "Overwrite existing file").action(async (options) => {
|
|
15083
15413
|
try {
|
|
15084
15414
|
const vgcDir = (0, import_node_path10.join)(process.cwd(), ".principal-views");
|
|
15085
15415
|
const canvasFile = (0, import_node_path10.join)(vgcDir, `${options.name}.canvas`);
|
|
@@ -15088,7 +15418,9 @@ function createCreateCommand() {
|
|
|
15088
15418
|
console.log(source_default.green(`Created directory: .principal-views/`));
|
|
15089
15419
|
}
|
|
15090
15420
|
if ((0, import_node_fs9.existsSync)(canvasFile) && !options.force) {
|
|
15091
|
-
console.error(
|
|
15421
|
+
console.error(
|
|
15422
|
+
source_default.red(`Error: Canvas file already exists: .principal-views/${options.name}.canvas`)
|
|
15423
|
+
);
|
|
15092
15424
|
console.log(source_default.yellow(`Use ${source_default.cyan("--force")} to overwrite`));
|
|
15093
15425
|
process.exit(1);
|
|
15094
15426
|
}
|
|
@@ -15096,7 +15428,9 @@ function createCreateCommand() {
|
|
|
15096
15428
|
console.log(source_default.green(`\u2713 Created canvas file: .principal-views/${options.name}.canvas`));
|
|
15097
15429
|
console.log("");
|
|
15098
15430
|
console.log(source_default.bold("Next steps:"));
|
|
15099
|
-
console.log(
|
|
15431
|
+
console.log(
|
|
15432
|
+
` 1. Open ${source_default.cyan(`.principal-views/${options.name}.canvas`)} in your editor`
|
|
15433
|
+
);
|
|
15100
15434
|
console.log(` 2. Add nodes and edges to define your architecture`);
|
|
15101
15435
|
console.log(` 3. Run ${source_default.cyan("privu validate")} to check your configuration`);
|
|
15102
15436
|
console.log(` 4. Run ${source_default.cyan("privu doctor")} to verify source mappings`);
|
|
@@ -15883,6 +16217,18 @@ var validNodeTypes = {
|
|
|
15883
16217
|
}
|
|
15884
16218
|
for (const [typeId, nodeType] of Object.entries(configuration.nodeTypes)) {
|
|
15885
16219
|
const basePath = `nodeTypes.${typeId}`;
|
|
16220
|
+
if (!nodeType.description) {
|
|
16221
|
+
violations.push({
|
|
16222
|
+
ruleId: "valid-node-types",
|
|
16223
|
+
severity: "error",
|
|
16224
|
+
file: configPath,
|
|
16225
|
+
path: `${basePath}.description`,
|
|
16226
|
+
message: `Node type "${typeId}" is missing required "description" field`,
|
|
16227
|
+
impact: "Node type must have a description explaining its purpose",
|
|
16228
|
+
suggestion: "Add a description field explaining what this node type represents",
|
|
16229
|
+
fixable: false
|
|
16230
|
+
});
|
|
16231
|
+
}
|
|
15886
16232
|
if (!nodeType.shape) {
|
|
15887
16233
|
violations.push({
|
|
15888
16234
|
ruleId: "valid-node-types",
|
|
@@ -16285,6 +16631,7 @@ var ALLOWED_FIELDS = {
|
|
|
16285
16631
|
root: ["metadata", "nodeTypes", "edgeTypes", "allowedConnections", "validation", "display"],
|
|
16286
16632
|
metadata: ["name", "version", "description"],
|
|
16287
16633
|
nodeType: [
|
|
16634
|
+
"description",
|
|
16288
16635
|
"shape",
|
|
16289
16636
|
"icon",
|
|
16290
16637
|
"color",
|
|
@@ -17161,11 +17508,7 @@ function createDefaultRulesEngine() {
|
|
|
17161
17508
|
}
|
|
17162
17509
|
|
|
17163
17510
|
// src/commands/lint.ts
|
|
17164
|
-
var CONFIG_FILE_NAMES2 = [
|
|
17165
|
-
".privurc.yaml",
|
|
17166
|
-
".privurc.yml",
|
|
17167
|
-
".privurc.json"
|
|
17168
|
-
];
|
|
17511
|
+
var CONFIG_FILE_NAMES2 = [".privurc.yaml", ".privurc.yml", ".privurc.json"];
|
|
17169
17512
|
function findConfig(startDir) {
|
|
17170
17513
|
let currentDir = (0, import_node_path11.resolve)(startDir);
|
|
17171
17514
|
while (true) {
|
|
@@ -17321,7 +17664,10 @@ function formatJsonOutput(results) {
|
|
|
17321
17664
|
}
|
|
17322
17665
|
function createLintCommand() {
|
|
17323
17666
|
const command = new Command("lint");
|
|
17324
|
-
command.description("Lint graph configuration files").argument(
|
|
17667
|
+
command.description("Lint graph configuration files").argument(
|
|
17668
|
+
"[files...]",
|
|
17669
|
+
"Files or glob patterns to lint (defaults to .principal-views/**/*.yaml)"
|
|
17670
|
+
).option("-c, --config <path>", "Path to config file").option("--library <path>", "Path to component library file").option("-q, --quiet", "Only output errors").option("--json", "Output results as JSON").option("--rule <rules...>", "Only run specific rules").option("--ignore-rule <rules...>", "Skip specific rules").action(async (files, options) => {
|
|
17325
17671
|
try {
|
|
17326
17672
|
const cwd = process.cwd();
|
|
17327
17673
|
let privuConfig = getDefaultConfig();
|
|
@@ -17369,7 +17715,11 @@ function createLintCommand() {
|
|
|
17369
17715
|
} else if (privuConfig.include && privuConfig.include.length > 0) {
|
|
17370
17716
|
patterns = privuConfig.include;
|
|
17371
17717
|
} else {
|
|
17372
|
-
patterns = [
|
|
17718
|
+
patterns = [
|
|
17719
|
+
".principal-views/**/*.yaml",
|
|
17720
|
+
".principal-views/**/*.yml",
|
|
17721
|
+
".principal-views/**/*.json"
|
|
17722
|
+
];
|
|
17373
17723
|
}
|
|
17374
17724
|
const matchedFiles = await globby(patterns, {
|
|
17375
17725
|
ignore: privuConfig.exclude || ["**/node_modules/**"],
|
|
@@ -17384,9 +17734,16 @@ function createLintCommand() {
|
|
|
17384
17734
|
});
|
|
17385
17735
|
if (configFiles.length === 0) {
|
|
17386
17736
|
if (options.json) {
|
|
17387
|
-
console.log(
|
|
17737
|
+
console.log(
|
|
17738
|
+
JSON.stringify({
|
|
17739
|
+
files: [],
|
|
17740
|
+
summary: { totalFiles: 0, totalErrors: 0, totalWarnings: 0, totalFixable: 0 }
|
|
17741
|
+
})
|
|
17742
|
+
);
|
|
17388
17743
|
} else {
|
|
17389
|
-
console.log(
|
|
17744
|
+
console.log(
|
|
17745
|
+
source_default.yellow("No configuration files found matching the specified patterns.")
|
|
17746
|
+
);
|
|
17390
17747
|
console.log(source_default.dim(`Patterns searched: ${patterns.join(", ")}`));
|
|
17391
17748
|
}
|
|
17392
17749
|
return;
|
|
@@ -17408,14 +17765,16 @@ function createLintCommand() {
|
|
|
17408
17765
|
const loaded = loadGraphConfig(absolutePath);
|
|
17409
17766
|
if (!loaded) {
|
|
17410
17767
|
results.set(relativePath, {
|
|
17411
|
-
violations: [
|
|
17412
|
-
|
|
17413
|
-
|
|
17414
|
-
|
|
17415
|
-
|
|
17416
|
-
|
|
17417
|
-
|
|
17418
|
-
|
|
17768
|
+
violations: [
|
|
17769
|
+
{
|
|
17770
|
+
ruleId: "parse-error",
|
|
17771
|
+
severity: "error",
|
|
17772
|
+
file: relativePath,
|
|
17773
|
+
message: `Could not parse file: ${filePath}`,
|
|
17774
|
+
impact: "File cannot be validated",
|
|
17775
|
+
fixable: false
|
|
17776
|
+
}
|
|
17777
|
+
],
|
|
17419
17778
|
errorCount: 1,
|
|
17420
17779
|
warningCount: 0,
|
|
17421
17780
|
fixableCount: 0,
|