@soulcraft/brainy 6.2.2 → 6.2.4
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/augmentations/KnowledgeAugmentation.d.ts +40 -0
- package/dist/augmentations/KnowledgeAugmentation.js +251 -0
- package/dist/importManager.d.ts +78 -0
- package/dist/importManager.js +267 -0
- package/dist/query/typeInference.d.ts +158 -0
- package/dist/query/typeInference.js +760 -0
- package/dist/storage/adapters/historicalStorageAdapter.d.ts +0 -2
- package/dist/storage/adapters/historicalStorageAdapter.js +4 -4
- package/dist/storage/adapters/typeAwareStorageAdapter.d.ts +252 -0
- package/dist/storage/adapters/typeAwareStorageAdapter.js +814 -0
- package/dist/storage/baseStorage.d.ts +12 -0
- package/dist/storage/baseStorage.js +16 -0
- package/dist/types/brainyDataInterface.d.ts +52 -0
- package/dist/types/brainyDataInterface.js +10 -0
- package/dist/utils/metadataIndex.d.ts +6 -2
- package/dist/utils/metadataIndex.js +31 -14
- package/dist/vfs/ConceptSystem.d.ts +203 -0
- package/dist/vfs/ConceptSystem.js +545 -0
- package/dist/vfs/EntityManager.d.ts +75 -0
- package/dist/vfs/EntityManager.js +216 -0
- package/dist/vfs/EventRecorder.d.ts +84 -0
- package/dist/vfs/EventRecorder.js +269 -0
- package/dist/vfs/GitBridge.d.ts +167 -0
- package/dist/vfs/GitBridge.js +537 -0
- package/dist/vfs/KnowledgeLayer.d.ts +35 -0
- package/dist/vfs/KnowledgeLayer.js +443 -0
- package/dist/vfs/PersistentEntitySystem.d.ts +165 -0
- package/dist/vfs/PersistentEntitySystem.js +503 -0
- package/dist/vfs/SemanticVersioning.d.ts +105 -0
- package/dist/vfs/SemanticVersioning.js +309 -0
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge Layer for VFS
|
|
3
|
+
*
|
|
4
|
+
* This is the REAL integration that makes VFS intelligent.
|
|
5
|
+
* It wraps VFS operations and adds Knowledge Layer processing.
|
|
6
|
+
*/
|
|
7
|
+
import { VirtualFileSystem } from './VirtualFileSystem.js';
|
|
8
|
+
import { Brainy } from '../brainy.js';
|
|
9
|
+
export declare class KnowledgeLayer {
|
|
10
|
+
private vfs;
|
|
11
|
+
private brain;
|
|
12
|
+
private eventRecorder;
|
|
13
|
+
private semanticVersioning;
|
|
14
|
+
private entitySystem;
|
|
15
|
+
private conceptSystem;
|
|
16
|
+
private gitBridge;
|
|
17
|
+
private enabled;
|
|
18
|
+
constructor(vfs: VirtualFileSystem, brain: Brainy);
|
|
19
|
+
/**
|
|
20
|
+
* Enable Knowledge Layer by wrapping VFS methods
|
|
21
|
+
*/
|
|
22
|
+
enable(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Add Knowledge Layer query methods to VFS
|
|
25
|
+
*/
|
|
26
|
+
private addKnowledgeMethods;
|
|
27
|
+
/**
|
|
28
|
+
* Disable Knowledge Layer
|
|
29
|
+
*/
|
|
30
|
+
disable(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Enable Knowledge Layer on a VFS instance
|
|
34
|
+
*/
|
|
35
|
+
export declare function enableKnowledgeLayer(vfs: VirtualFileSystem, brain: Brainy): Promise<KnowledgeLayer>;
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge Layer for VFS
|
|
3
|
+
*
|
|
4
|
+
* This is the REAL integration that makes VFS intelligent.
|
|
5
|
+
* It wraps VFS operations and adds Knowledge Layer processing.
|
|
6
|
+
*/
|
|
7
|
+
import { EventRecorder } from './EventRecorder.js';
|
|
8
|
+
import { SemanticVersioning } from './SemanticVersioning.js';
|
|
9
|
+
import { PersistentEntitySystem } from './PersistentEntitySystem.js';
|
|
10
|
+
import { ConceptSystem } from './ConceptSystem.js';
|
|
11
|
+
import { GitBridge } from './GitBridge.js';
|
|
12
|
+
export class KnowledgeLayer {
|
|
13
|
+
constructor(vfs, brain) {
|
|
14
|
+
this.vfs = vfs;
|
|
15
|
+
this.brain = brain;
|
|
16
|
+
this.enabled = false;
|
|
17
|
+
// Initialize all Knowledge Layer components
|
|
18
|
+
this.eventRecorder = new EventRecorder(brain);
|
|
19
|
+
this.semanticVersioning = new SemanticVersioning(brain);
|
|
20
|
+
this.entitySystem = new PersistentEntitySystem(brain);
|
|
21
|
+
this.conceptSystem = new ConceptSystem(brain);
|
|
22
|
+
this.gitBridge = new GitBridge(vfs, brain);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Enable Knowledge Layer by wrapping VFS methods
|
|
26
|
+
*/
|
|
27
|
+
async enable() {
|
|
28
|
+
if (this.enabled)
|
|
29
|
+
return;
|
|
30
|
+
this.enabled = true;
|
|
31
|
+
// Save original methods
|
|
32
|
+
const originalWriteFile = this.vfs.writeFile.bind(this.vfs);
|
|
33
|
+
const originalUnlink = this.vfs.unlink.bind(this.vfs);
|
|
34
|
+
const originalRename = this.vfs.rename.bind(this.vfs);
|
|
35
|
+
const originalMkdir = this.vfs.mkdir.bind(this.vfs);
|
|
36
|
+
const originalRmdir = this.vfs.rmdir.bind(this.vfs);
|
|
37
|
+
// Wrap writeFile to add intelligence
|
|
38
|
+
this.vfs.writeFile = async (path, data, options) => {
|
|
39
|
+
// Call original VFS method first
|
|
40
|
+
const result = await originalWriteFile(path, data, options);
|
|
41
|
+
// Process in background (non-blocking)
|
|
42
|
+
setImmediate(async () => {
|
|
43
|
+
try {
|
|
44
|
+
const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
45
|
+
// 1. Record the event
|
|
46
|
+
await this.eventRecorder.recordEvent({
|
|
47
|
+
type: 'write',
|
|
48
|
+
path,
|
|
49
|
+
content: buffer,
|
|
50
|
+
size: buffer.length,
|
|
51
|
+
author: options?.author || 'system'
|
|
52
|
+
});
|
|
53
|
+
// 2. Check for semantic versioning
|
|
54
|
+
try {
|
|
55
|
+
const existingContent = await this.vfs.readFile(path).catch(() => null);
|
|
56
|
+
if (existingContent) {
|
|
57
|
+
const shouldVersion = await this.semanticVersioning.shouldVersion(existingContent, buffer);
|
|
58
|
+
if (shouldVersion) {
|
|
59
|
+
await this.semanticVersioning.createVersion(path, buffer, {
|
|
60
|
+
message: options?.message || 'Automatic semantic version'
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
console.debug('Versioning check failed:', err);
|
|
67
|
+
}
|
|
68
|
+
// 3. Extract entities
|
|
69
|
+
if (options?.extractEntities !== false) {
|
|
70
|
+
await this.entitySystem.extractEntities(path, buffer);
|
|
71
|
+
}
|
|
72
|
+
// 4. Extract concepts
|
|
73
|
+
if (options?.extractConcepts !== false) {
|
|
74
|
+
await this.conceptSystem.extractAndLinkConcepts(path, buffer);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.debug('Knowledge Layer processing error:', error);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return result;
|
|
82
|
+
};
|
|
83
|
+
// Wrap unlink to record deletion
|
|
84
|
+
this.vfs.unlink = async (path) => {
|
|
85
|
+
const result = await originalUnlink(path);
|
|
86
|
+
setImmediate(async () => {
|
|
87
|
+
await this.eventRecorder.recordEvent({
|
|
88
|
+
type: 'delete',
|
|
89
|
+
path,
|
|
90
|
+
author: 'system'
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
return result;
|
|
94
|
+
};
|
|
95
|
+
// Wrap rename to track moves
|
|
96
|
+
this.vfs.rename = async (oldPath, newPath) => {
|
|
97
|
+
const result = await originalRename(oldPath, newPath);
|
|
98
|
+
setImmediate(async () => {
|
|
99
|
+
await this.eventRecorder.recordEvent({
|
|
100
|
+
type: 'rename',
|
|
101
|
+
path: oldPath,
|
|
102
|
+
metadata: { newPath },
|
|
103
|
+
author: 'system'
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
return result;
|
|
107
|
+
};
|
|
108
|
+
// Wrap mkdir to track directory creation
|
|
109
|
+
this.vfs.mkdir = async (path, options) => {
|
|
110
|
+
const result = await originalMkdir(path, options);
|
|
111
|
+
setImmediate(async () => {
|
|
112
|
+
await this.eventRecorder.recordEvent({
|
|
113
|
+
type: 'mkdir',
|
|
114
|
+
path,
|
|
115
|
+
author: 'system'
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
return result;
|
|
119
|
+
};
|
|
120
|
+
// Wrap rmdir to track directory deletion
|
|
121
|
+
this.vfs.rmdir = async (path, options) => {
|
|
122
|
+
const result = await originalRmdir(path, options);
|
|
123
|
+
setImmediate(async () => {
|
|
124
|
+
await this.eventRecorder.recordEvent({
|
|
125
|
+
type: 'rmdir',
|
|
126
|
+
path,
|
|
127
|
+
author: 'system'
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
return result;
|
|
131
|
+
};
|
|
132
|
+
// Add Knowledge Layer methods to VFS
|
|
133
|
+
this.addKnowledgeMethods();
|
|
134
|
+
console.log('✨ Knowledge Layer enabled on VFS');
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Add Knowledge Layer query methods to VFS
|
|
138
|
+
*/
|
|
139
|
+
addKnowledgeMethods() {
|
|
140
|
+
// Event history
|
|
141
|
+
this.vfs.getHistory = async (path, options) => {
|
|
142
|
+
return await this.eventRecorder.getHistory(path, options);
|
|
143
|
+
};
|
|
144
|
+
this.vfs.reconstructAtTime = async (path, timestamp) => {
|
|
145
|
+
return await this.eventRecorder.reconstructFileAtTime(path, timestamp);
|
|
146
|
+
};
|
|
147
|
+
// Semantic versioning
|
|
148
|
+
this.vfs.getVersions = async (path) => {
|
|
149
|
+
return await this.semanticVersioning.getVersions(path);
|
|
150
|
+
};
|
|
151
|
+
this.vfs.getVersion = async (path, versionId) => {
|
|
152
|
+
return await this.semanticVersioning.getVersion(path, versionId);
|
|
153
|
+
};
|
|
154
|
+
this.vfs.restoreVersion = async (path, versionId) => {
|
|
155
|
+
const content = await this.semanticVersioning.getVersion(path, versionId);
|
|
156
|
+
if (content) {
|
|
157
|
+
await this.vfs.writeFile(path, content);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
// Entity system
|
|
161
|
+
this.vfs.createEntity = async (config) => {
|
|
162
|
+
return await this.entitySystem.createEntity(config);
|
|
163
|
+
};
|
|
164
|
+
this.vfs.findEntity = async (query) => {
|
|
165
|
+
return await this.entitySystem.findEntity(query);
|
|
166
|
+
};
|
|
167
|
+
this.vfs.getEntityEvolution = async (entityId) => {
|
|
168
|
+
return await this.entitySystem.getEvolution(entityId);
|
|
169
|
+
};
|
|
170
|
+
// Concept system
|
|
171
|
+
this.vfs.createConcept = async (config) => {
|
|
172
|
+
return await this.conceptSystem.createConcept(config);
|
|
173
|
+
};
|
|
174
|
+
this.vfs.findConcepts = async (query) => {
|
|
175
|
+
return await this.conceptSystem.findConcepts(query);
|
|
176
|
+
};
|
|
177
|
+
this.vfs.getConceptGraph = async (options) => {
|
|
178
|
+
return await this.conceptSystem.getConceptGraph(options);
|
|
179
|
+
};
|
|
180
|
+
// Git bridge
|
|
181
|
+
this.vfs.exportToGit = async (vfsPath, gitPath) => {
|
|
182
|
+
return await this.gitBridge.exportToGit(vfsPath, gitPath);
|
|
183
|
+
};
|
|
184
|
+
this.vfs.importFromGit = async (gitPath, vfsPath) => {
|
|
185
|
+
return await this.gitBridge.importFromGit(gitPath, vfsPath);
|
|
186
|
+
};
|
|
187
|
+
// Temporal coupling
|
|
188
|
+
this.vfs.findTemporalCoupling = async (path, windowMs) => {
|
|
189
|
+
return await this.eventRecorder.findTemporalCoupling(path, windowMs);
|
|
190
|
+
};
|
|
191
|
+
// Entity convenience methods that wrap Brainy's core API
|
|
192
|
+
this.vfs.linkEntities = async (fromEntity, toEntity, relationship) => {
|
|
193
|
+
// Handle both entity IDs and entity objects
|
|
194
|
+
const fromId = typeof fromEntity === 'string' ? fromEntity : fromEntity.id;
|
|
195
|
+
const toId = typeof toEntity === 'string' ? toEntity : toEntity.id;
|
|
196
|
+
// Use brain.relate to create the relationship
|
|
197
|
+
return await this.brain.relate({
|
|
198
|
+
from: fromId,
|
|
199
|
+
to: toId,
|
|
200
|
+
type: relationship // VerbType or string
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
// Find where an entity appears across files
|
|
204
|
+
this.vfs.findEntityOccurrences = async (entityId) => {
|
|
205
|
+
const occurrences = [];
|
|
206
|
+
// Search for files that contain references to this entity
|
|
207
|
+
// First, get all relationships where this entity is involved
|
|
208
|
+
const relations = await this.brain.getRelations({ from: entityId });
|
|
209
|
+
const toRelations = await this.brain.getRelations({ to: entityId });
|
|
210
|
+
// Find file entities that relate to this entity
|
|
211
|
+
for (const rel of [...relations, ...toRelations]) {
|
|
212
|
+
try {
|
|
213
|
+
// Check if the related entity is a file
|
|
214
|
+
const relatedId = rel.from === entityId ? rel.to : rel.from;
|
|
215
|
+
const entity = await this.brain.get(relatedId);
|
|
216
|
+
if (entity?.metadata?.vfsType === 'file' && entity?.metadata?.path) {
|
|
217
|
+
occurrences.push({
|
|
218
|
+
path: entity.metadata.path,
|
|
219
|
+
context: entity.data ? entity.data.toString().substring(0, 200) : undefined
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
// Entity might not exist, continue
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Also search for files that mention the entity name in their content
|
|
228
|
+
const entityData = await this.brain.get(entityId);
|
|
229
|
+
if (entityData?.metadata?.name) {
|
|
230
|
+
const searchResults = await this.brain.find({
|
|
231
|
+
query: entityData.metadata.name,
|
|
232
|
+
where: { vfsType: 'file' },
|
|
233
|
+
limit: 20
|
|
234
|
+
});
|
|
235
|
+
for (const result of searchResults) {
|
|
236
|
+
if (result.entity?.metadata?.path && !occurrences.some(o => o.path === result.entity.metadata.path)) {
|
|
237
|
+
occurrences.push({
|
|
238
|
+
path: result.entity.metadata.path,
|
|
239
|
+
context: result.entity.data ? result.entity.data.toString().substring(0, 200) : undefined
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return occurrences;
|
|
245
|
+
};
|
|
246
|
+
// Update an entity (convenience wrapper)
|
|
247
|
+
this.vfs.updateEntity = async (entityId, updates) => {
|
|
248
|
+
// Get current entity from brain
|
|
249
|
+
const currentEntity = await this.brain.get(entityId);
|
|
250
|
+
if (!currentEntity) {
|
|
251
|
+
throw new Error(`Entity ${entityId} not found`);
|
|
252
|
+
}
|
|
253
|
+
// Merge updates
|
|
254
|
+
const updatedMetadata = {
|
|
255
|
+
...currentEntity.metadata,
|
|
256
|
+
...updates,
|
|
257
|
+
lastUpdated: Date.now(),
|
|
258
|
+
version: (currentEntity.metadata?.version || 0) + 1
|
|
259
|
+
};
|
|
260
|
+
// Update via brain
|
|
261
|
+
await this.brain.update({
|
|
262
|
+
id: entityId,
|
|
263
|
+
data: JSON.stringify(updatedMetadata),
|
|
264
|
+
metadata: updatedMetadata
|
|
265
|
+
});
|
|
266
|
+
return entityId;
|
|
267
|
+
};
|
|
268
|
+
// Get entity graph (convenience wrapper)
|
|
269
|
+
this.vfs.getEntityGraph = async (entityId, options) => {
|
|
270
|
+
const depth = options?.depth || 2;
|
|
271
|
+
const graph = { nodes: new Map(), edges: [] };
|
|
272
|
+
const visited = new Set();
|
|
273
|
+
const traverse = async (id, currentDepth) => {
|
|
274
|
+
if (visited.has(id) || currentDepth > depth)
|
|
275
|
+
return;
|
|
276
|
+
visited.add(id);
|
|
277
|
+
// Add node
|
|
278
|
+
const entity = await this.brain.get(id);
|
|
279
|
+
if (entity) {
|
|
280
|
+
graph.nodes.set(id, entity);
|
|
281
|
+
}
|
|
282
|
+
// Get relationships
|
|
283
|
+
const relations = await this.brain.getRelations({ from: id });
|
|
284
|
+
const toRelations = await this.brain.getRelations({ to: id });
|
|
285
|
+
for (const rel of [...relations, ...toRelations]) {
|
|
286
|
+
graph.edges.push(rel);
|
|
287
|
+
// Traverse connected nodes
|
|
288
|
+
if (currentDepth < depth) {
|
|
289
|
+
const nextId = rel.from === id ? rel.to : rel.from;
|
|
290
|
+
await traverse(nextId, currentDepth + 1);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
await traverse(entityId, 0);
|
|
295
|
+
return {
|
|
296
|
+
nodes: Array.from(graph.nodes.values()),
|
|
297
|
+
edges: graph.edges
|
|
298
|
+
};
|
|
299
|
+
};
|
|
300
|
+
// List all entities of a specific type
|
|
301
|
+
this.vfs.listEntities = async (query) => {
|
|
302
|
+
return await this.entitySystem.findEntity(query || {});
|
|
303
|
+
};
|
|
304
|
+
// Find files by concept
|
|
305
|
+
this.vfs.findByConcept = async (conceptName) => {
|
|
306
|
+
const paths = [];
|
|
307
|
+
// First find the concept
|
|
308
|
+
const concepts = await this.conceptSystem.findConcepts({ name: conceptName });
|
|
309
|
+
if (concepts.length === 0) {
|
|
310
|
+
return paths;
|
|
311
|
+
}
|
|
312
|
+
const concept = concepts[0];
|
|
313
|
+
// Search for files that contain concept keywords
|
|
314
|
+
const searchTerms = [conceptName, ...(concept.keywords || [])].join(' ');
|
|
315
|
+
const searchResults = await this.brain.find({
|
|
316
|
+
query: searchTerms,
|
|
317
|
+
where: { vfsType: 'file' },
|
|
318
|
+
limit: 50
|
|
319
|
+
});
|
|
320
|
+
// Get unique paths
|
|
321
|
+
const pathSet = new Set();
|
|
322
|
+
for (const result of searchResults) {
|
|
323
|
+
if (result.entity?.metadata?.path) {
|
|
324
|
+
pathSet.add(result.entity.metadata.path);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
// Also check concept manifestations if stored
|
|
328
|
+
if (concept.manifestations) {
|
|
329
|
+
for (const manifestation of concept.manifestations) {
|
|
330
|
+
if (manifestation.filePath) {
|
|
331
|
+
pathSet.add(manifestation.filePath);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return Array.from(pathSet);
|
|
336
|
+
};
|
|
337
|
+
// Get timeline of events
|
|
338
|
+
this.vfs.getTimeline = async (options) => {
|
|
339
|
+
const fromTime = options?.from ? new Date(options.from).getTime() : Date.now() - 30 * 24 * 60 * 60 * 1000; // 30 days ago
|
|
340
|
+
const toTime = options?.to ? new Date(options.to).getTime() : Date.now();
|
|
341
|
+
const limit = options?.limit || 100;
|
|
342
|
+
// Get events from event recorder
|
|
343
|
+
const events = await this.eventRecorder.getEvents({
|
|
344
|
+
since: fromTime,
|
|
345
|
+
until: toTime,
|
|
346
|
+
types: options?.types,
|
|
347
|
+
limit
|
|
348
|
+
});
|
|
349
|
+
// Transform to timeline format
|
|
350
|
+
return events.map(event => ({
|
|
351
|
+
timestamp: new Date(event.timestamp),
|
|
352
|
+
type: event.type,
|
|
353
|
+
path: event.path,
|
|
354
|
+
user: event.author,
|
|
355
|
+
description: `${event.type} ${event.path}${event.oldPath ? ` (from ${event.oldPath})` : ''}`
|
|
356
|
+
}));
|
|
357
|
+
};
|
|
358
|
+
// Get collaboration history for a file
|
|
359
|
+
this.vfs.getCollaborationHistory = async (path) => {
|
|
360
|
+
// Get all events for this path
|
|
361
|
+
const history = await this.eventRecorder.getHistory(path, { limit: 100 });
|
|
362
|
+
return history.map(event => ({
|
|
363
|
+
user: event.author || 'system',
|
|
364
|
+
timestamp: new Date(event.timestamp),
|
|
365
|
+
action: event.type,
|
|
366
|
+
size: event.size
|
|
367
|
+
}));
|
|
368
|
+
};
|
|
369
|
+
// Export to markdown format
|
|
370
|
+
this.vfs.exportToMarkdown = async (path) => {
|
|
371
|
+
const markdown = [];
|
|
372
|
+
const traverse = async (currentPath, depth = 0) => {
|
|
373
|
+
const indent = ' '.repeat(depth);
|
|
374
|
+
try {
|
|
375
|
+
const stats = await this.vfs.stat(currentPath);
|
|
376
|
+
if (stats.isDirectory()) {
|
|
377
|
+
// Add directory header
|
|
378
|
+
const name = currentPath.split('/').pop() || currentPath;
|
|
379
|
+
markdown.push(`${indent}## ${name}/`);
|
|
380
|
+
markdown.push('');
|
|
381
|
+
// List and traverse children
|
|
382
|
+
const children = await this.vfs.readdir(currentPath);
|
|
383
|
+
for (const child of children.sort()) {
|
|
384
|
+
const childPath = currentPath === '/' ? `/${child}` : `${currentPath}/${child}`;
|
|
385
|
+
await traverse(childPath, depth + 1);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
// Add file content
|
|
390
|
+
const name = currentPath.split('/').pop() || currentPath;
|
|
391
|
+
const extension = name.split('.').pop() || 'txt';
|
|
392
|
+
try {
|
|
393
|
+
const content = await this.vfs.readFile(currentPath);
|
|
394
|
+
const textContent = content.toString('utf8');
|
|
395
|
+
markdown.push(`${indent}### ${name}`);
|
|
396
|
+
markdown.push('');
|
|
397
|
+
// Add code block for code files
|
|
398
|
+
if (['js', 'ts', 'jsx', 'tsx', 'py', 'java', 'cpp', 'go', 'rs', 'json'].includes(extension)) {
|
|
399
|
+
markdown.push(`${indent}\`\`\`${extension}`);
|
|
400
|
+
markdown.push(textContent.split('\n').map(line => `${indent}${line}`).join('\n'));
|
|
401
|
+
markdown.push(`${indent}\`\`\``);
|
|
402
|
+
}
|
|
403
|
+
else if (extension === 'md') {
|
|
404
|
+
// Include markdown directly
|
|
405
|
+
markdown.push(textContent);
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
// Plain text in quotes
|
|
409
|
+
markdown.push(`${indent}> ${textContent.split('\n').join(`\n${indent}> `)}`);
|
|
410
|
+
}
|
|
411
|
+
markdown.push('');
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
markdown.push(`${indent}*Binary or unreadable file*`);
|
|
415
|
+
markdown.push('');
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
catch (error) {
|
|
420
|
+
// Skip inaccessible paths
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
await traverse(path);
|
|
424
|
+
return markdown.join('\n');
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Disable Knowledge Layer
|
|
429
|
+
*/
|
|
430
|
+
async disable() {
|
|
431
|
+
// Would restore original methods here
|
|
432
|
+
this.enabled = false;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Enable Knowledge Layer on a VFS instance
|
|
437
|
+
*/
|
|
438
|
+
export async function enableKnowledgeLayer(vfs, brain) {
|
|
439
|
+
const knowledgeLayer = new KnowledgeLayer(vfs, brain);
|
|
440
|
+
await knowledgeLayer.enable();
|
|
441
|
+
return knowledgeLayer;
|
|
442
|
+
}
|
|
443
|
+
//# sourceMappingURL=KnowledgeLayer.js.map
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent Entity System for VFS
|
|
3
|
+
*
|
|
4
|
+
* Manages entities that evolve across files and time
|
|
5
|
+
* Not just story characters - any evolving entity: APIs, customers, services, models
|
|
6
|
+
* PRODUCTION-READY: Real implementation using Brainy
|
|
7
|
+
*/
|
|
8
|
+
import { Brainy } from '../brainy.js';
|
|
9
|
+
import { EntityManager, ManagedEntity } from './EntityManager.js';
|
|
10
|
+
/**
|
|
11
|
+
* Persistent entity that exists across files and evolves over time
|
|
12
|
+
*/
|
|
13
|
+
export interface PersistentEntity extends ManagedEntity {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
type: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
aliases: string[];
|
|
19
|
+
appearances: EntityAppearance[];
|
|
20
|
+
attributes: Record<string, any>;
|
|
21
|
+
created: number;
|
|
22
|
+
lastUpdated: number;
|
|
23
|
+
version: number;
|
|
24
|
+
entityType?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* An appearance of an entity in a specific file/location
|
|
28
|
+
*/
|
|
29
|
+
export interface EntityAppearance extends ManagedEntity {
|
|
30
|
+
id: string;
|
|
31
|
+
entityId: string;
|
|
32
|
+
filePath: string;
|
|
33
|
+
context: string;
|
|
34
|
+
position?: {
|
|
35
|
+
line?: number;
|
|
36
|
+
column?: number;
|
|
37
|
+
offset?: number;
|
|
38
|
+
};
|
|
39
|
+
timestamp: number;
|
|
40
|
+
version: number;
|
|
41
|
+
changes?: EntityChange[];
|
|
42
|
+
confidence: number;
|
|
43
|
+
eventType?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A change/evolution to an entity
|
|
47
|
+
*/
|
|
48
|
+
export interface EntityChange {
|
|
49
|
+
field: string;
|
|
50
|
+
oldValue: any;
|
|
51
|
+
newValue: any;
|
|
52
|
+
timestamp: number;
|
|
53
|
+
source: string;
|
|
54
|
+
reason?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Configuration for persistent entities
|
|
58
|
+
*/
|
|
59
|
+
export interface PersistentEntityConfig {
|
|
60
|
+
autoExtract?: boolean;
|
|
61
|
+
similarityThreshold?: number;
|
|
62
|
+
maxAppearances?: number;
|
|
63
|
+
evolutionTracking?: boolean;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Persistent Entity System
|
|
67
|
+
*
|
|
68
|
+
* Tracks entities that exist across multiple files and evolve over time
|
|
69
|
+
* Examples:
|
|
70
|
+
* - Story characters that appear in multiple chapters
|
|
71
|
+
* - API endpoints that evolve across documentation
|
|
72
|
+
* - Business entities that appear in multiple reports
|
|
73
|
+
* - Code classes/functions that span multiple files
|
|
74
|
+
*/
|
|
75
|
+
export declare class PersistentEntitySystem extends EntityManager {
|
|
76
|
+
private config;
|
|
77
|
+
private entityCache;
|
|
78
|
+
constructor(brain: Brainy, config?: PersistentEntityConfig);
|
|
79
|
+
/**
|
|
80
|
+
* Create a new persistent entity
|
|
81
|
+
*/
|
|
82
|
+
createEntity(entity: Omit<PersistentEntity, 'id' | 'created' | 'lastUpdated' | 'version' | 'appearances'>): Promise<string>;
|
|
83
|
+
/**
|
|
84
|
+
* Find an existing entity by name or attributes
|
|
85
|
+
*/
|
|
86
|
+
findEntity(query: {
|
|
87
|
+
name?: string;
|
|
88
|
+
type?: string;
|
|
89
|
+
attributes?: Record<string, any>;
|
|
90
|
+
similar?: string;
|
|
91
|
+
}): Promise<PersistentEntity[]>;
|
|
92
|
+
/**
|
|
93
|
+
* Record an appearance of an entity in a file
|
|
94
|
+
*/
|
|
95
|
+
recordAppearance(entityId: string, filePath: string, context: string, options?: {
|
|
96
|
+
position?: EntityAppearance['position'];
|
|
97
|
+
confidence?: number;
|
|
98
|
+
extractChanges?: boolean;
|
|
99
|
+
}): Promise<string>;
|
|
100
|
+
/**
|
|
101
|
+
* Get entity evolution history
|
|
102
|
+
*/
|
|
103
|
+
getEvolution(entityId: string): Promise<{
|
|
104
|
+
entity: PersistentEntity;
|
|
105
|
+
timeline: Array<{
|
|
106
|
+
timestamp: number;
|
|
107
|
+
version: number;
|
|
108
|
+
changes: EntityChange[];
|
|
109
|
+
appearance?: EntityAppearance;
|
|
110
|
+
}>;
|
|
111
|
+
}>;
|
|
112
|
+
/**
|
|
113
|
+
* Find all appearances of an entity
|
|
114
|
+
*/
|
|
115
|
+
findAppearances(entityId: string, options?: {
|
|
116
|
+
filePath?: string;
|
|
117
|
+
since?: number;
|
|
118
|
+
until?: number;
|
|
119
|
+
minConfidence?: number;
|
|
120
|
+
}): Promise<EntityAppearance[]>;
|
|
121
|
+
/**
|
|
122
|
+
* Evolve an entity with new information
|
|
123
|
+
*/
|
|
124
|
+
evolveEntity(entityId: string, updates: Partial<Pick<PersistentEntity, 'name' | 'description' | 'aliases' | 'attributes'>>, source: string, reason?: string): Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* Extract entities from content (auto-extraction)
|
|
127
|
+
*/
|
|
128
|
+
extractEntities(filePath: string, content: Buffer): Promise<string[]>;
|
|
129
|
+
/**
|
|
130
|
+
* Update references when a file moves
|
|
131
|
+
*/
|
|
132
|
+
updateReferences(oldPath: string, newPath: string): Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* Get persistent entity by ID
|
|
135
|
+
*/
|
|
136
|
+
getPersistentEntity(entityId: string): Promise<PersistentEntity | null>;
|
|
137
|
+
/**
|
|
138
|
+
* Update stored entity (rename to avoid parent method conflict)
|
|
139
|
+
*/
|
|
140
|
+
private updatePersistentEntity;
|
|
141
|
+
/**
|
|
142
|
+
* Detect changes in entity from context
|
|
143
|
+
*/
|
|
144
|
+
private detectChanges;
|
|
145
|
+
/**
|
|
146
|
+
* Generate embedding for entity
|
|
147
|
+
*/
|
|
148
|
+
private generateEntityEmbedding;
|
|
149
|
+
/**
|
|
150
|
+
* Generate embedding for text
|
|
151
|
+
*/
|
|
152
|
+
private generateTextEmbedding;
|
|
153
|
+
/**
|
|
154
|
+
* Detect entity type from name and context
|
|
155
|
+
*/
|
|
156
|
+
private detectEntityType;
|
|
157
|
+
/**
|
|
158
|
+
* Extract context around a position
|
|
159
|
+
*/
|
|
160
|
+
private extractContext;
|
|
161
|
+
/**
|
|
162
|
+
* Clear entity cache
|
|
163
|
+
*/
|
|
164
|
+
clearCache(entityId?: string): void;
|
|
165
|
+
}
|