@principal-ai/principal-view-cli 0.1.19 → 0.1.21
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/hooks.js +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/schema.js +5 -2
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +270 -34
- package/dist/index.cjs +523 -101
- package/dist/index.cjs.map +3 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -13484,31 +13484,68 @@ 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
|
+
);
|
|
13493
|
+
validateIconName(comp.icon, `nodeComponents.${compId}.icon`, issues);
|
|
13488
13494
|
if (comp.size && typeof comp.size === "object") {
|
|
13489
|
-
checkUnknownFields(
|
|
13495
|
+
checkUnknownFields(
|
|
13496
|
+
comp.size,
|
|
13497
|
+
ALLOWED_LIBRARY_FIELDS.nodeComponentSize,
|
|
13498
|
+
`nodeComponents.${compId}.size`,
|
|
13499
|
+
issues
|
|
13500
|
+
);
|
|
13490
13501
|
}
|
|
13491
13502
|
if (comp.states && typeof comp.states === "object") {
|
|
13492
|
-
for (const [stateId, stateDef] of Object.entries(
|
|
13503
|
+
for (const [stateId, stateDef] of Object.entries(
|
|
13504
|
+
comp.states
|
|
13505
|
+
)) {
|
|
13493
13506
|
if (stateDef && typeof stateDef === "object") {
|
|
13494
|
-
checkUnknownFields(
|
|
13507
|
+
checkUnknownFields(
|
|
13508
|
+
stateDef,
|
|
13509
|
+
ALLOWED_LIBRARY_FIELDS.nodeComponentState,
|
|
13510
|
+
`nodeComponents.${compId}.states.${stateId}`,
|
|
13511
|
+
issues
|
|
13512
|
+
);
|
|
13513
|
+
const state = stateDef;
|
|
13514
|
+
validateIconName(state.icon, `nodeComponents.${compId}.states.${stateId}.icon`, issues);
|
|
13495
13515
|
}
|
|
13496
13516
|
}
|
|
13497
13517
|
}
|
|
13498
13518
|
if (comp.dataSchema && typeof comp.dataSchema === "object") {
|
|
13499
|
-
for (const [fieldName, fieldDef] of Object.entries(
|
|
13519
|
+
for (const [fieldName, fieldDef] of Object.entries(
|
|
13520
|
+
comp.dataSchema
|
|
13521
|
+
)) {
|
|
13500
13522
|
if (fieldDef && typeof fieldDef === "object") {
|
|
13501
|
-
checkUnknownFields(
|
|
13523
|
+
checkUnknownFields(
|
|
13524
|
+
fieldDef,
|
|
13525
|
+
ALLOWED_LIBRARY_FIELDS.nodeComponentDataSchemaField,
|
|
13526
|
+
`nodeComponents.${compId}.dataSchema.${fieldName}`,
|
|
13527
|
+
issues
|
|
13528
|
+
);
|
|
13502
13529
|
}
|
|
13503
13530
|
}
|
|
13504
13531
|
}
|
|
13505
13532
|
if (comp.layout && typeof comp.layout === "object") {
|
|
13506
|
-
checkUnknownFields(
|
|
13533
|
+
checkUnknownFields(
|
|
13534
|
+
comp.layout,
|
|
13535
|
+
ALLOWED_LIBRARY_FIELDS.nodeComponentLayout,
|
|
13536
|
+
`nodeComponents.${compId}.layout`,
|
|
13537
|
+
issues
|
|
13538
|
+
);
|
|
13507
13539
|
}
|
|
13508
13540
|
if (Array.isArray(comp.actions)) {
|
|
13509
13541
|
comp.actions.forEach((action, actionIndex) => {
|
|
13510
13542
|
if (action && typeof action === "object") {
|
|
13511
|
-
checkUnknownFields(
|
|
13543
|
+
checkUnknownFields(
|
|
13544
|
+
action,
|
|
13545
|
+
ALLOWED_LIBRARY_FIELDS.nodeComponentAction,
|
|
13546
|
+
`nodeComponents.${compId}.actions[${actionIndex}]`,
|
|
13547
|
+
issues
|
|
13548
|
+
);
|
|
13512
13549
|
}
|
|
13513
13550
|
});
|
|
13514
13551
|
}
|
|
@@ -13519,12 +13556,27 @@ function validateLibrary(library) {
|
|
|
13519
13556
|
for (const [compId, compDef] of Object.entries(lib.edgeComponents)) {
|
|
13520
13557
|
if (compDef && typeof compDef === "object") {
|
|
13521
13558
|
const comp = compDef;
|
|
13522
|
-
checkUnknownFields(
|
|
13559
|
+
checkUnknownFields(
|
|
13560
|
+
comp,
|
|
13561
|
+
ALLOWED_LIBRARY_FIELDS.edgeComponent,
|
|
13562
|
+
`edgeComponents.${compId}`,
|
|
13563
|
+
issues
|
|
13564
|
+
);
|
|
13523
13565
|
if (comp.animation && typeof comp.animation === "object") {
|
|
13524
|
-
checkUnknownFields(
|
|
13566
|
+
checkUnknownFields(
|
|
13567
|
+
comp.animation,
|
|
13568
|
+
ALLOWED_LIBRARY_FIELDS.edgeComponentAnimation,
|
|
13569
|
+
`edgeComponents.${compId}.animation`,
|
|
13570
|
+
issues
|
|
13571
|
+
);
|
|
13525
13572
|
}
|
|
13526
13573
|
if (comp.label && typeof comp.label === "object") {
|
|
13527
|
-
checkUnknownFields(
|
|
13574
|
+
checkUnknownFields(
|
|
13575
|
+
comp.label,
|
|
13576
|
+
ALLOWED_LIBRARY_FIELDS.edgeComponentLabel,
|
|
13577
|
+
`edgeComponents.${compId}.label`,
|
|
13578
|
+
issues
|
|
13579
|
+
);
|
|
13528
13580
|
}
|
|
13529
13581
|
}
|
|
13530
13582
|
}
|
|
@@ -13533,9 +13585,19 @@ function validateLibrary(library) {
|
|
|
13533
13585
|
lib.connectionRules.forEach((rule, ruleIndex) => {
|
|
13534
13586
|
if (rule && typeof rule === "object") {
|
|
13535
13587
|
const r = rule;
|
|
13536
|
-
checkUnknownFields(
|
|
13588
|
+
checkUnknownFields(
|
|
13589
|
+
r,
|
|
13590
|
+
ALLOWED_LIBRARY_FIELDS.connectionRule,
|
|
13591
|
+
`connectionRules[${ruleIndex}]`,
|
|
13592
|
+
issues
|
|
13593
|
+
);
|
|
13537
13594
|
if (r.constraints && typeof r.constraints === "object") {
|
|
13538
|
-
checkUnknownFields(
|
|
13595
|
+
checkUnknownFields(
|
|
13596
|
+
r.constraints,
|
|
13597
|
+
ALLOWED_LIBRARY_FIELDS.connectionRuleConstraints,
|
|
13598
|
+
`connectionRules[${ruleIndex}].constraints`,
|
|
13599
|
+
issues
|
|
13600
|
+
);
|
|
13539
13601
|
}
|
|
13540
13602
|
}
|
|
13541
13603
|
});
|
|
@@ -13544,15 +13606,60 @@ function validateLibrary(library) {
|
|
|
13544
13606
|
}
|
|
13545
13607
|
var STANDARD_CANVAS_TYPES = ["text", "group", "file", "link"];
|
|
13546
13608
|
var VALID_NODE_SHAPES = ["circle", "rectangle", "hexagon", "diamond", "custom"];
|
|
13609
|
+
function kebabToPascalCase(str2) {
|
|
13610
|
+
return str2.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
|
|
13611
|
+
}
|
|
13612
|
+
function isKebabCase(str2) {
|
|
13613
|
+
return str2.includes("-") && str2 === str2.toLowerCase();
|
|
13614
|
+
}
|
|
13615
|
+
function validateIconName(iconValue, path4, issues) {
|
|
13616
|
+
if (typeof iconValue !== "string" || !iconValue) {
|
|
13617
|
+
return;
|
|
13618
|
+
}
|
|
13619
|
+
if (isKebabCase(iconValue)) {
|
|
13620
|
+
const suggested = kebabToPascalCase(iconValue);
|
|
13621
|
+
issues.push({
|
|
13622
|
+
type: "error",
|
|
13623
|
+
message: `Invalid icon name "${iconValue}" - icons must be in PascalCase`,
|
|
13624
|
+
path: path4,
|
|
13625
|
+
suggestion: `Use "${suggested}" instead of "${iconValue}"`
|
|
13626
|
+
});
|
|
13627
|
+
return;
|
|
13628
|
+
}
|
|
13629
|
+
if (iconValue[0] === iconValue[0].toLowerCase() && iconValue[0] !== iconValue[0].toUpperCase()) {
|
|
13630
|
+
const suggested = iconValue.charAt(0).toUpperCase() + iconValue.slice(1);
|
|
13631
|
+
issues.push({
|
|
13632
|
+
type: "error",
|
|
13633
|
+
message: `Invalid icon name "${iconValue}" - icons must start with uppercase`,
|
|
13634
|
+
path: path4,
|
|
13635
|
+
suggestion: `Use "${suggested}" instead of "${iconValue}"`
|
|
13636
|
+
});
|
|
13637
|
+
}
|
|
13638
|
+
}
|
|
13547
13639
|
var ALLOWED_CANVAS_FIELDS = {
|
|
13548
13640
|
root: ["nodes", "edges", "pv"],
|
|
13549
13641
|
pv: ["version", "name", "description", "nodeTypes", "edgeTypes", "pathConfig", "display"],
|
|
13550
|
-
pvPathConfig: [
|
|
13642
|
+
pvPathConfig: [
|
|
13643
|
+
"projectRoot",
|
|
13644
|
+
"captureSource",
|
|
13645
|
+
"enableActionPatterns",
|
|
13646
|
+
"logLevel",
|
|
13647
|
+
"ignoreUnsourced"
|
|
13648
|
+
],
|
|
13551
13649
|
pvDisplay: ["layout", "theme", "animations"],
|
|
13552
13650
|
pvDisplayTheme: ["primary", "success", "warning", "danger", "info"],
|
|
13553
13651
|
pvDisplayAnimations: ["enabled", "speed"],
|
|
13554
13652
|
pvNodeType: ["label", "description", "color", "icon", "shape"],
|
|
13555
|
-
pvEdgeType: [
|
|
13653
|
+
pvEdgeType: [
|
|
13654
|
+
"label",
|
|
13655
|
+
"style",
|
|
13656
|
+
"color",
|
|
13657
|
+
"width",
|
|
13658
|
+
"directed",
|
|
13659
|
+
"animation",
|
|
13660
|
+
"labelConfig",
|
|
13661
|
+
"activatedBy"
|
|
13662
|
+
],
|
|
13556
13663
|
pvEdgeTypeAnimation: ["type", "duration", "color"],
|
|
13557
13664
|
pvEdgeTypeLabelConfig: ["field", "position"],
|
|
13558
13665
|
// Base node fields from JSON Canvas spec
|
|
@@ -13563,26 +13670,71 @@ var ALLOWED_CANVAS_FIELDS = {
|
|
|
13563
13670
|
nodeLink: ["url"],
|
|
13564
13671
|
nodeGroup: ["label", "background", "backgroundStyle"],
|
|
13565
13672
|
// Node pv extension
|
|
13566
|
-
nodePv: [
|
|
13673
|
+
nodePv: [
|
|
13674
|
+
"nodeType",
|
|
13675
|
+
"description",
|
|
13676
|
+
"shape",
|
|
13677
|
+
"icon",
|
|
13678
|
+
"fill",
|
|
13679
|
+
"stroke",
|
|
13680
|
+
"states",
|
|
13681
|
+
"sources",
|
|
13682
|
+
"actions",
|
|
13683
|
+
"dataSchema",
|
|
13684
|
+
"layout"
|
|
13685
|
+
],
|
|
13567
13686
|
nodePvState: ["color", "icon", "label"],
|
|
13568
13687
|
nodePvAction: ["pattern", "event", "state", "metadata", "triggerEdges"],
|
|
13569
13688
|
nodePvDataSchemaField: ["type", "required", "displayInLabel"],
|
|
13570
13689
|
nodePvLayout: ["layer", "cluster"],
|
|
13571
13690
|
// Edge fields
|
|
13572
|
-
edge: [
|
|
13691
|
+
edge: [
|
|
13692
|
+
"id",
|
|
13693
|
+
"fromNode",
|
|
13694
|
+
"toNode",
|
|
13695
|
+
"fromSide",
|
|
13696
|
+
"toSide",
|
|
13697
|
+
"fromEnd",
|
|
13698
|
+
"toEnd",
|
|
13699
|
+
"color",
|
|
13700
|
+
"label",
|
|
13701
|
+
"pv"
|
|
13702
|
+
],
|
|
13573
13703
|
edgePv: ["edgeType", "style", "width", "animation", "activatedBy"],
|
|
13574
13704
|
edgePvAnimation: ["type", "duration", "color"],
|
|
13575
13705
|
edgePvActivatedBy: ["action", "animation", "direction", "duration"]
|
|
13576
13706
|
};
|
|
13577
13707
|
var ALLOWED_LIBRARY_FIELDS = {
|
|
13578
13708
|
root: ["version", "name", "description", "nodeComponents", "edgeComponents", "connectionRules"],
|
|
13579
|
-
nodeComponent: [
|
|
13709
|
+
nodeComponent: [
|
|
13710
|
+
"description",
|
|
13711
|
+
"tags",
|
|
13712
|
+
"defaultLabel",
|
|
13713
|
+
"shape",
|
|
13714
|
+
"icon",
|
|
13715
|
+
"color",
|
|
13716
|
+
"size",
|
|
13717
|
+
"states",
|
|
13718
|
+
"sources",
|
|
13719
|
+
"actions",
|
|
13720
|
+
"dataSchema",
|
|
13721
|
+
"layout"
|
|
13722
|
+
],
|
|
13580
13723
|
nodeComponentSize: ["width", "height"],
|
|
13581
13724
|
nodeComponentState: ["color", "icon", "label"],
|
|
13582
13725
|
nodeComponentAction: ["pattern", "event", "state", "metadata", "triggerEdges"],
|
|
13583
13726
|
nodeComponentDataSchemaField: ["type", "required", "displayInLabel", "label", "displayInInfo"],
|
|
13584
13727
|
nodeComponentLayout: ["layer", "cluster"],
|
|
13585
|
-
edgeComponent: [
|
|
13728
|
+
edgeComponent: [
|
|
13729
|
+
"description",
|
|
13730
|
+
"tags",
|
|
13731
|
+
"style",
|
|
13732
|
+
"color",
|
|
13733
|
+
"width",
|
|
13734
|
+
"directed",
|
|
13735
|
+
"animation",
|
|
13736
|
+
"label"
|
|
13737
|
+
],
|
|
13586
13738
|
edgeComponentAnimation: ["type", "duration", "color"],
|
|
13587
13739
|
edgeComponentLabel: ["field", "position"],
|
|
13588
13740
|
connectionRule: ["from", "to", "via", "constraints"],
|
|
@@ -13661,23 +13813,45 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13661
13813
|
});
|
|
13662
13814
|
}
|
|
13663
13815
|
if (pv.pathConfig && typeof pv.pathConfig === "object") {
|
|
13664
|
-
checkUnknownFields(
|
|
13816
|
+
checkUnknownFields(
|
|
13817
|
+
pv.pathConfig,
|
|
13818
|
+
ALLOWED_CANVAS_FIELDS.pvPathConfig,
|
|
13819
|
+
"pv.pathConfig",
|
|
13820
|
+
issues
|
|
13821
|
+
);
|
|
13665
13822
|
}
|
|
13666
13823
|
if (pv.display && typeof pv.display === "object") {
|
|
13667
13824
|
const display = pv.display;
|
|
13668
13825
|
checkUnknownFields(display, ALLOWED_CANVAS_FIELDS.pvDisplay, "pv.display", issues);
|
|
13669
13826
|
if (display.theme && typeof display.theme === "object") {
|
|
13670
|
-
checkUnknownFields(
|
|
13827
|
+
checkUnknownFields(
|
|
13828
|
+
display.theme,
|
|
13829
|
+
ALLOWED_CANVAS_FIELDS.pvDisplayTheme,
|
|
13830
|
+
"pv.display.theme",
|
|
13831
|
+
issues
|
|
13832
|
+
);
|
|
13671
13833
|
}
|
|
13672
13834
|
if (display.animations && typeof display.animations === "object") {
|
|
13673
|
-
checkUnknownFields(
|
|
13835
|
+
checkUnknownFields(
|
|
13836
|
+
display.animations,
|
|
13837
|
+
ALLOWED_CANVAS_FIELDS.pvDisplayAnimations,
|
|
13838
|
+
"pv.display.animations",
|
|
13839
|
+
issues
|
|
13840
|
+
);
|
|
13674
13841
|
}
|
|
13675
13842
|
}
|
|
13676
13843
|
if (pv.nodeTypes && typeof pv.nodeTypes === "object") {
|
|
13677
13844
|
canvasNodeTypes = Object.keys(pv.nodeTypes);
|
|
13678
13845
|
for (const [typeId, typeDef] of Object.entries(pv.nodeTypes)) {
|
|
13679
13846
|
if (typeDef && typeof typeDef === "object") {
|
|
13680
|
-
checkUnknownFields(
|
|
13847
|
+
checkUnknownFields(
|
|
13848
|
+
typeDef,
|
|
13849
|
+
ALLOWED_CANVAS_FIELDS.pvNodeType,
|
|
13850
|
+
`pv.nodeTypes.${typeId}`,
|
|
13851
|
+
issues
|
|
13852
|
+
);
|
|
13853
|
+
const nodeType = typeDef;
|
|
13854
|
+
validateIconName(nodeType.icon, `pv.nodeTypes.${typeId}.icon`, issues);
|
|
13681
13855
|
}
|
|
13682
13856
|
}
|
|
13683
13857
|
}
|
|
@@ -13686,12 +13860,27 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13686
13860
|
for (const [typeId, typeDef] of Object.entries(pv.edgeTypes)) {
|
|
13687
13861
|
if (typeDef && typeof typeDef === "object") {
|
|
13688
13862
|
const edgeTypeDef = typeDef;
|
|
13689
|
-
checkUnknownFields(
|
|
13863
|
+
checkUnknownFields(
|
|
13864
|
+
edgeTypeDef,
|
|
13865
|
+
ALLOWED_CANVAS_FIELDS.pvEdgeType,
|
|
13866
|
+
`pv.edgeTypes.${typeId}`,
|
|
13867
|
+
issues
|
|
13868
|
+
);
|
|
13690
13869
|
if (edgeTypeDef.animation && typeof edgeTypeDef.animation === "object") {
|
|
13691
|
-
checkUnknownFields(
|
|
13870
|
+
checkUnknownFields(
|
|
13871
|
+
edgeTypeDef.animation,
|
|
13872
|
+
ALLOWED_CANVAS_FIELDS.pvEdgeTypeAnimation,
|
|
13873
|
+
`pv.edgeTypes.${typeId}.animation`,
|
|
13874
|
+
issues
|
|
13875
|
+
);
|
|
13692
13876
|
}
|
|
13693
13877
|
if (edgeTypeDef.labelConfig && typeof edgeTypeDef.labelConfig === "object") {
|
|
13694
|
-
checkUnknownFields(
|
|
13878
|
+
checkUnknownFields(
|
|
13879
|
+
edgeTypeDef.labelConfig,
|
|
13880
|
+
ALLOWED_CANVAS_FIELDS.pvEdgeTypeLabelConfig,
|
|
13881
|
+
`pv.edgeTypes.${typeId}.labelConfig`,
|
|
13882
|
+
issues
|
|
13883
|
+
);
|
|
13695
13884
|
}
|
|
13696
13885
|
}
|
|
13697
13886
|
}
|
|
@@ -13704,7 +13893,11 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13704
13893
|
} else {
|
|
13705
13894
|
c.nodes.forEach((node, index) => {
|
|
13706
13895
|
if (!node || typeof node !== "object") {
|
|
13707
|
-
issues.push({
|
|
13896
|
+
issues.push({
|
|
13897
|
+
type: "error",
|
|
13898
|
+
message: `Node at index ${index} must be an object`,
|
|
13899
|
+
path: `nodes[${index}]`
|
|
13900
|
+
});
|
|
13708
13901
|
return;
|
|
13709
13902
|
}
|
|
13710
13903
|
const n = node;
|
|
@@ -13723,31 +13916,83 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13723
13916
|
}
|
|
13724
13917
|
checkUnknownFields(n, allowedNodeFields, nodePath2, issues);
|
|
13725
13918
|
if (typeof n.id !== "string" || !n.id) {
|
|
13726
|
-
issues.push({
|
|
13919
|
+
issues.push({
|
|
13920
|
+
type: "error",
|
|
13921
|
+
message: `Node at index ${index} must have a string "id"`,
|
|
13922
|
+
path: `${nodePath2}.id`
|
|
13923
|
+
});
|
|
13727
13924
|
}
|
|
13728
13925
|
if (typeof n.type !== "string") {
|
|
13729
|
-
issues.push({
|
|
13926
|
+
issues.push({
|
|
13927
|
+
type: "error",
|
|
13928
|
+
message: `Node "${nodeLabel}" must have a string "type"`,
|
|
13929
|
+
path: `${nodePath2}.type`
|
|
13930
|
+
});
|
|
13730
13931
|
}
|
|
13731
13932
|
if (typeof n.x !== "number") {
|
|
13732
|
-
issues.push({
|
|
13933
|
+
issues.push({
|
|
13934
|
+
type: "error",
|
|
13935
|
+
message: `Node "${nodeLabel}" must have a numeric "x" position`,
|
|
13936
|
+
path: `${nodePath2}.x`
|
|
13937
|
+
});
|
|
13733
13938
|
}
|
|
13734
13939
|
if (typeof n.y !== "number") {
|
|
13735
|
-
issues.push({
|
|
13940
|
+
issues.push({
|
|
13941
|
+
type: "error",
|
|
13942
|
+
message: `Node "${nodeLabel}" must have a numeric "y" position`,
|
|
13943
|
+
path: `${nodePath2}.y`
|
|
13944
|
+
});
|
|
13736
13945
|
}
|
|
13737
13946
|
if (typeof n.width !== "number") {
|
|
13738
|
-
issues.push({
|
|
13947
|
+
issues.push({
|
|
13948
|
+
type: "error",
|
|
13949
|
+
message: `Node "${nodeLabel}" must have a numeric "width"`,
|
|
13950
|
+
path: `${nodePath2}.width`
|
|
13951
|
+
});
|
|
13739
13952
|
}
|
|
13740
13953
|
if (typeof n.height !== "number") {
|
|
13741
|
-
issues.push({
|
|
13954
|
+
issues.push({
|
|
13955
|
+
type: "error",
|
|
13956
|
+
message: `Node "${nodeLabel}" must have a numeric "height"`,
|
|
13957
|
+
path: `${nodePath2}.height`
|
|
13958
|
+
});
|
|
13959
|
+
}
|
|
13960
|
+
if (nodeType === "text" && (typeof n.text !== "string" || !n.text)) {
|
|
13961
|
+
issues.push({
|
|
13962
|
+
type: "error",
|
|
13963
|
+
message: `Node "${nodeLabel}" has type "text" but is missing required "text" field`,
|
|
13964
|
+
path: `${nodePath2}.text`,
|
|
13965
|
+
suggestion: 'Add a "text" field with markdown content, or change the node type'
|
|
13966
|
+
});
|
|
13967
|
+
}
|
|
13968
|
+
if (nodeType === "file" && (typeof n.file !== "string" || !n.file)) {
|
|
13969
|
+
issues.push({
|
|
13970
|
+
type: "error",
|
|
13971
|
+
message: `Node "${nodeLabel}" has type "file" but is missing required "file" field`,
|
|
13972
|
+
path: `${nodePath2}.file`,
|
|
13973
|
+
suggestion: 'Add a "file" field with a file path, or change the node type'
|
|
13974
|
+
});
|
|
13975
|
+
}
|
|
13976
|
+
if (nodeType === "link" && (typeof n.url !== "string" || !n.url)) {
|
|
13977
|
+
issues.push({
|
|
13978
|
+
type: "error",
|
|
13979
|
+
message: `Node "${nodeLabel}" has type "link" but is missing required "url" field`,
|
|
13980
|
+
path: `${nodePath2}.url`,
|
|
13981
|
+
suggestion: 'Add a "url" field with a URL, or change the node type'
|
|
13982
|
+
});
|
|
13742
13983
|
}
|
|
13743
|
-
const isStandardType = STANDARD_CANVAS_TYPES.includes(
|
|
13984
|
+
const isStandardType = STANDARD_CANVAS_TYPES.includes(
|
|
13985
|
+
nodeType
|
|
13986
|
+
);
|
|
13744
13987
|
if (!isStandardType) {
|
|
13745
13988
|
if (!n.pv || typeof n.pv !== "object") {
|
|
13746
13989
|
issues.push({
|
|
13747
13990
|
type: "error",
|
|
13748
13991
|
message: `Node "${n.id || index}" uses custom type "${nodeType}" but has no "pv" extension`,
|
|
13749
13992
|
path: `nodes[${index}].pv`,
|
|
13750
|
-
suggestion: `Use a standard type (${STANDARD_CANVAS_TYPES.join(
|
|
13993
|
+
suggestion: `Use a standard type (${STANDARD_CANVAS_TYPES.join(
|
|
13994
|
+
", "
|
|
13995
|
+
)}) or add pv.nodeType and pv.shape`
|
|
13751
13996
|
});
|
|
13752
13997
|
} else {
|
|
13753
13998
|
const nodePv = n.pv;
|
|
@@ -13771,27 +14016,54 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13771
14016
|
if (n.pv && typeof n.pv === "object") {
|
|
13772
14017
|
const nodePv = n.pv;
|
|
13773
14018
|
checkUnknownFields(nodePv, ALLOWED_CANVAS_FIELDS.nodePv, `${nodePath2}.pv`, issues);
|
|
14019
|
+
validateIconName(nodePv.icon, `${nodePath2}.pv.icon`, issues);
|
|
13774
14020
|
if (nodePv.states && typeof nodePv.states === "object") {
|
|
13775
|
-
for (const [stateId, stateDef] of Object.entries(
|
|
14021
|
+
for (const [stateId, stateDef] of Object.entries(
|
|
14022
|
+
nodePv.states
|
|
14023
|
+
)) {
|
|
13776
14024
|
if (stateDef && typeof stateDef === "object") {
|
|
13777
|
-
checkUnknownFields(
|
|
14025
|
+
checkUnknownFields(
|
|
14026
|
+
stateDef,
|
|
14027
|
+
ALLOWED_CANVAS_FIELDS.nodePvState,
|
|
14028
|
+
`${nodePath2}.pv.states.${stateId}`,
|
|
14029
|
+
issues
|
|
14030
|
+
);
|
|
14031
|
+
const state = stateDef;
|
|
14032
|
+
validateIconName(state.icon, `${nodePath2}.pv.states.${stateId}.icon`, issues);
|
|
13778
14033
|
}
|
|
13779
14034
|
}
|
|
13780
14035
|
}
|
|
13781
14036
|
if (nodePv.dataSchema && typeof nodePv.dataSchema === "object") {
|
|
13782
|
-
for (const [fieldName, fieldDef] of Object.entries(
|
|
14037
|
+
for (const [fieldName, fieldDef] of Object.entries(
|
|
14038
|
+
nodePv.dataSchema
|
|
14039
|
+
)) {
|
|
13783
14040
|
if (fieldDef && typeof fieldDef === "object") {
|
|
13784
|
-
checkUnknownFields(
|
|
14041
|
+
checkUnknownFields(
|
|
14042
|
+
fieldDef,
|
|
14043
|
+
ALLOWED_CANVAS_FIELDS.nodePvDataSchemaField,
|
|
14044
|
+
`${nodePath2}.pv.dataSchema.${fieldName}`,
|
|
14045
|
+
issues
|
|
14046
|
+
);
|
|
13785
14047
|
}
|
|
13786
14048
|
}
|
|
13787
14049
|
}
|
|
13788
14050
|
if (nodePv.layout && typeof nodePv.layout === "object") {
|
|
13789
|
-
checkUnknownFields(
|
|
14051
|
+
checkUnknownFields(
|
|
14052
|
+
nodePv.layout,
|
|
14053
|
+
ALLOWED_CANVAS_FIELDS.nodePvLayout,
|
|
14054
|
+
`${nodePath2}.pv.layout`,
|
|
14055
|
+
issues
|
|
14056
|
+
);
|
|
13790
14057
|
}
|
|
13791
14058
|
if (Array.isArray(nodePv.actions)) {
|
|
13792
14059
|
nodePv.actions.forEach((action, actionIndex) => {
|
|
13793
14060
|
if (action && typeof action === "object") {
|
|
13794
|
-
checkUnknownFields(
|
|
14061
|
+
checkUnknownFields(
|
|
14062
|
+
action,
|
|
14063
|
+
ALLOWED_CANVAS_FIELDS.nodePvAction,
|
|
14064
|
+
`${nodePath2}.pv.actions[${actionIndex}]`,
|
|
14065
|
+
issues
|
|
14066
|
+
);
|
|
13795
14067
|
}
|
|
13796
14068
|
});
|
|
13797
14069
|
}
|
|
@@ -13829,7 +14101,11 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13829
14101
|
const nodeIds = new Set(c.nodes?.map((n) => n.id) || []);
|
|
13830
14102
|
c.edges.forEach((edge, index) => {
|
|
13831
14103
|
if (!edge || typeof edge !== "object") {
|
|
13832
|
-
issues.push({
|
|
14104
|
+
issues.push({
|
|
14105
|
+
type: "error",
|
|
14106
|
+
message: `Edge at index ${index} must be an object`,
|
|
14107
|
+
path: `edges[${index}]`
|
|
14108
|
+
});
|
|
13833
14109
|
return;
|
|
13834
14110
|
}
|
|
13835
14111
|
const e = edge;
|
|
@@ -13837,28 +14113,89 @@ function validateCanvas(canvas, filePath, library) {
|
|
|
13837
14113
|
const edgeLabel = e.id || index;
|
|
13838
14114
|
checkUnknownFields(e, ALLOWED_CANVAS_FIELDS.edge, edgePath, issues);
|
|
13839
14115
|
if (typeof e.id !== "string" || !e.id) {
|
|
13840
|
-
issues.push({
|
|
14116
|
+
issues.push({
|
|
14117
|
+
type: "error",
|
|
14118
|
+
message: `Edge at index ${index} must have a string "id"`,
|
|
14119
|
+
path: `${edgePath}.id`
|
|
14120
|
+
});
|
|
13841
14121
|
}
|
|
13842
14122
|
if (typeof e.fromNode !== "string") {
|
|
13843
|
-
issues.push({
|
|
14123
|
+
issues.push({
|
|
14124
|
+
type: "error",
|
|
14125
|
+
message: `Edge "${edgeLabel}" must have a string "fromNode"`,
|
|
14126
|
+
path: `${edgePath}.fromNode`
|
|
14127
|
+
});
|
|
13844
14128
|
} else if (!nodeIds.has(e.fromNode)) {
|
|
13845
|
-
issues.push({
|
|
14129
|
+
issues.push({
|
|
14130
|
+
type: "error",
|
|
14131
|
+
message: `Edge "${edgeLabel}" references unknown node "${e.fromNode}"`,
|
|
14132
|
+
path: `${edgePath}.fromNode`
|
|
14133
|
+
});
|
|
13846
14134
|
}
|
|
13847
14135
|
if (typeof e.toNode !== "string") {
|
|
13848
|
-
issues.push({
|
|
14136
|
+
issues.push({
|
|
14137
|
+
type: "error",
|
|
14138
|
+
message: `Edge "${edgeLabel}" must have a string "toNode"`,
|
|
14139
|
+
path: `${edgePath}.toNode`
|
|
14140
|
+
});
|
|
13849
14141
|
} else if (!nodeIds.has(e.toNode)) {
|
|
13850
|
-
issues.push({
|
|
14142
|
+
issues.push({
|
|
14143
|
+
type: "error",
|
|
14144
|
+
message: `Edge "${edgeLabel}" references unknown node "${e.toNode}"`,
|
|
14145
|
+
path: `${edgePath}.toNode`
|
|
14146
|
+
});
|
|
14147
|
+
}
|
|
14148
|
+
const VALID_SIDES = ["top", "right", "bottom", "left"];
|
|
14149
|
+
if (typeof e.fromSide !== "string") {
|
|
14150
|
+
issues.push({
|
|
14151
|
+
type: "error",
|
|
14152
|
+
message: `Edge "${edgeLabel}" must have a "fromSide" field`,
|
|
14153
|
+
path: `${edgePath}.fromSide`,
|
|
14154
|
+
suggestion: `Specify which side of the source node the edge starts from: ${VALID_SIDES.join(", ")}`
|
|
14155
|
+
});
|
|
14156
|
+
} else if (!VALID_SIDES.includes(e.fromSide)) {
|
|
14157
|
+
issues.push({
|
|
14158
|
+
type: "error",
|
|
14159
|
+
message: `Edge "${edgeLabel}" has invalid fromSide "${e.fromSide}"`,
|
|
14160
|
+
path: `${edgePath}.fromSide`,
|
|
14161
|
+
suggestion: `Valid values: ${VALID_SIDES.join(", ")}`
|
|
14162
|
+
});
|
|
14163
|
+
}
|
|
14164
|
+
if (typeof e.toSide !== "string") {
|
|
14165
|
+
issues.push({
|
|
14166
|
+
type: "error",
|
|
14167
|
+
message: `Edge "${edgeLabel}" must have a "toSide" field`,
|
|
14168
|
+
path: `${edgePath}.toSide`,
|
|
14169
|
+
suggestion: `Specify which side of the target node the edge connects to: ${VALID_SIDES.join(", ")}`
|
|
14170
|
+
});
|
|
14171
|
+
} else if (!VALID_SIDES.includes(e.toSide)) {
|
|
14172
|
+
issues.push({
|
|
14173
|
+
type: "error",
|
|
14174
|
+
message: `Edge "${edgeLabel}" has invalid toSide "${e.toSide}"`,
|
|
14175
|
+
path: `${edgePath}.toSide`,
|
|
14176
|
+
suggestion: `Valid values: ${VALID_SIDES.join(", ")}`
|
|
14177
|
+
});
|
|
13851
14178
|
}
|
|
13852
14179
|
if (e.pv && typeof e.pv === "object") {
|
|
13853
14180
|
const edgePv = e.pv;
|
|
13854
14181
|
checkUnknownFields(edgePv, ALLOWED_CANVAS_FIELDS.edgePv, `${edgePath}.pv`, issues);
|
|
13855
14182
|
if (edgePv.animation && typeof edgePv.animation === "object") {
|
|
13856
|
-
checkUnknownFields(
|
|
14183
|
+
checkUnknownFields(
|
|
14184
|
+
edgePv.animation,
|
|
14185
|
+
ALLOWED_CANVAS_FIELDS.edgePvAnimation,
|
|
14186
|
+
`${edgePath}.pv.animation`,
|
|
14187
|
+
issues
|
|
14188
|
+
);
|
|
13857
14189
|
}
|
|
13858
14190
|
if (Array.isArray(edgePv.activatedBy)) {
|
|
13859
14191
|
edgePv.activatedBy.forEach((trigger, triggerIndex) => {
|
|
13860
14192
|
if (trigger && typeof trigger === "object") {
|
|
13861
|
-
checkUnknownFields(
|
|
14193
|
+
checkUnknownFields(
|
|
14194
|
+
trigger,
|
|
14195
|
+
ALLOWED_CANVAS_FIELDS.edgePvActivatedBy,
|
|
14196
|
+
`${edgePath}.pv.activatedBy[${triggerIndex}]`,
|
|
14197
|
+
issues
|
|
14198
|
+
);
|
|
13862
14199
|
}
|
|
13863
14200
|
});
|
|
13864
14201
|
}
|
|
@@ -13923,7 +14260,10 @@ function validateFile(filePath, library) {
|
|
|
13923
14260
|
}
|
|
13924
14261
|
function createValidateCommand() {
|
|
13925
14262
|
const command = new Command("validate");
|
|
13926
|
-
command.description("Validate .canvas configuration files").argument(
|
|
14263
|
+
command.description("Validate .canvas configuration files").argument(
|
|
14264
|
+
"[files...]",
|
|
14265
|
+
"Files or glob patterns to validate (defaults to .principal-views/*.canvas)"
|
|
14266
|
+
).option("-q, --quiet", "Only output errors").option("--json", "Output results as JSON").action(async (files, options) => {
|
|
13927
14267
|
try {
|
|
13928
14268
|
const patterns = files.length > 0 ? files : [".principal-views/*.canvas"];
|
|
13929
14269
|
const matchedFiles = await globby(patterns, {
|
|
@@ -13956,10 +14296,16 @@ function createValidateCommand() {
|
|
|
13956
14296
|
const validCount = allResults.filter((r) => r.isValid).length;
|
|
13957
14297
|
const invalidCount = allResults.length - validCount;
|
|
13958
14298
|
if (options.json) {
|
|
13959
|
-
console.log(
|
|
13960
|
-
|
|
13961
|
-
|
|
13962
|
-
|
|
14299
|
+
console.log(
|
|
14300
|
+
JSON.stringify(
|
|
14301
|
+
{
|
|
14302
|
+
files: allResults,
|
|
14303
|
+
summary: { total: allResults.length, valid: validCount, invalid: invalidCount }
|
|
14304
|
+
},
|
|
14305
|
+
null,
|
|
14306
|
+
2
|
|
14307
|
+
)
|
|
14308
|
+
);
|
|
13963
14309
|
} else {
|
|
13964
14310
|
if (!options.quiet) {
|
|
13965
14311
|
const fileCount = libraryResult ? `${results.length} canvas file(s) + library` : `${results.length} canvas file(s)`;
|
|
@@ -13994,7 +14340,9 @@ Validating ${fileCount}...
|
|
|
13994
14340
|
if (invalidCount === 0) {
|
|
13995
14341
|
console.log(source_default.green(`\u2713 All ${validCount} file(s) are valid`));
|
|
13996
14342
|
} else {
|
|
13997
|
-
console.log(
|
|
14343
|
+
console.log(
|
|
14344
|
+
source_default.red(`\u2717 ${invalidCount} of ${allResults.length} file(s) failed validation`)
|
|
14345
|
+
);
|
|
13998
14346
|
process.exit(1);
|
|
13999
14347
|
}
|
|
14000
14348
|
}
|
|
@@ -14109,7 +14457,9 @@ function createInitCommand() {
|
|
|
14109
14457
|
console.log(source_default.green(`Created directory: .principal-views/`));
|
|
14110
14458
|
}
|
|
14111
14459
|
if ((0, import_node_fs5.existsSync)(canvasFile) && !options.force) {
|
|
14112
|
-
console.log(
|
|
14460
|
+
console.log(
|
|
14461
|
+
source_default.yellow(`Canvas file already exists: .principal-views/${options.name}.canvas`)
|
|
14462
|
+
);
|
|
14113
14463
|
} else {
|
|
14114
14464
|
(0, import_node_fs5.writeFileSync)(canvasFile, JSON.stringify(TEMPLATE_CANVAS, null, 2));
|
|
14115
14465
|
console.log(source_default.green(`Created canvas file: .principal-views/${options.name}.canvas`));
|
|
@@ -14150,11 +14500,15 @@ edgeComponents: {}
|
|
|
14150
14500
|
if ((0, import_node_fs5.existsSync)(preCommitFile)) {
|
|
14151
14501
|
const existingContent = (0, import_node_fs5.readFileSync)(preCommitFile, "utf8");
|
|
14152
14502
|
if (existingContent.includes("principal-view-cli lint") || existingContent.includes("privu lint")) {
|
|
14153
|
-
console.log(
|
|
14503
|
+
console.log(
|
|
14504
|
+
source_default.yellow(`Husky pre-commit hook already includes principal view linting`)
|
|
14505
|
+
);
|
|
14154
14506
|
} else {
|
|
14155
14507
|
const updatedContent = existingContent.trimEnd() + "\n\n# Run principal view linting\nnpx @principal-ai/principal-view-cli lint --quiet\n";
|
|
14156
14508
|
(0, import_node_fs5.writeFileSync)(preCommitFile, updatedContent);
|
|
14157
|
-
console.log(
|
|
14509
|
+
console.log(
|
|
14510
|
+
source_default.green(`Updated Husky pre-commit hook with principal view linting`)
|
|
14511
|
+
);
|
|
14158
14512
|
huskySetup = true;
|
|
14159
14513
|
}
|
|
14160
14514
|
} else {
|
|
@@ -14184,8 +14538,16 @@ edgeComponents: {}
|
|
|
14184
14538
|
console.log(source_default.green(`Installed Husky and created pre-commit hook`));
|
|
14185
14539
|
huskySetup = true;
|
|
14186
14540
|
} catch (installError) {
|
|
14187
|
-
console.log(
|
|
14188
|
-
|
|
14541
|
+
console.log(
|
|
14542
|
+
source_default.yellow(
|
|
14543
|
+
`Could not install Husky automatically: ${installError.message}`
|
|
14544
|
+
)
|
|
14545
|
+
);
|
|
14546
|
+
console.log(
|
|
14547
|
+
source_default.dim(
|
|
14548
|
+
` You can install it manually: ${pm} add --dev husky && npx husky init`
|
|
14549
|
+
)
|
|
14550
|
+
);
|
|
14189
14551
|
}
|
|
14190
14552
|
}
|
|
14191
14553
|
}
|
|
@@ -14196,8 +14558,12 @@ edgeComponents: {}
|
|
|
14196
14558
|
console.log(source_default.bold("Setup complete!"));
|
|
14197
14559
|
console.log("");
|
|
14198
14560
|
console.log(source_default.bold("Files created:"));
|
|
14199
|
-
console.log(
|
|
14200
|
-
|
|
14561
|
+
console.log(
|
|
14562
|
+
` \u2022 ${source_default.cyan(".principal-views/library.yaml")} - Component library definitions`
|
|
14563
|
+
);
|
|
14564
|
+
console.log(
|
|
14565
|
+
` \u2022 ${source_default.cyan(`.principal-views/${options.name}.canvas`)} - Graph canvas file`
|
|
14566
|
+
);
|
|
14201
14567
|
if (options.lintConfig !== false) {
|
|
14202
14568
|
console.log(` \u2022 ${source_default.cyan(".privurc.yaml")} - Lint configuration`);
|
|
14203
14569
|
}
|
|
@@ -14207,7 +14573,9 @@ edgeComponents: {}
|
|
|
14207
14573
|
console.log("");
|
|
14208
14574
|
console.log(source_default.bold("Next steps:"));
|
|
14209
14575
|
console.log(` 1. Define components in ${source_default.cyan(".principal-views/library.yaml")}`);
|
|
14210
|
-
console.log(
|
|
14576
|
+
console.log(
|
|
14577
|
+
` 2. Build your graph in ${source_default.cyan(`.principal-views/${options.name}.canvas`)}`
|
|
14578
|
+
);
|
|
14211
14579
|
console.log(` 3. Run ${source_default.cyan("privu lint")} to validate your configuration`);
|
|
14212
14580
|
if (huskySetup) {
|
|
14213
14581
|
console.log(` 4. Commits will now automatically lint .principal-views files`);
|
|
@@ -14303,11 +14671,21 @@ with standard canvas tools like Obsidian.
|
|
|
14303
14671
|
${source_default.bold("Required Structure:")}
|
|
14304
14672
|
${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
14673
|
${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
|
-
|
|
14674
|
+
${source_default.dim("\u2502")} ${source_default.green('"nodes"')}: [...], ${source_default.dim(
|
|
14675
|
+
"// Required: array of nodes"
|
|
14676
|
+
)} ${source_default.dim("\u2502")}
|
|
14677
|
+
${source_default.dim("\u2502")} ${source_default.green('"edges"')}: [...], ${source_default.dim(
|
|
14678
|
+
"// Optional: array of edges"
|
|
14679
|
+
)} ${source_default.dim("\u2502")}
|
|
14680
|
+
${source_default.dim("\u2502")} ${source_default.green('"pv"')}: { ${source_default.dim(
|
|
14681
|
+
"// Required: PV extension"
|
|
14682
|
+
)} ${source_default.dim("\u2502")}
|
|
14683
|
+
${source_default.dim("\u2502")} ${source_default.yellow('"name"')}: "...", ${source_default.dim(
|
|
14684
|
+
"// Required: graph name"
|
|
14685
|
+
)} ${source_default.dim("\u2502")}
|
|
14686
|
+
${source_default.dim("\u2502")} ${source_default.yellow('"version"')}: "..." ${source_default.dim(
|
|
14687
|
+
"// Required: schema version"
|
|
14688
|
+
)} ${source_default.dim("\u2502")}
|
|
14311
14689
|
${source_default.dim("\u2502")} } ${source_default.dim("\u2502")}
|
|
14312
14690
|
${source_default.dim("\u2502")} } ${source_default.dim("\u2502")}
|
|
14313
14691
|
${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 +14716,9 @@ ${source_default.bold("Standard Node Types:")}
|
|
|
14338
14716
|
Requires: ${source_default.dim("text")} (string)
|
|
14339
14717
|
|
|
14340
14718
|
${source_default.yellow("group")} Visual container for other nodes
|
|
14341
|
-
Optional: ${source_default.dim("label")}, ${source_default.dim("background")}, ${source_default.dim(
|
|
14719
|
+
Optional: ${source_default.dim("label")}, ${source_default.dim("background")}, ${source_default.dim(
|
|
14720
|
+
"backgroundStyle"
|
|
14721
|
+
)}
|
|
14342
14722
|
|
|
14343
14723
|
${source_default.yellow("file")} Reference to external file
|
|
14344
14724
|
Requires: ${source_default.dim("file")} (path string)
|
|
@@ -14384,10 +14764,10 @@ ${source_default.bold("Required Fields:")}
|
|
|
14384
14764
|
${source_default.green("id")} ${source_default.dim("string")} Unique identifier
|
|
14385
14765
|
${source_default.green("fromNode")} ${source_default.dim("string")} Source node ID
|
|
14386
14766
|
${source_default.green("toNode")} ${source_default.dim("string")} Target node ID
|
|
14387
|
-
|
|
14388
|
-
${source_default.bold("Optional Fields:")}
|
|
14389
14767
|
${source_default.green("fromSide")} ${source_default.dim("string")} Side of source: top, right, bottom, left
|
|
14390
14768
|
${source_default.green("toSide")} ${source_default.dim("string")} Side of target: top, right, bottom, left
|
|
14769
|
+
|
|
14770
|
+
${source_default.bold("Optional Fields:")}
|
|
14391
14771
|
${source_default.green("fromEnd")} ${source_default.dim("string")} Source endpoint: none, arrow
|
|
14392
14772
|
${source_default.green("toEnd")} ${source_default.dim("string")} Target endpoint: none, arrow (default)
|
|
14393
14773
|
${source_default.green("color")} ${source_default.dim("string")} Edge color (hex or preset)
|
|
@@ -14397,6 +14777,7 @@ ${source_default.bold("PV Edge Extension:")}
|
|
|
14397
14777
|
${source_default.dim("{")}
|
|
14398
14778
|
${source_default.green('"id"')}: "edge-1",
|
|
14399
14779
|
${source_default.green('"fromNode"')}: "api", ${source_default.green('"toNode"')}: "db",
|
|
14780
|
+
${source_default.green('"fromSide"')}: "right", ${source_default.green('"toSide"')}: "left",
|
|
14400
14781
|
${source_default.green('"pv"')}: {
|
|
14401
14782
|
${source_default.yellow('"edgeType"')}: "query" ${source_default.dim("// Must be defined in vv.edgeTypes")}
|
|
14402
14783
|
}
|
|
@@ -14409,7 +14790,9 @@ ${source_default.bold("Defining Edge Types (in canvas vv):")}
|
|
|
14409
14790
|
"version": "1.0.0",
|
|
14410
14791
|
${source_default.yellow('"edgeTypes"')}: {
|
|
14411
14792
|
"query": {
|
|
14412
|
-
${source_default.cyan('"style"')}: "solid", ${source_default.dim(
|
|
14793
|
+
${source_default.cyan('"style"')}: "solid", ${source_default.dim(
|
|
14794
|
+
"// solid, dashed, dotted, animated"
|
|
14795
|
+
)}
|
|
14413
14796
|
${source_default.cyan('"color"')}: "#64748b", ${source_default.dim("// Hex color")}
|
|
14414
14797
|
${source_default.cyan('"width"')}: 2, ${source_default.dim("// Line width in pixels")}
|
|
14415
14798
|
${source_default.cyan('"directed"')}: true, ${source_default.dim("// Show arrow")}
|
|
@@ -14463,7 +14846,9 @@ ${source_default.bold("Node-Level pv (for custom types):")}
|
|
|
14463
14846
|
${source_default.yellow('"nodeType"')}: "service", ${source_default.dim("// Required: Type identifier")}
|
|
14464
14847
|
${source_default.yellow('"shape"')}: "rectangle", ${source_default.dim("// Required: Visual shape")}
|
|
14465
14848
|
${source_default.cyan('"fill"')}: "#3b82f6", ${source_default.dim("// Optional: Fill color (hex)")}
|
|
14466
|
-
${source_default.cyan('"stroke"')}: "#1d4ed8", ${source_default.dim(
|
|
14849
|
+
${source_default.cyan('"stroke"')}: "#1d4ed8", ${source_default.dim(
|
|
14850
|
+
"// Optional: Border color (hex)"
|
|
14851
|
+
)}
|
|
14467
14852
|
${source_default.cyan('"icon"')}: "Server", ${source_default.dim("// Optional: Lucide icon name")}
|
|
14468
14853
|
${source_default.cyan('"sources"')}: ["src/**/*.ts"], ${source_default.dim("// Optional: Source patterns")}
|
|
14469
14854
|
${source_default.cyan('"states"')}: { ${source_default.dim("// Optional: State definitions")}
|
|
@@ -14574,6 +14959,8 @@ ${source_default.dim("\u2500".repeat(50))}
|
|
|
14574
14959
|
"id": "api-to-db",
|
|
14575
14960
|
"fromNode": "api",
|
|
14576
14961
|
"toNode": "db",
|
|
14962
|
+
"fromSide": "right",
|
|
14963
|
+
"toSide": "left",
|
|
14577
14964
|
"pv": { "edgeType": "query" }
|
|
14578
14965
|
}
|
|
14579
14966
|
],
|
|
@@ -14705,7 +15092,9 @@ async function checkConfig(configPath, projectRoot) {
|
|
|
14705
15092
|
type: "warning",
|
|
14706
15093
|
configFile: relativePath,
|
|
14707
15094
|
nodeType: nodeTypeName,
|
|
14708
|
-
message: `Config may be stale: "${newestFile}" was modified ${formatTimeDiff(
|
|
15095
|
+
message: `Config may be stale: "${newestFile}" was modified ${formatTimeDiff(
|
|
15096
|
+
timeDiff
|
|
15097
|
+
)} after the config`,
|
|
14709
15098
|
details: `Pattern: ${pattern} (matched ${matchedFiles.length} file${matchedFiles.length > 1 ? "s" : ""})`
|
|
14710
15099
|
});
|
|
14711
15100
|
}
|
|
@@ -14729,7 +15118,9 @@ function createDoctorCommand() {
|
|
|
14729
15118
|
const vgcDir = (0, import_node_path8.resolve)(projectRoot, ".principal-views");
|
|
14730
15119
|
if (!(0, import_node_fs7.existsSync)(vgcDir)) {
|
|
14731
15120
|
if (options.json) {
|
|
14732
|
-
console.log(
|
|
15121
|
+
console.log(
|
|
15122
|
+
JSON.stringify({ error: "No .principal-views directory found", results: [] })
|
|
15123
|
+
);
|
|
14733
15124
|
} else {
|
|
14734
15125
|
console.log(source_default.yellow("No .principal-views directory found."));
|
|
14735
15126
|
console.log(source_default.dim('Run "privu init" to create a configuration.'));
|
|
@@ -14743,7 +15134,9 @@ function createDoctorCommand() {
|
|
|
14743
15134
|
});
|
|
14744
15135
|
if (configFiles.length === 0) {
|
|
14745
15136
|
if (options.json) {
|
|
14746
|
-
console.log(
|
|
15137
|
+
console.log(
|
|
15138
|
+
JSON.stringify({ error: "No config files found in .principal-views", results: [] })
|
|
15139
|
+
);
|
|
14747
15140
|
} else {
|
|
14748
15141
|
console.log(source_default.yellow("No configuration files found in .principal-views/"));
|
|
14749
15142
|
}
|
|
@@ -14803,7 +15196,9 @@ Checking ${results.length} configuration file(s)...
|
|
|
14803
15196
|
for (const result of results) {
|
|
14804
15197
|
const issues = filterIssues(result.issues);
|
|
14805
15198
|
if (issues.length === 0 && !options.quiet && !options.errorsOnly) {
|
|
14806
|
-
console.log(
|
|
15199
|
+
console.log(
|
|
15200
|
+
source_default.green(`\u2713 ${result.configFile}`) + source_default.dim(` (${result.configName})`)
|
|
15201
|
+
);
|
|
14807
15202
|
continue;
|
|
14808
15203
|
}
|
|
14809
15204
|
if (issues.length > 0) {
|
|
@@ -14923,7 +15318,9 @@ function initializeHusky(repoPath) {
|
|
|
14923
15318
|
}
|
|
14924
15319
|
console.log("\u2705 Husky installed and initialized");
|
|
14925
15320
|
} catch (error) {
|
|
14926
|
-
throw new Error(
|
|
15321
|
+
throw new Error(
|
|
15322
|
+
`Failed to initialize husky: ${error instanceof Error ? error.message : String(error)}`
|
|
15323
|
+
);
|
|
14927
15324
|
}
|
|
14928
15325
|
}
|
|
14929
15326
|
}
|
|
@@ -14939,7 +15336,7 @@ function addVVHook(repoPath) {
|
|
|
14939
15336
|
const hookPath = (0, import_node_path9.join)(repoPath, HUSKY_DIR, PRE_COMMIT_HOOK);
|
|
14940
15337
|
const vvContent = getVVHookContent();
|
|
14941
15338
|
if ((0, import_node_fs8.existsSync)(hookPath)) {
|
|
14942
|
-
|
|
15339
|
+
const existingContent = (0, import_node_fs8.readFileSync)(hookPath, "utf8");
|
|
14943
15340
|
if (existingContent.includes(VV_HOOK_MARKER)) {
|
|
14944
15341
|
return;
|
|
14945
15342
|
}
|
|
@@ -15055,7 +15452,9 @@ function createHooksCommand() {
|
|
|
15055
15452
|
console.log(source_default.bold("\nPrincipal View Hooks Status\n"));
|
|
15056
15453
|
console.log(`Repository: ${repoPath}`);
|
|
15057
15454
|
console.log(`Husky: ${source_default.green("installed")}`);
|
|
15058
|
-
console.log(
|
|
15455
|
+
console.log(
|
|
15456
|
+
`PV Hooks: ${hasHook ? source_default.green("configured") : source_default.yellow("not configured")}`
|
|
15457
|
+
);
|
|
15059
15458
|
if (hasHook) {
|
|
15060
15459
|
console.log("\nUse --remove to remove or --check to verify");
|
|
15061
15460
|
} else {
|
|
@@ -15079,7 +15478,10 @@ var TEMPLATE_CANVAS2 = {
|
|
|
15079
15478
|
};
|
|
15080
15479
|
function createCreateCommand() {
|
|
15081
15480
|
const command = new Command("create");
|
|
15082
|
-
command.description("Create a new canvas file in the .principal-views folder").requiredOption(
|
|
15481
|
+
command.description("Create a new canvas file in the .principal-views folder").requiredOption(
|
|
15482
|
+
"-n, --name <name>",
|
|
15483
|
+
'Name for the canvas file (e.g., "cache-sync-architecture")'
|
|
15484
|
+
).option("-f, --force", "Overwrite existing file").action(async (options) => {
|
|
15083
15485
|
try {
|
|
15084
15486
|
const vgcDir = (0, import_node_path10.join)(process.cwd(), ".principal-views");
|
|
15085
15487
|
const canvasFile = (0, import_node_path10.join)(vgcDir, `${options.name}.canvas`);
|
|
@@ -15088,7 +15490,9 @@ function createCreateCommand() {
|
|
|
15088
15490
|
console.log(source_default.green(`Created directory: .principal-views/`));
|
|
15089
15491
|
}
|
|
15090
15492
|
if ((0, import_node_fs9.existsSync)(canvasFile) && !options.force) {
|
|
15091
|
-
console.error(
|
|
15493
|
+
console.error(
|
|
15494
|
+
source_default.red(`Error: Canvas file already exists: .principal-views/${options.name}.canvas`)
|
|
15495
|
+
);
|
|
15092
15496
|
console.log(source_default.yellow(`Use ${source_default.cyan("--force")} to overwrite`));
|
|
15093
15497
|
process.exit(1);
|
|
15094
15498
|
}
|
|
@@ -15096,7 +15500,9 @@ function createCreateCommand() {
|
|
|
15096
15500
|
console.log(source_default.green(`\u2713 Created canvas file: .principal-views/${options.name}.canvas`));
|
|
15097
15501
|
console.log("");
|
|
15098
15502
|
console.log(source_default.bold("Next steps:"));
|
|
15099
|
-
console.log(
|
|
15503
|
+
console.log(
|
|
15504
|
+
` 1. Open ${source_default.cyan(`.principal-views/${options.name}.canvas`)} in your editor`
|
|
15505
|
+
);
|
|
15100
15506
|
console.log(` 2. Add nodes and edges to define your architecture`);
|
|
15101
15507
|
console.log(` 3. Run ${source_default.cyan("privu validate")} to check your configuration`);
|
|
15102
15508
|
console.log(` 4. Run ${source_default.cyan("privu doctor")} to verify source mappings`);
|
|
@@ -15508,7 +15914,11 @@ function createRulesEngine(rules) {
|
|
|
15508
15914
|
}
|
|
15509
15915
|
|
|
15510
15916
|
// ../core/dist/rules/config.js
|
|
15511
|
-
var DEFAULT_INCLUDE_PATTERNS = [
|
|
15917
|
+
var DEFAULT_INCLUDE_PATTERNS = [
|
|
15918
|
+
".principal-views/**/*.yaml",
|
|
15919
|
+
".principal-views/**/*.yml",
|
|
15920
|
+
".principal-views/**/*.json"
|
|
15921
|
+
];
|
|
15512
15922
|
var DEFAULT_EXCLUDE_PATTERNS = ["**/node_modules/**", "**/*.test.*"];
|
|
15513
15923
|
var VALID_SEVERITIES = [
|
|
15514
15924
|
"off",
|
|
@@ -17174,11 +17584,7 @@ function createDefaultRulesEngine() {
|
|
|
17174
17584
|
}
|
|
17175
17585
|
|
|
17176
17586
|
// src/commands/lint.ts
|
|
17177
|
-
var CONFIG_FILE_NAMES2 = [
|
|
17178
|
-
".privurc.yaml",
|
|
17179
|
-
".privurc.yml",
|
|
17180
|
-
".privurc.json"
|
|
17181
|
-
];
|
|
17587
|
+
var CONFIG_FILE_NAMES2 = [".privurc.yaml", ".privurc.yml", ".privurc.json"];
|
|
17182
17588
|
function findConfig(startDir) {
|
|
17183
17589
|
let currentDir = (0, import_node_path11.resolve)(startDir);
|
|
17184
17590
|
while (true) {
|
|
@@ -17334,7 +17740,10 @@ function formatJsonOutput(results) {
|
|
|
17334
17740
|
}
|
|
17335
17741
|
function createLintCommand() {
|
|
17336
17742
|
const command = new Command("lint");
|
|
17337
|
-
command.description("Lint graph configuration files").argument(
|
|
17743
|
+
command.description("Lint graph configuration files").argument(
|
|
17744
|
+
"[files...]",
|
|
17745
|
+
"Files or glob patterns to lint (defaults to .principal-views/**/*.yaml)"
|
|
17746
|
+
).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) => {
|
|
17338
17747
|
try {
|
|
17339
17748
|
const cwd = process.cwd();
|
|
17340
17749
|
let privuConfig = getDefaultConfig();
|
|
@@ -17382,7 +17791,11 @@ function createLintCommand() {
|
|
|
17382
17791
|
} else if (privuConfig.include && privuConfig.include.length > 0) {
|
|
17383
17792
|
patterns = privuConfig.include;
|
|
17384
17793
|
} else {
|
|
17385
|
-
patterns = [
|
|
17794
|
+
patterns = [
|
|
17795
|
+
".principal-views/**/*.yaml",
|
|
17796
|
+
".principal-views/**/*.yml",
|
|
17797
|
+
".principal-views/**/*.json"
|
|
17798
|
+
];
|
|
17386
17799
|
}
|
|
17387
17800
|
const matchedFiles = await globby(patterns, {
|
|
17388
17801
|
ignore: privuConfig.exclude || ["**/node_modules/**"],
|
|
@@ -17397,9 +17810,16 @@ function createLintCommand() {
|
|
|
17397
17810
|
});
|
|
17398
17811
|
if (configFiles.length === 0) {
|
|
17399
17812
|
if (options.json) {
|
|
17400
|
-
console.log(
|
|
17813
|
+
console.log(
|
|
17814
|
+
JSON.stringify({
|
|
17815
|
+
files: [],
|
|
17816
|
+
summary: { totalFiles: 0, totalErrors: 0, totalWarnings: 0, totalFixable: 0 }
|
|
17817
|
+
})
|
|
17818
|
+
);
|
|
17401
17819
|
} else {
|
|
17402
|
-
console.log(
|
|
17820
|
+
console.log(
|
|
17821
|
+
source_default.yellow("No configuration files found matching the specified patterns.")
|
|
17822
|
+
);
|
|
17403
17823
|
console.log(source_default.dim(`Patterns searched: ${patterns.join(", ")}`));
|
|
17404
17824
|
}
|
|
17405
17825
|
return;
|
|
@@ -17421,14 +17841,16 @@ function createLintCommand() {
|
|
|
17421
17841
|
const loaded = loadGraphConfig(absolutePath);
|
|
17422
17842
|
if (!loaded) {
|
|
17423
17843
|
results.set(relativePath, {
|
|
17424
|
-
violations: [
|
|
17425
|
-
|
|
17426
|
-
|
|
17427
|
-
|
|
17428
|
-
|
|
17429
|
-
|
|
17430
|
-
|
|
17431
|
-
|
|
17844
|
+
violations: [
|
|
17845
|
+
{
|
|
17846
|
+
ruleId: "parse-error",
|
|
17847
|
+
severity: "error",
|
|
17848
|
+
file: relativePath,
|
|
17849
|
+
message: `Could not parse file: ${filePath}`,
|
|
17850
|
+
impact: "File cannot be validated",
|
|
17851
|
+
fixable: false
|
|
17852
|
+
}
|
|
17853
|
+
],
|
|
17432
17854
|
errorCount: 1,
|
|
17433
17855
|
warningCount: 0,
|
|
17434
17856
|
fixableCount: 0,
|