@soulcraft/brainy 3.20.2 → 3.20.3
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/CHANGELOG.md +9 -0
- package/bin/brainy-interactive.js +2 -2
- package/dist/brainy.d.ts +1 -1
- package/dist/mcp/brainyMCPAdapter.d.ts +1 -1
- package/dist/mcp/brainyMCPService.d.ts +1 -1
- package/dist/neural/embeddedPatterns.d.ts +1 -1
- package/dist/neural/embeddedPatterns.js +1 -1
- package/dist/shared/default-augmentations.d.ts +1 -1
- package/dist/types/{brainyDataInterface.js → brainyInterface.js} +1 -1
- package/package.json +1 -1
- package/dist/augmentationFactory.d.ts +0 -86
- package/dist/augmentationFactory.js +0 -342
- package/dist/augmentationRegistry.d.ts +0 -38
- package/dist/augmentationRegistry.js +0 -54
- package/dist/augmentationRegistryLoader.d.ts +0 -146
- package/dist/augmentationRegistryLoader.js +0 -213
- package/dist/augmentations/KnowledgeAugmentation.d.ts +0 -40
- package/dist/augmentations/KnowledgeAugmentation.js +0 -251
- package/dist/augmentations/intelligentVerbScoring.d.ts +0 -158
- package/dist/augmentations/intelligentVerbScoring.js +0 -377
- package/dist/augmentations/marketplace/AugmentationMarketplace.d.ts +0 -168
- package/dist/augmentations/marketplace/AugmentationMarketplace.js +0 -329
- package/dist/augmentations/marketplace/cli.d.ts +0 -47
- package/dist/augmentations/marketplace/cli.js +0 -265
- package/dist/augmentations/memoryAugmentations.d.ts +0 -72
- package/dist/augmentations/memoryAugmentations.js +0 -280
- package/dist/augmentations/serverSearchAugmentations.d.ts +0 -190
- package/dist/augmentations/serverSearchAugmentations.js +0 -586
- package/dist/brainy-unified.d.ts +0 -106
- package/dist/brainy-unified.js +0 -327
- package/dist/brainyData.d.ts +0 -1832
- package/dist/brainyData.js +0 -6443
- package/dist/brainyDataV3.d.ts +0 -186
- package/dist/brainyDataV3.js +0 -337
- package/dist/config/distributedPresets-new.d.ts +0 -118
- package/dist/config/distributedPresets-new.js +0 -318
- package/dist/config/modelPrecisionManager.d.ts +0 -42
- package/dist/config/modelPrecisionManager.js +0 -98
- package/dist/connectors/interfaces/IConnector.d.ts +0 -143
- package/dist/connectors/interfaces/IConnector.js +0 -8
- package/dist/demo.d.ts +0 -106
- package/dist/demo.js +0 -201
- package/dist/embeddings/SingletonModelManager.d.ts +0 -95
- package/dist/embeddings/SingletonModelManager.js +0 -220
- package/dist/embeddings/lightweight-embedder.d.ts +0 -22
- package/dist/embeddings/lightweight-embedder.js +0 -128
- package/dist/embeddings/model-manager.d.ts +0 -39
- package/dist/embeddings/model-manager.js +0 -245
- package/dist/embeddings/universal-memory-manager.d.ts +0 -38
- package/dist/embeddings/universal-memory-manager.js +0 -166
- package/dist/embeddings/worker-embedding.d.ts +0 -7
- package/dist/embeddings/worker-embedding.js +0 -73
- package/dist/embeddings/worker-manager.d.ts +0 -28
- package/dist/embeddings/worker-manager.js +0 -162
- package/dist/examples/basicUsage.d.ts +0 -4
- package/dist/examples/basicUsage.js +0 -121
- package/dist/indices/fieldIndex.d.ts +0 -76
- package/dist/indices/fieldIndex.js +0 -357
- package/dist/mcp/brainyMCPBroadcast.d.ts +0 -82
- package/dist/mcp/brainyMCPBroadcast.js +0 -303
- package/dist/mcp/brainyMCPClient.d.ts +0 -92
- package/dist/mcp/brainyMCPClient.js +0 -258
- package/dist/scripts/precomputePatternEmbeddings.d.ts +0 -19
- package/dist/scripts/precomputePatternEmbeddings.js +0 -100
- package/dist/utils/cacheAutoConfig.d.ts +0 -63
- package/dist/utils/cacheAutoConfig.js +0 -261
- package/dist/utils/hybridModelManager.d.ts +0 -64
- package/dist/utils/hybridModelManager.js +0 -95
- package/dist/utils/statistics.d.ts +0 -28
- package/dist/utils/statistics.js +0 -25
- package/dist/vfs/ConceptSystem.d.ts +0 -203
- package/dist/vfs/ConceptSystem.js +0 -545
- package/dist/vfs/EntityManager.d.ts +0 -75
- package/dist/vfs/EntityManager.js +0 -216
- package/dist/vfs/EventRecorder.d.ts +0 -84
- package/dist/vfs/EventRecorder.js +0 -269
- package/dist/vfs/GitBridge.d.ts +0 -167
- package/dist/vfs/GitBridge.js +0 -537
- package/dist/vfs/KnowledgeAugmentation.d.ts +0 -104
- package/dist/vfs/KnowledgeAugmentation.js +0 -146
- package/dist/vfs/KnowledgeLayer.d.ts +0 -35
- package/dist/vfs/KnowledgeLayer.js +0 -443
- package/dist/vfs/PersistentEntitySystem.d.ts +0 -165
- package/dist/vfs/PersistentEntitySystem.js +0 -503
- package/dist/vfs/SemanticVersioning.d.ts +0 -105
- package/dist/vfs/SemanticVersioning.js +0 -309
- package/dist/vfs/VFSHealthCheck.d.ts +0 -78
- package/dist/vfs/VFSHealthCheck.js +0 -299
- /package/dist/types/{brainyDataInterface.d.ts → brainyInterface.d.ts} +0 -0
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Semantic Versioning System for VFS
|
|
3
|
-
*
|
|
4
|
-
* Only creates versions when the MEANING of content changes significantly
|
|
5
|
-
* PRODUCTION-READY: Real implementation using embeddings
|
|
6
|
-
*/
|
|
7
|
-
import { NounType, VerbType } from '../types/graphTypes.js';
|
|
8
|
-
import { cosineDistance } from '../utils/distance.js';
|
|
9
|
-
import { createHash } from 'crypto';
|
|
10
|
-
import { v4 as uuidv4 } from '../universal/uuid.js';
|
|
11
|
-
import { EntityManager } from './EntityManager.js';
|
|
12
|
-
/**
|
|
13
|
-
* Semantic Versioning System
|
|
14
|
-
*
|
|
15
|
-
* Creates versions only when content meaning changes significantly
|
|
16
|
-
* Uses vector embeddings to detect semantic changes
|
|
17
|
-
*/
|
|
18
|
-
export class SemanticVersioning extends EntityManager {
|
|
19
|
-
constructor(brain, config) {
|
|
20
|
-
super(brain, 'vfs-version');
|
|
21
|
-
this.versionCache = new Map();
|
|
22
|
-
this.config = {
|
|
23
|
-
threshold: config?.threshold ?? 0.3,
|
|
24
|
-
maxVersions: config?.maxVersions ?? 10,
|
|
25
|
-
minInterval: config?.minInterval ?? 60000, // 1 minute
|
|
26
|
-
sizeChangeThreshold: config?.sizeChangeThreshold ?? 0.5
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Check if content has changed enough to warrant a new version
|
|
31
|
-
*/
|
|
32
|
-
async shouldVersion(oldContent, newContent) {
|
|
33
|
-
// Quick hash check - if identical, no version needed
|
|
34
|
-
const oldHash = this.hashContent(oldContent);
|
|
35
|
-
const newHash = this.hashContent(newContent);
|
|
36
|
-
if (oldHash === newHash) {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
// Check size change
|
|
40
|
-
const sizeChange = Math.abs(oldContent.length - newContent.length) / Math.max(oldContent.length, 1);
|
|
41
|
-
if (sizeChange > this.config.sizeChangeThreshold) {
|
|
42
|
-
return true; // Large size change warrants version
|
|
43
|
-
}
|
|
44
|
-
// For small files, any change is significant
|
|
45
|
-
if (oldContent.length < 100 || newContent.length < 100) {
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
// Check semantic change using embeddings
|
|
49
|
-
try {
|
|
50
|
-
const semanticDistance = await this.calculateSemanticDistance(oldContent, newContent);
|
|
51
|
-
return semanticDistance > this.config.threshold;
|
|
52
|
-
}
|
|
53
|
-
catch (error) {
|
|
54
|
-
// If embedding fails, fall back to size-based decision
|
|
55
|
-
console.warn('Failed to calculate semantic distance:', error);
|
|
56
|
-
return sizeChange > 0.2;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Create a new version
|
|
61
|
-
*/
|
|
62
|
-
async createVersion(path, content, metadata) {
|
|
63
|
-
const versionId = uuidv4();
|
|
64
|
-
const timestamp = Date.now();
|
|
65
|
-
const hash = this.hashContent(content);
|
|
66
|
-
// Get current version number
|
|
67
|
-
const versions = await this.getVersions(path);
|
|
68
|
-
const versionNumber = versions.length + 1;
|
|
69
|
-
const parentVersion = versions[0]?.id;
|
|
70
|
-
// Generate embedding for semantic comparison
|
|
71
|
-
let embedding;
|
|
72
|
-
let semanticHash;
|
|
73
|
-
try {
|
|
74
|
-
// Only generate embedding for reasonably sized content
|
|
75
|
-
if (content.length < 100000) {
|
|
76
|
-
embedding = await this.generateEmbedding(content);
|
|
77
|
-
if (embedding) {
|
|
78
|
-
semanticHash = this.hashEmbedding(embedding);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
console.warn('Failed to generate embedding for version:', error);
|
|
84
|
-
}
|
|
85
|
-
// Create version entity
|
|
86
|
-
const version = {
|
|
87
|
-
id: versionId,
|
|
88
|
-
path,
|
|
89
|
-
version: versionNumber,
|
|
90
|
-
timestamp,
|
|
91
|
-
hash,
|
|
92
|
-
semanticHash,
|
|
93
|
-
size: content.length,
|
|
94
|
-
author: metadata?.author,
|
|
95
|
-
message: metadata?.message,
|
|
96
|
-
parentVersion
|
|
97
|
-
};
|
|
98
|
-
// Store version using EntityManager (with actual content as data)
|
|
99
|
-
await this.storeEntity(version, NounType.State, embedding, content);
|
|
100
|
-
// Create relationship to parent version if exists
|
|
101
|
-
if (parentVersion) {
|
|
102
|
-
try {
|
|
103
|
-
await this.createRelationship(versionId, parentVersion, VerbType.Succeeds);
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
console.warn(`Failed to create parent relationship for version ${versionId}:`, error);
|
|
107
|
-
// Continue without relationship - non-critical for version functionality
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
// Update cache
|
|
111
|
-
if (!this.versionCache.has(path)) {
|
|
112
|
-
this.versionCache.set(path, []);
|
|
113
|
-
}
|
|
114
|
-
this.versionCache.get(path).unshift({
|
|
115
|
-
id: versionId,
|
|
116
|
-
path,
|
|
117
|
-
version: versionNumber,
|
|
118
|
-
timestamp,
|
|
119
|
-
hash,
|
|
120
|
-
size: content.length,
|
|
121
|
-
semanticHash,
|
|
122
|
-
author: metadata?.author,
|
|
123
|
-
message: metadata?.message,
|
|
124
|
-
parentVersion
|
|
125
|
-
});
|
|
126
|
-
// Prune old versions if needed
|
|
127
|
-
await this.pruneVersions(path);
|
|
128
|
-
return versionId;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Get all versions for a file
|
|
132
|
-
*/
|
|
133
|
-
async getVersions(path) {
|
|
134
|
-
// Check cache first
|
|
135
|
-
if (this.versionCache.has(path)) {
|
|
136
|
-
return this.versionCache.get(path);
|
|
137
|
-
}
|
|
138
|
-
// Query using EntityManager
|
|
139
|
-
const versions = await this.findEntities({ path }, NounType.State, this.config.maxVersions * 2 // Get extra in case some are pruned
|
|
140
|
-
);
|
|
141
|
-
// Sort by timestamp (newest first)
|
|
142
|
-
versions.sort((a, b) => b.timestamp - a.timestamp);
|
|
143
|
-
// Update cache
|
|
144
|
-
this.versionCache.set(path, versions);
|
|
145
|
-
return versions;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Get a specific version's content
|
|
149
|
-
*/
|
|
150
|
-
async getVersion(path, versionId) {
|
|
151
|
-
// Get the version entity
|
|
152
|
-
const version = await this.getEntity(versionId);
|
|
153
|
-
if (!version || version.path !== path) {
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
156
|
-
// Get the content from Brainy using the Brainy ID
|
|
157
|
-
const brainyId = await this.getBrainyId(versionId);
|
|
158
|
-
if (!brainyId) {
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
const entity = await this.brain.get(brainyId);
|
|
162
|
-
return entity?.data;
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Restore a file to a specific version
|
|
166
|
-
*/
|
|
167
|
-
async restoreVersion(path, versionId) {
|
|
168
|
-
const content = await this.getVersion(path, versionId);
|
|
169
|
-
if (!content) {
|
|
170
|
-
throw new Error(`Version ${versionId} not found for ${path}`);
|
|
171
|
-
}
|
|
172
|
-
// Create a new version pointing to the restored one
|
|
173
|
-
await this.createVersion(path, content, {
|
|
174
|
-
message: `Restored to version ${versionId}`
|
|
175
|
-
});
|
|
176
|
-
return content;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Get version history with diffs
|
|
180
|
-
*/
|
|
181
|
-
async getVersionHistory(path, limit = 10) {
|
|
182
|
-
const versions = await this.getVersions(path);
|
|
183
|
-
const history = [];
|
|
184
|
-
for (let i = 0; i < Math.min(versions.length, limit); i++) {
|
|
185
|
-
const version = versions[i];
|
|
186
|
-
let changes = undefined;
|
|
187
|
-
// Calculate changes from parent
|
|
188
|
-
if (version.parentVersion && i < versions.length - 1) {
|
|
189
|
-
const parentVersion = versions[i + 1];
|
|
190
|
-
if (parentVersion.id === version.parentVersion) {
|
|
191
|
-
// Simple size-based diff for now
|
|
192
|
-
changes = {
|
|
193
|
-
additions: Math.max(0, version.size - parentVersion.size),
|
|
194
|
-
deletions: Math.max(0, parentVersion.size - version.size),
|
|
195
|
-
semanticChange: version.semanticHash && parentVersion.semanticHash
|
|
196
|
-
? this.estimateSemanticChange(version.semanticHash, parentVersion.semanticHash)
|
|
197
|
-
: 0
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
history.push({ version, changes });
|
|
202
|
-
}
|
|
203
|
-
return history;
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Prune old versions beyond the limit
|
|
207
|
-
*/
|
|
208
|
-
async pruneVersions(path) {
|
|
209
|
-
const versions = await this.getVersions(path);
|
|
210
|
-
if (versions.length <= this.config.maxVersions) {
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
// Keep important versions (first, last, and evenly distributed)
|
|
214
|
-
const toKeep = new Set();
|
|
215
|
-
const toDelete = [];
|
|
216
|
-
// Always keep first and last
|
|
217
|
-
toKeep.add(versions[0].id); // Newest
|
|
218
|
-
toKeep.add(versions[versions.length - 1].id); // Oldest
|
|
219
|
-
// Keep evenly distributed versions
|
|
220
|
-
const step = Math.floor(versions.length / this.config.maxVersions);
|
|
221
|
-
for (let i = 0; i < versions.length; i += step) {
|
|
222
|
-
toKeep.add(versions[i].id);
|
|
223
|
-
}
|
|
224
|
-
// Mark others for deletion
|
|
225
|
-
for (const version of versions) {
|
|
226
|
-
if (!toKeep.has(version.id)) {
|
|
227
|
-
toDelete.push(version.id);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
// Delete excess versions
|
|
231
|
-
for (const id of toDelete.slice(0, versions.length - this.config.maxVersions)) {
|
|
232
|
-
await this.deleteEntity(id);
|
|
233
|
-
}
|
|
234
|
-
// Update cache
|
|
235
|
-
this.versionCache.set(path, versions.filter(v => !toDelete.includes(v.id)));
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Calculate semantic distance between two pieces of content
|
|
239
|
-
*/
|
|
240
|
-
async calculateSemanticDistance(oldContent, newContent) {
|
|
241
|
-
// Generate embeddings
|
|
242
|
-
const [oldEmbedding, newEmbedding] = await Promise.all([
|
|
243
|
-
this.generateEmbedding(oldContent),
|
|
244
|
-
this.generateEmbedding(newContent)
|
|
245
|
-
]);
|
|
246
|
-
if (!oldEmbedding || !newEmbedding) {
|
|
247
|
-
throw new Error('Failed to generate embeddings');
|
|
248
|
-
}
|
|
249
|
-
// Calculate cosine distance
|
|
250
|
-
return cosineDistance(oldEmbedding, newEmbedding);
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Generate embedding for content
|
|
254
|
-
*/
|
|
255
|
-
async generateEmbedding(content) {
|
|
256
|
-
try {
|
|
257
|
-
// For text content, use first 10KB for embedding
|
|
258
|
-
const text = content.toString('utf8', 0, Math.min(10240, content.length));
|
|
259
|
-
// Use Brainy's embedding function
|
|
260
|
-
const vector = await this.brain.embed(text);
|
|
261
|
-
return vector;
|
|
262
|
-
}
|
|
263
|
-
catch (error) {
|
|
264
|
-
console.error('Failed to generate embedding:', error);
|
|
265
|
-
return undefined;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Hash content for quick comparison
|
|
270
|
-
*/
|
|
271
|
-
hashContent(content) {
|
|
272
|
-
return createHash('sha256').update(content).digest('hex');
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Hash embedding for quick comparison
|
|
276
|
-
*/
|
|
277
|
-
hashEmbedding(embedding) {
|
|
278
|
-
return createHash('sha256')
|
|
279
|
-
.update(Buffer.from(new Float32Array(embedding).buffer))
|
|
280
|
-
.digest('hex');
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Estimate semantic change from hashes (rough approximation)
|
|
284
|
-
*/
|
|
285
|
-
estimateSemanticChange(hash1, hash2) {
|
|
286
|
-
if (hash1 === hash2)
|
|
287
|
-
return 0;
|
|
288
|
-
// Simple hamming distance on first few characters
|
|
289
|
-
// This is a rough approximation
|
|
290
|
-
let distance = 0;
|
|
291
|
-
for (let i = 0; i < Math.min(hash1.length, hash2.length, 8); i++) {
|
|
292
|
-
if (hash1[i] !== hash2[i])
|
|
293
|
-
distance++;
|
|
294
|
-
}
|
|
295
|
-
return distance / 8;
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Clear version cache for a file
|
|
299
|
-
*/
|
|
300
|
-
clearCache(path) {
|
|
301
|
-
if (path) {
|
|
302
|
-
this.versionCache.delete(path);
|
|
303
|
-
}
|
|
304
|
-
else {
|
|
305
|
-
this.versionCache.clear();
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
//# sourceMappingURL=SemanticVersioning.js.map
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { Brainy } from '../brainy.js';
|
|
2
|
-
import { VirtualFileSystem } from './VirtualFileSystem.js';
|
|
3
|
-
export interface VFSHealthReport {
|
|
4
|
-
healthy: boolean;
|
|
5
|
-
rootDirectory: {
|
|
6
|
-
exists: boolean;
|
|
7
|
-
isDirectory: boolean;
|
|
8
|
-
accessible: boolean;
|
|
9
|
-
};
|
|
10
|
-
containsRelationships: {
|
|
11
|
-
intact: boolean;
|
|
12
|
-
orphanedFiles: string[];
|
|
13
|
-
missingRelationships: number;
|
|
14
|
-
};
|
|
15
|
-
metadataIntegrity: {
|
|
16
|
-
valid: boolean;
|
|
17
|
-
malformedEntities: string[];
|
|
18
|
-
};
|
|
19
|
-
performance: {
|
|
20
|
-
readLatency: number;
|
|
21
|
-
writeLatency: number;
|
|
22
|
-
cacheHitRate: number;
|
|
23
|
-
};
|
|
24
|
-
recommendations: string[];
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* VFS Health Check and Recovery System
|
|
28
|
-
*
|
|
29
|
-
* Provides automated health checks, diagnostics, and recovery
|
|
30
|
-
* procedures for the Virtual File System.
|
|
31
|
-
*/
|
|
32
|
-
export declare class VFSHealthCheck {
|
|
33
|
-
private vfs;
|
|
34
|
-
private brain;
|
|
35
|
-
private logger;
|
|
36
|
-
constructor(vfs: VirtualFileSystem, brain: Brainy);
|
|
37
|
-
/**
|
|
38
|
-
* Perform comprehensive health check
|
|
39
|
-
*/
|
|
40
|
-
checkHealth(): Promise<VFSHealthReport>;
|
|
41
|
-
/**
|
|
42
|
-
* Check root directory health
|
|
43
|
-
*/
|
|
44
|
-
private checkRootDirectory;
|
|
45
|
-
/**
|
|
46
|
-
* Check Contains relationships integrity
|
|
47
|
-
*/
|
|
48
|
-
private checkContainsRelationships;
|
|
49
|
-
/**
|
|
50
|
-
* Check metadata integrity
|
|
51
|
-
*/
|
|
52
|
-
private checkMetadataIntegrity;
|
|
53
|
-
/**
|
|
54
|
-
* Check performance metrics
|
|
55
|
-
*/
|
|
56
|
-
private checkPerformance;
|
|
57
|
-
/**
|
|
58
|
-
* Generate recommendations based on health report
|
|
59
|
-
*/
|
|
60
|
-
private generateRecommendations;
|
|
61
|
-
/**
|
|
62
|
-
* Attempt to recover VFS to healthy state
|
|
63
|
-
*/
|
|
64
|
-
recover(): Promise<void>;
|
|
65
|
-
/**
|
|
66
|
-
* Recover root directory
|
|
67
|
-
*/
|
|
68
|
-
private recoverRootDirectory;
|
|
69
|
-
/**
|
|
70
|
-
* Repair orphaned files by creating missing Contains relationships
|
|
71
|
-
*/
|
|
72
|
-
private repairOrphanedFiles;
|
|
73
|
-
/**
|
|
74
|
-
* Fix malformed metadata
|
|
75
|
-
*/
|
|
76
|
-
private fixMalformedMetadata;
|
|
77
|
-
private getParentPath;
|
|
78
|
-
}
|
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import { VFSError, VFSErrorCode } from './types.js';
|
|
2
|
-
import { Logger } from '../utils/logger.js';
|
|
3
|
-
/**
|
|
4
|
-
* VFS Health Check and Recovery System
|
|
5
|
-
*
|
|
6
|
-
* Provides automated health checks, diagnostics, and recovery
|
|
7
|
-
* procedures for the Virtual File System.
|
|
8
|
-
*/
|
|
9
|
-
export class VFSHealthCheck {
|
|
10
|
-
constructor(vfs, brain) {
|
|
11
|
-
this.vfs = vfs;
|
|
12
|
-
this.brain = brain;
|
|
13
|
-
this.logger = new Logger('VFSHealthCheck');
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Perform comprehensive health check
|
|
17
|
-
*/
|
|
18
|
-
async checkHealth() {
|
|
19
|
-
const report = {
|
|
20
|
-
healthy: true,
|
|
21
|
-
rootDirectory: {
|
|
22
|
-
exists: false,
|
|
23
|
-
isDirectory: false,
|
|
24
|
-
accessible: false
|
|
25
|
-
},
|
|
26
|
-
containsRelationships: {
|
|
27
|
-
intact: true,
|
|
28
|
-
orphanedFiles: [],
|
|
29
|
-
missingRelationships: 0
|
|
30
|
-
},
|
|
31
|
-
metadataIntegrity: {
|
|
32
|
-
valid: true,
|
|
33
|
-
malformedEntities: []
|
|
34
|
-
},
|
|
35
|
-
performance: {
|
|
36
|
-
readLatency: 0,
|
|
37
|
-
writeLatency: 0,
|
|
38
|
-
cacheHitRate: 0
|
|
39
|
-
},
|
|
40
|
-
recommendations: []
|
|
41
|
-
};
|
|
42
|
-
// Check root directory
|
|
43
|
-
await this.checkRootDirectory(report);
|
|
44
|
-
// Check Contains relationships
|
|
45
|
-
await this.checkContainsRelationships(report);
|
|
46
|
-
// Check metadata integrity
|
|
47
|
-
await this.checkMetadataIntegrity(report);
|
|
48
|
-
// Check performance metrics
|
|
49
|
-
await this.checkPerformance(report);
|
|
50
|
-
// Generate recommendations
|
|
51
|
-
this.generateRecommendations(report);
|
|
52
|
-
report.healthy =
|
|
53
|
-
report.rootDirectory.exists &&
|
|
54
|
-
report.rootDirectory.isDirectory &&
|
|
55
|
-
report.rootDirectory.accessible &&
|
|
56
|
-
report.containsRelationships.intact &&
|
|
57
|
-
report.metadataIntegrity.valid;
|
|
58
|
-
return report;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Check root directory health
|
|
62
|
-
*/
|
|
63
|
-
async checkRootDirectory(report) {
|
|
64
|
-
try {
|
|
65
|
-
// Check if root exists
|
|
66
|
-
const rootId = await this.vfs.resolvePath('/');
|
|
67
|
-
report.rootDirectory.exists = !!rootId;
|
|
68
|
-
if (rootId) {
|
|
69
|
-
// Get root entity
|
|
70
|
-
const rootEntity = await this.brain.get(rootId);
|
|
71
|
-
// Check if it's a directory
|
|
72
|
-
report.rootDirectory.isDirectory =
|
|
73
|
-
rootEntity?.metadata?.vfsType === 'directory' ||
|
|
74
|
-
rootEntity?.vfsType === 'directory';
|
|
75
|
-
// Check if it's accessible
|
|
76
|
-
try {
|
|
77
|
-
await this.vfs.readdir('/');
|
|
78
|
-
report.rootDirectory.accessible = true;
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
report.rootDirectory.accessible = false;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
this.logger.error('Root directory check failed:', error);
|
|
87
|
-
report.rootDirectory.exists = false;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Check Contains relationships integrity
|
|
92
|
-
*/
|
|
93
|
-
async checkContainsRelationships(report) {
|
|
94
|
-
try {
|
|
95
|
-
// Get all file entities
|
|
96
|
-
const files = await this.brain.find({
|
|
97
|
-
metadata: { vfsType: 'file' },
|
|
98
|
-
limit: 1000
|
|
99
|
-
});
|
|
100
|
-
for (const file of files) {
|
|
101
|
-
// Check if file has a Contains relationship with its parent
|
|
102
|
-
const parentPath = this.getParentPath(file.metadata.path);
|
|
103
|
-
if (parentPath) {
|
|
104
|
-
try {
|
|
105
|
-
const parentId = await this.vfs.resolvePath(parentPath);
|
|
106
|
-
const relations = await this.brain.getRelations({
|
|
107
|
-
from: parentId,
|
|
108
|
-
to: file.id,
|
|
109
|
-
type: 'Contains'
|
|
110
|
-
});
|
|
111
|
-
if (relations.length === 0) {
|
|
112
|
-
report.containsRelationships.orphanedFiles.push(file.metadata.path);
|
|
113
|
-
report.containsRelationships.missingRelationships++;
|
|
114
|
-
report.containsRelationships.intact = false;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
// Parent doesn't exist
|
|
119
|
-
report.containsRelationships.orphanedFiles.push(file.metadata.path);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
this.logger.error('Contains relationships check failed:', error);
|
|
126
|
-
report.containsRelationships.intact = false;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Check metadata integrity
|
|
131
|
-
*/
|
|
132
|
-
async checkMetadataIntegrity(report) {
|
|
133
|
-
try {
|
|
134
|
-
// Get all VFS entities
|
|
135
|
-
const entities = await this.brain.find({
|
|
136
|
-
metadata: { path: { $exists: true } },
|
|
137
|
-
limit: 1000
|
|
138
|
-
});
|
|
139
|
-
for (const entity of entities) {
|
|
140
|
-
// Check required metadata fields
|
|
141
|
-
if (!entity.metadata?.vfsType ||
|
|
142
|
-
!entity.metadata?.path ||
|
|
143
|
-
entity.metadata.vfsType !== 'file' && entity.metadata.vfsType !== 'directory') {
|
|
144
|
-
report.metadataIntegrity.malformedEntities.push(entity.id);
|
|
145
|
-
report.metadataIntegrity.valid = false;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
this.logger.error('Metadata integrity check failed:', error);
|
|
151
|
-
report.metadataIntegrity.valid = false;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Check performance metrics
|
|
156
|
-
*/
|
|
157
|
-
async checkPerformance(report) {
|
|
158
|
-
try {
|
|
159
|
-
// Test read performance
|
|
160
|
-
const readStart = Date.now();
|
|
161
|
-
await this.vfs.readdir('/');
|
|
162
|
-
report.performance.readLatency = Date.now() - readStart;
|
|
163
|
-
// Test write performance
|
|
164
|
-
const writeStart = Date.now();
|
|
165
|
-
const testPath = '/.health-check-' + Date.now();
|
|
166
|
-
await this.vfs.writeFile(testPath, 'test');
|
|
167
|
-
report.performance.writeLatency = Date.now() - writeStart;
|
|
168
|
-
// Clean up test file
|
|
169
|
-
await this.vfs.unlink(testPath);
|
|
170
|
-
// Calculate cache hit rate (if available)
|
|
171
|
-
const stats = await this.brain.getStatistics();
|
|
172
|
-
if (stats?.cache) {
|
|
173
|
-
report.performance.cacheHitRate = stats.cache.hitRate || 0;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
catch (error) {
|
|
177
|
-
this.logger.error('Performance check failed:', error);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Generate recommendations based on health report
|
|
182
|
-
*/
|
|
183
|
-
generateRecommendations(report) {
|
|
184
|
-
if (!report.rootDirectory.exists || !report.rootDirectory.isDirectory) {
|
|
185
|
-
report.recommendations.push('Run VFS recovery to rebuild root directory');
|
|
186
|
-
}
|
|
187
|
-
if (report.containsRelationships.orphanedFiles.length > 0) {
|
|
188
|
-
report.recommendations.push(`Repair ${report.containsRelationships.orphanedFiles.length} orphaned files`);
|
|
189
|
-
}
|
|
190
|
-
if (report.metadataIntegrity.malformedEntities.length > 0) {
|
|
191
|
-
report.recommendations.push(`Fix metadata for ${report.metadataIntegrity.malformedEntities.length} malformed entities`);
|
|
192
|
-
}
|
|
193
|
-
if (report.performance.readLatency > 100) {
|
|
194
|
-
report.recommendations.push('Consider enabling caching or optimizing indexes');
|
|
195
|
-
}
|
|
196
|
-
if (report.performance.cacheHitRate < 0.5) {
|
|
197
|
-
report.recommendations.push('Increase cache size or TTL for better performance');
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Attempt to recover VFS to healthy state
|
|
202
|
-
*/
|
|
203
|
-
async recover() {
|
|
204
|
-
this.logger.info('Starting VFS recovery...');
|
|
205
|
-
// 1. Ensure root directory exists and is properly configured
|
|
206
|
-
await this.recoverRootDirectory();
|
|
207
|
-
// 2. Repair orphaned files
|
|
208
|
-
await this.repairOrphanedFiles();
|
|
209
|
-
// 3. Fix malformed metadata
|
|
210
|
-
await this.fixMalformedMetadata();
|
|
211
|
-
this.logger.info('VFS recovery completed');
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Recover root directory
|
|
215
|
-
*/
|
|
216
|
-
async recoverRootDirectory() {
|
|
217
|
-
try {
|
|
218
|
-
// Force recreation of root directory with proper metadata
|
|
219
|
-
const rootId = await this.vfs['initializeRoot']();
|
|
220
|
-
// Verify root is now accessible
|
|
221
|
-
await this.vfs.readdir('/');
|
|
222
|
-
this.logger.info('Root directory recovered successfully');
|
|
223
|
-
}
|
|
224
|
-
catch (error) {
|
|
225
|
-
this.logger.error('Failed to recover root directory:', error);
|
|
226
|
-
throw new VFSError(VFSErrorCode.EIO, 'Failed to recover root directory', '/', 'recover');
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Repair orphaned files by creating missing Contains relationships
|
|
231
|
-
*/
|
|
232
|
-
async repairOrphanedFiles() {
|
|
233
|
-
const report = await this.checkHealth();
|
|
234
|
-
for (const filePath of report.containsRelationships.orphanedFiles) {
|
|
235
|
-
try {
|
|
236
|
-
const fileId = await this.vfs.resolvePath(filePath);
|
|
237
|
-
const parentPath = this.getParentPath(filePath);
|
|
238
|
-
if (parentPath) {
|
|
239
|
-
// Ensure parent directory exists
|
|
240
|
-
await this.vfs.mkdir(parentPath, { recursive: true });
|
|
241
|
-
const parentId = await this.vfs.resolvePath(parentPath);
|
|
242
|
-
// Create missing Contains relationship
|
|
243
|
-
await this.brain.relate({
|
|
244
|
-
from: parentId,
|
|
245
|
-
to: fileId,
|
|
246
|
-
type: 'Contains'
|
|
247
|
-
});
|
|
248
|
-
this.logger.info(`Repaired orphaned file: ${filePath}`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
catch (error) {
|
|
252
|
-
this.logger.error(`Failed to repair orphaned file ${filePath}:`, error);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Fix malformed metadata
|
|
258
|
-
*/
|
|
259
|
-
async fixMalformedMetadata() {
|
|
260
|
-
const report = await this.checkHealth();
|
|
261
|
-
for (const entityId of report.metadataIntegrity.malformedEntities) {
|
|
262
|
-
try {
|
|
263
|
-
const entity = await this.brain.get(entityId);
|
|
264
|
-
if (entity) {
|
|
265
|
-
// Reconstruct metadata
|
|
266
|
-
const fixedMetadata = {
|
|
267
|
-
path: entity.metadata?.path || entity.path || '/',
|
|
268
|
-
name: entity.metadata?.name || entity.name || '',
|
|
269
|
-
vfsType: entity.metadata?.vfsType || entity.vfsType || 'file',
|
|
270
|
-
size: entity.metadata?.size || entity.size || 0,
|
|
271
|
-
permissions: entity.metadata?.permissions || 0o644,
|
|
272
|
-
owner: entity.metadata?.owner || 'user',
|
|
273
|
-
group: entity.metadata?.group || 'users',
|
|
274
|
-
accessed: entity.metadata?.accessed || Date.now(),
|
|
275
|
-
modified: entity.metadata?.modified || Date.now(),
|
|
276
|
-
...entity.metadata
|
|
277
|
-
};
|
|
278
|
-
// Update entity with fixed metadata
|
|
279
|
-
await this.brain.update({
|
|
280
|
-
id: entityId,
|
|
281
|
-
metadata: fixedMetadata
|
|
282
|
-
});
|
|
283
|
-
this.logger.info(`Fixed metadata for entity: ${entityId}`);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
catch (error) {
|
|
287
|
-
this.logger.error(`Failed to fix metadata for entity ${entityId}:`, error);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
getParentPath(path) {
|
|
292
|
-
const normalized = path.replace(/\/+/g, '/').replace(/\/$/, '');
|
|
293
|
-
const lastSlash = normalized.lastIndexOf('/');
|
|
294
|
-
if (lastSlash <= 0)
|
|
295
|
-
return '/';
|
|
296
|
-
return normalized.substring(0, lastSlash);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
//# sourceMappingURL=VFSHealthCheck.js.map
|
|
File without changes
|