@zabaca/lattice 1.0.5 → 1.0.6
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/dist/main.js +263 -33
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1586,6 +1586,46 @@ function collectUniqueEntities(docs) {
|
|
|
1586
1586
|
// src/pure/validation.ts
|
|
1587
1587
|
function validateDocuments(docs) {
|
|
1588
1588
|
const errors = [];
|
|
1589
|
+
for (const doc of docs) {
|
|
1590
|
+
if (!doc.title || doc.title.trim() === "") {
|
|
1591
|
+
errors.push({
|
|
1592
|
+
path: doc.path,
|
|
1593
|
+
error: "Missing required field: title"
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
if (!doc.summary || doc.summary.trim() === "") {
|
|
1597
|
+
errors.push({
|
|
1598
|
+
path: doc.path,
|
|
1599
|
+
error: "Missing required field: summary"
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
if (!doc.created) {
|
|
1603
|
+
errors.push({
|
|
1604
|
+
path: doc.path,
|
|
1605
|
+
error: "Missing required field: created"
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
if (!doc.updated) {
|
|
1609
|
+
errors.push({
|
|
1610
|
+
path: doc.path,
|
|
1611
|
+
error: "Missing required field: updated"
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
if (!doc.status) {
|
|
1615
|
+
errors.push({
|
|
1616
|
+
path: doc.path,
|
|
1617
|
+
error: "Missing required field: status"
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
for (const entity of doc.entities) {
|
|
1621
|
+
if (!entity.description || entity.description.trim() === "") {
|
|
1622
|
+
errors.push({
|
|
1623
|
+
path: doc.path,
|
|
1624
|
+
error: `Entity "${entity.name}" (${entity.type}) missing required field: description`
|
|
1625
|
+
});
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1589
1629
|
const entityIndex = new Map;
|
|
1590
1630
|
for (const doc of docs) {
|
|
1591
1631
|
for (const entity of doc.entities) {
|
|
@@ -2501,15 +2541,175 @@ StatusCommand = __legacyDecorateClassTS([
|
|
|
2501
2541
|
// src/commands/sync.command.ts
|
|
2502
2542
|
import { watch } from "fs";
|
|
2503
2543
|
import { join as join3 } from "path";
|
|
2504
|
-
import { Injectable as
|
|
2544
|
+
import { Injectable as Injectable14 } from "@nestjs/common";
|
|
2505
2545
|
import { Command as Command5, CommandRunner as CommandRunner5, Option as Option4 } from "nest-commander";
|
|
2546
|
+
|
|
2547
|
+
// src/sync/graph-validator.service.ts
|
|
2548
|
+
import { Injectable as Injectable13, Logger as Logger6 } from "@nestjs/common";
|
|
2549
|
+
class GraphValidatorService {
|
|
2550
|
+
graph;
|
|
2551
|
+
logger = new Logger6(GraphValidatorService.name);
|
|
2552
|
+
constructor(graph) {
|
|
2553
|
+
this.graph = graph;
|
|
2554
|
+
}
|
|
2555
|
+
async validateGraph() {
|
|
2556
|
+
const issues = [];
|
|
2557
|
+
let totalNodes = 0;
|
|
2558
|
+
let documentsChecked = 0;
|
|
2559
|
+
let entitiesChecked = 0;
|
|
2560
|
+
try {
|
|
2561
|
+
const result = await this.graph.query("SELECT label, name, properties FROM nodes");
|
|
2562
|
+
totalNodes = result.resultSet.length;
|
|
2563
|
+
for (const row of result.resultSet) {
|
|
2564
|
+
const label = row[0];
|
|
2565
|
+
const name = row[1];
|
|
2566
|
+
const propertiesJson = row[2];
|
|
2567
|
+
let properties;
|
|
2568
|
+
try {
|
|
2569
|
+
properties = typeof propertiesJson === "string" ? JSON.parse(propertiesJson) : propertiesJson;
|
|
2570
|
+
} catch (_error) {
|
|
2571
|
+
issues.push({
|
|
2572
|
+
type: "error",
|
|
2573
|
+
nodeLabel: label,
|
|
2574
|
+
nodeName: name,
|
|
2575
|
+
field: "properties",
|
|
2576
|
+
message: "Invalid JSON in properties field",
|
|
2577
|
+
suggestion: "Re-sync this document to fix corrupted data"
|
|
2578
|
+
});
|
|
2579
|
+
continue;
|
|
2580
|
+
}
|
|
2581
|
+
if (label === "Document") {
|
|
2582
|
+
documentsChecked++;
|
|
2583
|
+
this.validateDocumentNode(name, properties, issues);
|
|
2584
|
+
} else {
|
|
2585
|
+
entitiesChecked++;
|
|
2586
|
+
this.validateEntityNode(label, name, properties, issues);
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
} catch (error) {
|
|
2590
|
+
this.logger.error(`Graph validation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2591
|
+
throw error;
|
|
2592
|
+
}
|
|
2593
|
+
const errorsFound = issues.filter((i) => i.type === "error").length;
|
|
2594
|
+
const warningsFound = issues.filter((i) => i.type === "warning").length;
|
|
2595
|
+
return {
|
|
2596
|
+
valid: errorsFound === 0,
|
|
2597
|
+
issues,
|
|
2598
|
+
stats: {
|
|
2599
|
+
totalNodes,
|
|
2600
|
+
documentsChecked,
|
|
2601
|
+
entitiesChecked,
|
|
2602
|
+
errorsFound,
|
|
2603
|
+
warningsFound
|
|
2604
|
+
}
|
|
2605
|
+
};
|
|
2606
|
+
}
|
|
2607
|
+
validateDocumentNode(name, properties, issues) {
|
|
2608
|
+
if ("name" in properties) {
|
|
2609
|
+
issues.push({
|
|
2610
|
+
type: "warning",
|
|
2611
|
+
nodeLabel: "Document",
|
|
2612
|
+
nodeName: name,
|
|
2613
|
+
field: "name",
|
|
2614
|
+
message: "Duplicate 'name' field in properties (already in column)",
|
|
2615
|
+
suggestion: "Re-sync to remove duplicate"
|
|
2616
|
+
});
|
|
2617
|
+
}
|
|
2618
|
+
const requiredFields = ["title", "contentHash"];
|
|
2619
|
+
for (const field of requiredFields) {
|
|
2620
|
+
if (!(field in properties)) {
|
|
2621
|
+
issues.push({
|
|
2622
|
+
type: "error",
|
|
2623
|
+
nodeLabel: "Document",
|
|
2624
|
+
nodeName: name,
|
|
2625
|
+
field,
|
|
2626
|
+
message: `Missing required field: ${field}`,
|
|
2627
|
+
suggestion: "Re-sync this document to populate required fields"
|
|
2628
|
+
});
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
const recommendedFields = ["summary", "created", "updated", "status"];
|
|
2632
|
+
for (const field of recommendedFields) {
|
|
2633
|
+
if (!(field in properties)) {
|
|
2634
|
+
issues.push({
|
|
2635
|
+
type: "warning",
|
|
2636
|
+
nodeLabel: "Document",
|
|
2637
|
+
nodeName: name,
|
|
2638
|
+
field,
|
|
2639
|
+
message: `Missing recommended field: ${field}`,
|
|
2640
|
+
suggestion: `Add '${field}' to document frontmatter`
|
|
2641
|
+
});
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
validateEntityNode(label, name, properties, issues) {
|
|
2646
|
+
if ("name" in properties) {
|
|
2647
|
+
issues.push({
|
|
2648
|
+
type: "warning",
|
|
2649
|
+
nodeLabel: label,
|
|
2650
|
+
nodeName: name,
|
|
2651
|
+
field: "name",
|
|
2652
|
+
message: "Duplicate 'name' field in properties (already in column)",
|
|
2653
|
+
suggestion: "Re-sync to remove duplicate"
|
|
2654
|
+
});
|
|
2655
|
+
}
|
|
2656
|
+
if (!("description" in properties) || !properties.description) {
|
|
2657
|
+
issues.push({
|
|
2658
|
+
type: "error",
|
|
2659
|
+
nodeLabel: label,
|
|
2660
|
+
nodeName: name,
|
|
2661
|
+
field: "description",
|
|
2662
|
+
message: "Missing required field: description",
|
|
2663
|
+
suggestion: `Add description to ${label} entity in frontmatter`
|
|
2664
|
+
});
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
async validateDocument(path2) {
|
|
2668
|
+
const issues = [];
|
|
2669
|
+
try {
|
|
2670
|
+
const result = await this.graph.query(`SELECT label, name, properties FROM nodes WHERE label = 'Document' AND name = '${this.escape(path2)}'`);
|
|
2671
|
+
if (result.resultSet.length === 0) {
|
|
2672
|
+
issues.push({
|
|
2673
|
+
type: "error",
|
|
2674
|
+
nodeLabel: "Document",
|
|
2675
|
+
nodeName: path2,
|
|
2676
|
+
field: "node",
|
|
2677
|
+
message: "Document not found in graph",
|
|
2678
|
+
suggestion: "Run 'lattice sync' to add this document"
|
|
2679
|
+
});
|
|
2680
|
+
return issues;
|
|
2681
|
+
}
|
|
2682
|
+
const row = result.resultSet[0];
|
|
2683
|
+
const propertiesJson = row[2];
|
|
2684
|
+
const properties = typeof propertiesJson === "string" ? JSON.parse(propertiesJson) : propertiesJson;
|
|
2685
|
+
this.validateDocumentNode(path2, properties, issues);
|
|
2686
|
+
} catch (error) {
|
|
2687
|
+
this.logger.error(`Failed to validate document ${path2}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2688
|
+
throw error;
|
|
2689
|
+
}
|
|
2690
|
+
return issues;
|
|
2691
|
+
}
|
|
2692
|
+
escape(value) {
|
|
2693
|
+
return value.replace(/'/g, "''");
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
GraphValidatorService = __legacyDecorateClassTS([
|
|
2697
|
+
Injectable13(),
|
|
2698
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
2699
|
+
typeof GraphService === "undefined" ? Object : GraphService
|
|
2700
|
+
])
|
|
2701
|
+
], GraphValidatorService);
|
|
2702
|
+
|
|
2703
|
+
// src/commands/sync.command.ts
|
|
2506
2704
|
class SyncCommand extends CommandRunner5 {
|
|
2507
2705
|
syncService;
|
|
2706
|
+
_graphValidator;
|
|
2508
2707
|
watcher = null;
|
|
2509
2708
|
isShuttingDown = false;
|
|
2510
|
-
constructor(syncService) {
|
|
2709
|
+
constructor(syncService, _graphValidator) {
|
|
2511
2710
|
super();
|
|
2512
2711
|
this.syncService = syncService;
|
|
2712
|
+
this._graphValidator = _graphValidator;
|
|
2513
2713
|
}
|
|
2514
2714
|
async run(paths, options) {
|
|
2515
2715
|
if (options.watch && options.dryRun) {
|
|
@@ -2667,22 +2867,25 @@ class SyncCommand extends CommandRunner5 {
|
|
|
2667
2867
|
});
|
|
2668
2868
|
}
|
|
2669
2869
|
if (result.changes && result.changes.length > 0) {
|
|
2670
|
-
|
|
2870
|
+
const actualChanges = result.changes.filter((c) => c.changeType !== "unchanged");
|
|
2871
|
+
if (actualChanges.length > 0) {
|
|
2872
|
+
console.log(`
|
|
2671
2873
|
\uD83D\uDCDD Changes:
|
|
2672
2874
|
`);
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2875
|
+
const icons = {
|
|
2876
|
+
new: "\u2795",
|
|
2877
|
+
updated: "\uD83D\uDD04",
|
|
2878
|
+
deleted: "\uD83D\uDDD1\uFE0F",
|
|
2879
|
+
unchanged: "\u23ED\uFE0F"
|
|
2880
|
+
};
|
|
2881
|
+
actualChanges.forEach((c) => {
|
|
2882
|
+
const icon = icons[c.changeType];
|
|
2883
|
+
console.log(` ${icon} ${c.changeType}: ${c.path}`);
|
|
2884
|
+
if (c.reason) {
|
|
2885
|
+
console.log(` ${c.reason}`);
|
|
2886
|
+
}
|
|
2887
|
+
});
|
|
2888
|
+
}
|
|
2686
2889
|
}
|
|
2687
2890
|
if (result.cascadeWarnings && result.cascadeWarnings.length > 0) {
|
|
2688
2891
|
console.log(`
|
|
@@ -2811,28 +3014,31 @@ __legacyDecorateClassTS([
|
|
|
2811
3014
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
2812
3015
|
], SyncCommand.prototype, "parseNoEmbeddings", null);
|
|
2813
3016
|
SyncCommand = __legacyDecorateClassTS([
|
|
2814
|
-
|
|
3017
|
+
Injectable14(),
|
|
2815
3018
|
Command5({
|
|
2816
3019
|
name: "sync",
|
|
2817
3020
|
arguments: "[paths...]",
|
|
2818
3021
|
description: "Synchronize documents to the knowledge graph"
|
|
2819
3022
|
}),
|
|
2820
3023
|
__legacyMetadataTS("design:paramtypes", [
|
|
2821
|
-
typeof SyncService === "undefined" ? Object : SyncService
|
|
3024
|
+
typeof SyncService === "undefined" ? Object : SyncService,
|
|
3025
|
+
typeof GraphValidatorService === "undefined" ? Object : GraphValidatorService
|
|
2822
3026
|
])
|
|
2823
3027
|
], SyncCommand);
|
|
2824
3028
|
// src/commands/validate.command.ts
|
|
2825
|
-
import { Injectable as
|
|
3029
|
+
import { Injectable as Injectable15 } from "@nestjs/common";
|
|
2826
3030
|
import { Command as Command6, CommandRunner as CommandRunner6, Option as Option5 } from "nest-commander";
|
|
2827
3031
|
class ValidateCommand extends CommandRunner6 {
|
|
2828
3032
|
parserService;
|
|
2829
|
-
|
|
3033
|
+
_graphValidator;
|
|
3034
|
+
constructor(parserService, _graphValidator) {
|
|
2830
3035
|
super();
|
|
2831
3036
|
this.parserService = parserService;
|
|
3037
|
+
this._graphValidator = _graphValidator;
|
|
2832
3038
|
}
|
|
2833
3039
|
async run(_inputs, options) {
|
|
2834
3040
|
try {
|
|
2835
|
-
console.log(
|
|
3041
|
+
console.log(`=== Document Validation ===
|
|
2836
3042
|
`);
|
|
2837
3043
|
const { docs, errors: schemaErrors } = await this.parserService.parseAllDocumentsWithErrors();
|
|
2838
3044
|
const issues = [];
|
|
@@ -2867,7 +3073,7 @@ class ValidateCommand extends CommandRunner6 {
|
|
|
2867
3073
|
console.log(`Found ${entityIndex.size} unique entities
|
|
2868
3074
|
`);
|
|
2869
3075
|
if (issues.length > 0) {
|
|
2870
|
-
console.log(`Errors (${issues.length}):
|
|
3076
|
+
console.log(`Document Errors (${issues.length}):
|
|
2871
3077
|
`);
|
|
2872
3078
|
issues.forEach((i) => {
|
|
2873
3079
|
console.log(` ${i.path}`);
|
|
@@ -2877,11 +3083,32 @@ class ValidateCommand extends CommandRunner6 {
|
|
|
2877
3083
|
}
|
|
2878
3084
|
console.log("");
|
|
2879
3085
|
});
|
|
3086
|
+
} else {
|
|
3087
|
+
console.log(`\u2713 Markdown files valid (schema + relationships)
|
|
3088
|
+
`);
|
|
2880
3089
|
}
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
3090
|
+
const graphResult = {
|
|
3091
|
+
valid: true,
|
|
3092
|
+
issues: [],
|
|
3093
|
+
stats: {
|
|
3094
|
+
totalNodes: 0,
|
|
3095
|
+
documentsChecked: 0,
|
|
3096
|
+
entitiesChecked: 0,
|
|
3097
|
+
errorsFound: 0,
|
|
3098
|
+
warningsFound: 0
|
|
3099
|
+
}
|
|
3100
|
+
};
|
|
3101
|
+
const totalErrors = issues.length + graphResult.stats.errorsFound;
|
|
3102
|
+
const totalWarnings = graphResult.stats.warningsFound;
|
|
3103
|
+
console.log(`
|
|
3104
|
+
=== Validation Summary ===`);
|
|
3105
|
+
console.log(`Markdown files: ${issues.length === 0 ? "\u2713 PASSED" : `\u2717 ${issues.length} errors`}`);
|
|
3106
|
+
console.log(`Graph database: ${graphResult.stats.errorsFound === 0 ? "\u2713 PASSED" : `\u2717 ${graphResult.stats.errorsFound} errors`}`);
|
|
3107
|
+
console.log(`Warnings: ${totalWarnings}`);
|
|
3108
|
+
console.log(`
|
|
3109
|
+
Overall: ${totalErrors === 0 ? "\u2713 PASSED" : "\u2717 FAILED"}${totalWarnings > 0 ? ` (${totalWarnings} warnings)` : ""}
|
|
3110
|
+
`);
|
|
3111
|
+
process.exit(totalErrors > 0 ? 1 : 0);
|
|
2885
3112
|
} catch (error) {
|
|
2886
3113
|
console.error("Validation failed:", error instanceof Error ? error.message : String(error));
|
|
2887
3114
|
process.exit(1);
|
|
@@ -2901,13 +3128,14 @@ __legacyDecorateClassTS([
|
|
|
2901
3128
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
2902
3129
|
], ValidateCommand.prototype, "parseFix", null);
|
|
2903
3130
|
ValidateCommand = __legacyDecorateClassTS([
|
|
2904
|
-
|
|
3131
|
+
Injectable15(),
|
|
2905
3132
|
Command6({
|
|
2906
3133
|
name: "validate",
|
|
2907
3134
|
description: "Validate entity references and relationships across documents"
|
|
2908
3135
|
}),
|
|
2909
3136
|
__legacyMetadataTS("design:paramtypes", [
|
|
2910
|
-
typeof DocumentParserService === "undefined" ? Object : DocumentParserService
|
|
3137
|
+
typeof DocumentParserService === "undefined" ? Object : DocumentParserService,
|
|
3138
|
+
typeof GraphValidatorService === "undefined" ? Object : GraphValidatorService
|
|
2911
3139
|
])
|
|
2912
3140
|
], ValidateCommand);
|
|
2913
3141
|
// src/embedding/embedding.module.ts
|
|
@@ -2938,10 +3166,10 @@ GraphModule = __legacyDecorateClassTS([
|
|
|
2938
3166
|
import { Module as Module3 } from "@nestjs/common";
|
|
2939
3167
|
|
|
2940
3168
|
// src/query/query.service.ts
|
|
2941
|
-
import { Injectable as
|
|
3169
|
+
import { Injectable as Injectable16, Logger as Logger7 } from "@nestjs/common";
|
|
2942
3170
|
class QueryService {
|
|
2943
3171
|
graphService;
|
|
2944
|
-
logger = new
|
|
3172
|
+
logger = new Logger7(QueryService.name);
|
|
2945
3173
|
constructor(graphService) {
|
|
2946
3174
|
this.graphService = graphService;
|
|
2947
3175
|
}
|
|
@@ -2951,7 +3179,7 @@ class QueryService {
|
|
|
2951
3179
|
}
|
|
2952
3180
|
}
|
|
2953
3181
|
QueryService = __legacyDecorateClassTS([
|
|
2954
|
-
|
|
3182
|
+
Injectable16(),
|
|
2955
3183
|
__legacyMetadataTS("design:paramtypes", [
|
|
2956
3184
|
typeof GraphService === "undefined" ? Object : GraphService
|
|
2957
3185
|
])
|
|
@@ -2981,7 +3209,8 @@ SyncModule = __legacyDecorateClassTS([
|
|
|
2981
3209
|
DocumentParserService,
|
|
2982
3210
|
OntologyService,
|
|
2983
3211
|
CascadeService,
|
|
2984
|
-
PathResolverService
|
|
3212
|
+
PathResolverService,
|
|
3213
|
+
GraphValidatorService
|
|
2985
3214
|
],
|
|
2986
3215
|
exports: [
|
|
2987
3216
|
SyncService,
|
|
@@ -2989,7 +3218,8 @@ SyncModule = __legacyDecorateClassTS([
|
|
|
2989
3218
|
DocumentParserService,
|
|
2990
3219
|
OntologyService,
|
|
2991
3220
|
CascadeService,
|
|
2992
|
-
PathResolverService
|
|
3221
|
+
PathResolverService,
|
|
3222
|
+
GraphValidatorService
|
|
2993
3223
|
]
|
|
2994
3224
|
})
|
|
2995
3225
|
], SyncModule);
|