@soulcraft/brainy 3.9.0 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -33
- package/dist/augmentations/KnowledgeAugmentation.d.ts +40 -0
- package/dist/augmentations/KnowledgeAugmentation.js +251 -0
- package/dist/augmentations/defaultAugmentations.d.ts +1 -0
- package/dist/augmentations/defaultAugmentations.js +5 -0
- package/dist/brainy.d.ts +11 -0
- package/dist/brainy.js +87 -1
- package/dist/embeddings/EmbeddingManager.js +14 -2
- package/dist/utils/mutex.d.ts +2 -0
- package/dist/utils/mutex.js +14 -3
- package/dist/vfs/ConceptSystem.d.ts +202 -0
- package/dist/vfs/ConceptSystem.js +598 -0
- package/dist/vfs/EntityManager.d.ts +75 -0
- package/dist/vfs/EntityManager.js +216 -0
- package/dist/vfs/EventRecorder.d.ts +83 -0
- package/dist/vfs/EventRecorder.js +292 -0
- package/dist/vfs/FSCompat.d.ts +85 -0
- package/dist/vfs/FSCompat.js +257 -0
- package/dist/vfs/GitBridge.d.ts +167 -0
- package/dist/vfs/GitBridge.js +537 -0
- package/dist/vfs/KnowledgeAugmentation.d.ts +104 -0
- package/dist/vfs/KnowledgeAugmentation.js +146 -0
- package/dist/vfs/KnowledgeLayer.d.ts +35 -0
- package/dist/vfs/KnowledgeLayer.js +443 -0
- package/dist/vfs/PathResolver.d.ts +96 -0
- package/dist/vfs/PathResolver.js +362 -0
- package/dist/vfs/PersistentEntitySystem.d.ts +163 -0
- package/dist/vfs/PersistentEntitySystem.js +525 -0
- package/dist/vfs/SemanticVersioning.d.ts +105 -0
- package/dist/vfs/SemanticVersioning.js +318 -0
- package/dist/vfs/VirtualFileSystem.d.ts +246 -0
- package/dist/vfs/VirtualFileSystem.js +1927 -0
- package/dist/vfs/importers/DirectoryImporter.d.ts +86 -0
- package/dist/vfs/importers/DirectoryImporter.js +298 -0
- package/dist/vfs/index.d.ts +19 -0
- package/dist/vfs/index.js +26 -0
- package/dist/vfs/streams/VFSReadStream.d.ts +19 -0
- package/dist/vfs/streams/VFSReadStream.js +54 -0
- package/dist/vfs/streams/VFSWriteStream.d.ts +21 -0
- package/dist/vfs/streams/VFSWriteStream.js +70 -0
- package/dist/vfs/types.d.ts +330 -0
- package/dist/vfs/types.js +46 -0
- package/package.json +1 -1
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge Augmentation
|
|
3
|
+
*
|
|
4
|
+
* Main orchestrator for the Knowledge Layer that coordinates all knowledge systems
|
|
5
|
+
* and enhances the VFS with intelligent capabilities
|
|
6
|
+
*/
|
|
7
|
+
import crypto from 'crypto';
|
|
8
|
+
import { EventRecorder } from './EventRecorder.js';
|
|
9
|
+
import { SemanticVersioning } from './SemanticVersioning.js';
|
|
10
|
+
import { PersistentEntitySystem } from './PersistentEntitySystem.js';
|
|
11
|
+
import { ConceptSystem } from './ConceptSystem.js';
|
|
12
|
+
import { GitBridge } from './GitBridge.js';
|
|
13
|
+
export class KnowledgeAugmentation {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.enabled = false;
|
|
16
|
+
this.config = config;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Initialize the Knowledge Augmentation with Brainy instance
|
|
20
|
+
*/
|
|
21
|
+
async init(brain, vfs) {
|
|
22
|
+
this.brain = brain;
|
|
23
|
+
this.vfs = vfs;
|
|
24
|
+
if (!this.config.enabled) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// Initialize sub-systems
|
|
28
|
+
if (this.config.eventRecording?.enabled) {
|
|
29
|
+
this.eventRecorder = new EventRecorder(this.brain);
|
|
30
|
+
}
|
|
31
|
+
if (this.config.semanticVersioning?.enabled !== false) {
|
|
32
|
+
this.semanticVersioning = new SemanticVersioning(this.brain);
|
|
33
|
+
}
|
|
34
|
+
if (this.config.entitySystem?.enabled !== false) {
|
|
35
|
+
this.entitySystem = new PersistentEntitySystem(this.brain);
|
|
36
|
+
}
|
|
37
|
+
if (this.config.conceptSystem?.enabled !== false) {
|
|
38
|
+
this.conceptSystem = new ConceptSystem(this.brain);
|
|
39
|
+
}
|
|
40
|
+
if (this.config.gitBridge?.enabled !== false) {
|
|
41
|
+
this.gitBridge = new GitBridge(this.brain, this.vfs);
|
|
42
|
+
}
|
|
43
|
+
this.enabled = true;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Enable the Knowledge Augmentation
|
|
47
|
+
*/
|
|
48
|
+
async enable() {
|
|
49
|
+
if (!this.brain || !this.vfs) {
|
|
50
|
+
throw new Error('Knowledge augmentation not initialized. Call init() first.');
|
|
51
|
+
}
|
|
52
|
+
this.enabled = true;
|
|
53
|
+
// Enhance VFS with knowledge methods
|
|
54
|
+
this.enhanceVFS();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Disable the Knowledge Augmentation
|
|
58
|
+
*/
|
|
59
|
+
async disable() {
|
|
60
|
+
this.enabled = false;
|
|
61
|
+
// Remove VFS enhancements if any were added
|
|
62
|
+
// For now, just mark as disabled
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if the knowledge augmentation is enabled
|
|
66
|
+
*/
|
|
67
|
+
isEnabled() {
|
|
68
|
+
return this.enabled;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get the EventRecorder instance
|
|
72
|
+
*/
|
|
73
|
+
getEventRecorder() {
|
|
74
|
+
return this.eventRecorder;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get the SemanticVersioning instance
|
|
78
|
+
*/
|
|
79
|
+
getSemanticVersioning() {
|
|
80
|
+
return this.semanticVersioning;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get the PersistentEntitySystem instance
|
|
84
|
+
*/
|
|
85
|
+
getEntitySystem() {
|
|
86
|
+
return this.entitySystem;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get the ConceptSystem instance
|
|
90
|
+
*/
|
|
91
|
+
getConceptSystem() {
|
|
92
|
+
return this.conceptSystem;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get the GitBridge instance
|
|
96
|
+
*/
|
|
97
|
+
getGitBridge() {
|
|
98
|
+
return this.gitBridge;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Record a file event (called by VFS)
|
|
102
|
+
*/
|
|
103
|
+
async recordEvent(type, path, metadata) {
|
|
104
|
+
if (!this.enabled || !this.eventRecorder)
|
|
105
|
+
return;
|
|
106
|
+
await this.eventRecorder.recordEvent({
|
|
107
|
+
id: crypto.randomUUID(),
|
|
108
|
+
timestamp: Date.now(),
|
|
109
|
+
type,
|
|
110
|
+
path,
|
|
111
|
+
metadata
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Create a semantic version (called by VFS)
|
|
116
|
+
*/
|
|
117
|
+
async createVersion(path, content) {
|
|
118
|
+
if (!this.enabled || !this.semanticVersioning)
|
|
119
|
+
return;
|
|
120
|
+
await this.semanticVersioning.createVersion(path, content);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Extract entities from content (called by VFS)
|
|
124
|
+
*/
|
|
125
|
+
async extractEntities(path, content) {
|
|
126
|
+
if (!this.enabled || !this.entitySystem)
|
|
127
|
+
return;
|
|
128
|
+
await this.entitySystem.extractEntities(content, { sourcePath: path });
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Extract concepts from content (called by VFS)
|
|
132
|
+
*/
|
|
133
|
+
async extractConcepts(path, content) {
|
|
134
|
+
if (!this.enabled || !this.conceptSystem)
|
|
135
|
+
return;
|
|
136
|
+
await this.conceptSystem.extractConcepts(content, { sourcePath: path });
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Enhance the VFS with knowledge methods
|
|
140
|
+
*/
|
|
141
|
+
enhanceVFS() {
|
|
142
|
+
// For now, the VFS calls the knowledge methods directly
|
|
143
|
+
// In the future, we could add methods to the VFS prototype
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=KnowledgeAugmentation.js.map
|
|
@@ -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
|