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