@soulcraft/brainy 5.2.1 → 5.3.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.
@@ -0,0 +1,275 @@
1
+ /**
2
+ * VersionIndex - Fast Version Lookup Using Existing Index Infrastructure (v5.3.0)
3
+ *
4
+ * Integrates with Brainy's existing index system:
5
+ * - Uses MetadataIndexManager for field indexing
6
+ * - Leverages UnifiedCache for memory management
7
+ * - Uses EntityIdMapper for efficient ID handling
8
+ * - Uses ChunkManager for adaptive chunking
9
+ * - Leverages Roaring Bitmaps for fast set operations
10
+ *
11
+ * Version metadata is stored as regular entities with type='_version'
12
+ * This allows us to use existing index infrastructure without modification!
13
+ *
14
+ * Fields indexed:
15
+ * - versionEntityId: Entity being versioned
16
+ * - versionBranch: Branch version was created on
17
+ * - versionNumber: Version number
18
+ * - versionTag: Optional user tag
19
+ * - versionTimestamp: Creation timestamp
20
+ * - versionCommitHash: Commit hash
21
+ *
22
+ * NO MOCKS - Production implementation
23
+ */
24
+ /**
25
+ * VersionIndex - Version lookup and querying using existing indexes
26
+ *
27
+ * Strategy: Store version metadata as special entities with type='_version'
28
+ * This leverages ALL existing index infrastructure automatically!
29
+ */
30
+ export class VersionIndex {
31
+ constructor(brain) {
32
+ this.initialized = false;
33
+ this.brain = brain;
34
+ }
35
+ /**
36
+ * Initialize version index
37
+ *
38
+ * No special setup needed - we use existing entity storage and indexes!
39
+ */
40
+ async initialize() {
41
+ if (this.initialized)
42
+ return;
43
+ this.initialized = true;
44
+ }
45
+ /**
46
+ * Add version to index
47
+ *
48
+ * Stores version metadata as a special entity with type='_version'
49
+ * This automatically indexes it using existing MetadataIndexManager!
50
+ *
51
+ * @param version Version metadata
52
+ */
53
+ async addVersion(version) {
54
+ await this.initialize();
55
+ // Generate unique ID for version entity
56
+ const versionEntityId = this.getVersionEntityId(version.entityId, version.version, version.branch);
57
+ // Store as special entity with type='state' (version is a snapshot/state)
58
+ // This automatically gets indexed by MetadataIndexManager!
59
+ await this.brain.saveNounMetadata(versionEntityId, {
60
+ id: versionEntityId,
61
+ type: 'state', // Use standard 'state' type (version = snapshot state)
62
+ name: `Version ${version.version} of ${version.entityId}`,
63
+ metadata: {
64
+ // Flag to identify as version metadata
65
+ _isVersion: true,
66
+ // These fields are automatically indexed by MetadataIndexManager
67
+ versionEntityId: version.entityId, // Entity being versioned
68
+ versionBranch: version.branch, // Branch
69
+ versionNumber: version.version, // Version number
70
+ versionTag: version.tag, // Optional tag
71
+ versionTimestamp: version.timestamp, // Timestamp (indexed with bucketing)
72
+ versionCommitHash: version.commitHash, // Commit hash
73
+ versionContentHash: version.contentHash, // Content hash
74
+ versionAuthor: version.author, // Author
75
+ versionDescription: version.description, // Description
76
+ versionMetadata: version.metadata // Additional metadata
77
+ }
78
+ });
79
+ }
80
+ /**
81
+ * Get versions for an entity
82
+ *
83
+ * Uses existing MetadataIndexManager to query efficiently!
84
+ *
85
+ * @param query Version query
86
+ * @returns List of versions (newest first)
87
+ */
88
+ async getVersions(query) {
89
+ await this.initialize();
90
+ // Build metadata filter using existing query system
91
+ const filters = {
92
+ type: 'state',
93
+ _isVersion: true,
94
+ versionEntityId: query.entityId,
95
+ versionBranch: query.branch
96
+ };
97
+ // Add optional filters
98
+ if (query.tag) {
99
+ filters.versionTag = query.tag;
100
+ }
101
+ // Query using existing search infrastructure
102
+ const results = await this.brain.searchByMetadata(filters);
103
+ // Convert entities back to EntityVersion format
104
+ const versions = [];
105
+ for (const entity of results) {
106
+ const version = this.entityToVersion(entity);
107
+ if (version) {
108
+ // Filter by date range if specified
109
+ if (query.startDate && version.timestamp < query.startDate)
110
+ continue;
111
+ if (query.endDate && version.timestamp > query.endDate)
112
+ continue;
113
+ versions.push(version);
114
+ }
115
+ }
116
+ // Sort by version number (newest first)
117
+ versions.sort((a, b) => b.version - a.version);
118
+ // Apply pagination
119
+ const start = query.offset || 0;
120
+ const end = query.limit ? start + query.limit : undefined;
121
+ return versions.slice(start, end);
122
+ }
123
+ /**
124
+ * Get specific version
125
+ *
126
+ * @param entityId Entity ID
127
+ * @param version Version number
128
+ * @param branch Branch name
129
+ * @returns Version metadata or null
130
+ */
131
+ async getVersion(entityId, version, branch) {
132
+ await this.initialize();
133
+ const versionEntityId = this.getVersionEntityId(entityId, version, branch);
134
+ const entity = await this.brain.getNounMetadata(versionEntityId);
135
+ if (!entity)
136
+ return null;
137
+ return this.entityToVersion(entity);
138
+ }
139
+ /**
140
+ * Get version by tag
141
+ *
142
+ * @param entityId Entity ID
143
+ * @param tag Version tag
144
+ * @param branch Branch name
145
+ * @returns Version metadata or null
146
+ */
147
+ async getVersionByTag(entityId, tag, branch) {
148
+ await this.initialize();
149
+ // Query using existing metadata index
150
+ const results = await this.brain.searchByMetadata({
151
+ type: 'state',
152
+ _isVersion: true,
153
+ versionEntityId: entityId,
154
+ versionBranch: branch,
155
+ versionTag: tag
156
+ });
157
+ if (results.length === 0)
158
+ return null;
159
+ // Return first match (tags should be unique per entity/branch)
160
+ return this.entityToVersion(results[0]);
161
+ }
162
+ /**
163
+ * Get version count for entity
164
+ *
165
+ * @param entityId Entity ID
166
+ * @param branch Branch name
167
+ * @returns Number of versions
168
+ */
169
+ async getVersionCount(entityId, branch) {
170
+ await this.initialize();
171
+ // Use existing search infrastructure
172
+ const results = await this.brain.searchByMetadata({
173
+ type: 'state',
174
+ _isVersion: true,
175
+ versionEntityId: entityId,
176
+ versionBranch: branch
177
+ });
178
+ return results.length;
179
+ }
180
+ /**
181
+ * Remove version from index
182
+ *
183
+ * @param entityId Entity ID
184
+ * @param version Version number
185
+ * @param branch Branch name
186
+ */
187
+ async removeVersion(entityId, version, branch) {
188
+ await this.initialize();
189
+ const versionEntityId = this.getVersionEntityId(entityId, version, branch);
190
+ // Delete version entity (automatically removed from indexes)
191
+ await this.brain.deleteNounMetadata(versionEntityId);
192
+ }
193
+ /**
194
+ * Convert entity to EntityVersion format
195
+ *
196
+ * @param entity Entity from storage
197
+ * @returns EntityVersion or null if invalid
198
+ */
199
+ entityToVersion(entity) {
200
+ if (!entity || !entity.metadata)
201
+ return null;
202
+ const m = entity.metadata;
203
+ if (!m.versionEntityId ||
204
+ !m.versionBranch ||
205
+ m.versionNumber === undefined ||
206
+ !m.versionCommitHash ||
207
+ !m.versionContentHash ||
208
+ !m.versionTimestamp) {
209
+ return null;
210
+ }
211
+ return {
212
+ version: m.versionNumber,
213
+ entityId: m.versionEntityId,
214
+ branch: m.versionBranch,
215
+ commitHash: m.versionCommitHash,
216
+ timestamp: m.versionTimestamp,
217
+ contentHash: m.versionContentHash,
218
+ tag: m.versionTag,
219
+ description: m.versionDescription,
220
+ author: m.versionAuthor,
221
+ metadata: m.versionMetadata
222
+ };
223
+ }
224
+ /**
225
+ * Generate unique ID for version entity
226
+ *
227
+ * Format: _version:{entityId}:{version}:{branch}
228
+ *
229
+ * @param entityId Entity ID
230
+ * @param version Version number
231
+ * @param branch Branch name
232
+ * @returns Version entity ID
233
+ */
234
+ getVersionEntityId(entityId, version, branch) {
235
+ return `_version:${entityId}:${version}:${branch}`;
236
+ }
237
+ /**
238
+ * Get all versioned entities (for cleanup/debugging)
239
+ *
240
+ * @returns List of entity IDs that have versions
241
+ */
242
+ async getVersionedEntities() {
243
+ await this.initialize();
244
+ // Query all version entities
245
+ const results = await this.brain.searchByMetadata({
246
+ type: 'state',
247
+ _isVersion: true
248
+ });
249
+ // Extract unique entity IDs
250
+ const entityIds = new Set();
251
+ for (const entity of results) {
252
+ const version = this.entityToVersion(entity);
253
+ if (version) {
254
+ entityIds.add(version.entityId);
255
+ }
256
+ }
257
+ return Array.from(entityIds);
258
+ }
259
+ /**
260
+ * Clear all versions for an entity
261
+ *
262
+ * @param entityId Entity ID
263
+ * @param branch Branch name
264
+ * @returns Number of versions deleted
265
+ */
266
+ async clearVersions(entityId, branch) {
267
+ await this.initialize();
268
+ const versions = await this.getVersions({ entityId, branch });
269
+ for (const version of versions) {
270
+ await this.removeVersion(entityId, version.version, branch);
271
+ }
272
+ return versions.length;
273
+ }
274
+ }
275
+ //# sourceMappingURL=VersionIndex.js.map
@@ -0,0 +1,195 @@
1
+ /**
2
+ * VersionManager - Entity-Level Versioning Engine (v5.3.0)
3
+ *
4
+ * Provides entity-level version control with:
5
+ * - save() - Create entity version
6
+ * - restore() - Restore entity to specific version
7
+ * - list() - List all versions of an entity
8
+ * - compare() - Deep diff between versions
9
+ * - prune() - Remove old versions (retention policies)
10
+ *
11
+ * Architecture:
12
+ * - Hybrid storage: COW commits for full snapshots + version index for fast queries
13
+ * - Content-addressable: SHA-256 hashing for deduplication
14
+ * - Space-efficient: Only stores changed data
15
+ * - Branch-aware: Versions tied to current branch
16
+ *
17
+ * NO MOCKS - Production implementation
18
+ */
19
+ import { VersionDiff } from './VersionDiff.js';
20
+ export interface EntityVersion {
21
+ /** Version number (1-indexed, sequential per entity) */
22
+ version: number;
23
+ /** Entity ID */
24
+ entityId: string;
25
+ /** Branch this version was created on */
26
+ branch: string;
27
+ /** Commit hash containing this version */
28
+ commitHash: string;
29
+ /** Timestamp of version creation */
30
+ timestamp: number;
31
+ /** Optional user-provided tag (e.g., 'v1.0', 'before-refactor') */
32
+ tag?: string;
33
+ /** Optional description */
34
+ description?: string;
35
+ /** Content hash (SHA-256 of entity data) */
36
+ contentHash: string;
37
+ /** Author of this version */
38
+ author?: string;
39
+ /** Metadata about the version */
40
+ metadata?: Record<string, any>;
41
+ }
42
+ export interface VersionQuery {
43
+ /** Entity ID to query versions for */
44
+ entityId: string;
45
+ /** Optional: Filter by branch (default: current branch) */
46
+ branch?: string;
47
+ /** Optional: Limit number of versions returned */
48
+ limit?: number;
49
+ /** Optional: Skip first N versions */
50
+ offset?: number;
51
+ /** Optional: Filter by tag */
52
+ tag?: string;
53
+ /** Optional: Filter by date range */
54
+ startDate?: number;
55
+ endDate?: number;
56
+ }
57
+ export interface SaveVersionOptions {
58
+ /** Optional tag for this version (e.g., 'v1.0', 'milestone-1') */
59
+ tag?: string;
60
+ /** Optional description */
61
+ description?: string;
62
+ /** Optional author name */
63
+ author?: string;
64
+ /** Optional custom metadata */
65
+ metadata?: Record<string, any>;
66
+ /** Optional: Create commit automatically (default: false) */
67
+ createCommit?: boolean;
68
+ /** Optional: Commit message if createCommit is true */
69
+ commitMessage?: string;
70
+ }
71
+ export interface RestoreOptions {
72
+ /** Optional: Create version before restoring (for undo) */
73
+ createSnapshot?: boolean;
74
+ /** Optional: Tag for snapshot before restore */
75
+ snapshotTag?: string;
76
+ }
77
+ export interface PruneOptions {
78
+ /** Keep N most recent versions (required if keepVersions not set) */
79
+ keepRecent?: number;
80
+ /** Keep versions newer than timestamp (optional) */
81
+ keepAfter?: number;
82
+ /** Keep tagged versions (default: true) */
83
+ keepTagged?: boolean;
84
+ /** Dry run - don't actually delete (default: false) */
85
+ dryRun?: boolean;
86
+ }
87
+ /**
88
+ * VersionManager - Core versioning engine
89
+ */
90
+ export declare class VersionManager {
91
+ private brain;
92
+ private versionStorage;
93
+ private versionIndex;
94
+ private initialized;
95
+ constructor(brain: any);
96
+ /**
97
+ * Initialize versioning system (lazy)
98
+ */
99
+ initialize(): Promise<void>;
100
+ /**
101
+ * Save a version of an entity
102
+ *
103
+ * Creates a version snapshot of the current entity state.
104
+ * If createCommit is true, also creates a commit containing this version.
105
+ *
106
+ * @param entityId Entity ID to version
107
+ * @param options Save options
108
+ * @returns Created version metadata
109
+ */
110
+ save(entityId: string, options?: SaveVersionOptions): Promise<EntityVersion>;
111
+ /**
112
+ * Get all versions of an entity
113
+ *
114
+ * @param entityId Entity ID
115
+ * @param query Optional query filters
116
+ * @returns List of versions (newest first)
117
+ */
118
+ list(entityId: string, query?: Partial<VersionQuery>): Promise<EntityVersion[]>;
119
+ /**
120
+ * Get a specific version of an entity
121
+ *
122
+ * @param entityId Entity ID
123
+ * @param version Version number (1-indexed)
124
+ * @returns Version metadata
125
+ */
126
+ getVersion(entityId: string, version: number): Promise<EntityVersion | null>;
127
+ /**
128
+ * Get version by tag
129
+ *
130
+ * @param entityId Entity ID
131
+ * @param tag Version tag
132
+ * @returns Version metadata
133
+ */
134
+ getVersionByTag(entityId: string, tag: string): Promise<EntityVersion | null>;
135
+ /**
136
+ * Restore entity to a specific version
137
+ *
138
+ * Overwrites current entity state with the specified version.
139
+ * Optionally creates a snapshot before restoring for undo capability.
140
+ *
141
+ * @param entityId Entity ID
142
+ * @param version Version number or tag
143
+ * @param options Restore options
144
+ * @returns Restored version metadata
145
+ */
146
+ restore(entityId: string, version: number | string, options?: RestoreOptions): Promise<EntityVersion>;
147
+ /**
148
+ * Compare two versions of an entity
149
+ *
150
+ * @param entityId Entity ID
151
+ * @param fromVersion Version number or tag (older)
152
+ * @param toVersion Version number or tag (newer)
153
+ * @returns Diff between versions
154
+ */
155
+ compare(entityId: string, fromVersion: number | string, toVersion: number | string): Promise<VersionDiff>;
156
+ /**
157
+ * Prune old versions based on retention policy
158
+ *
159
+ * @param entityId Entity ID (or '*' for all entities)
160
+ * @param options Prune options
161
+ * @returns Number of versions deleted
162
+ */
163
+ prune(entityId: string, options: PruneOptions): Promise<{
164
+ deleted: number;
165
+ kept: number;
166
+ }>;
167
+ /**
168
+ * Get version count for an entity
169
+ *
170
+ * @param entityId Entity ID
171
+ * @returns Number of versions
172
+ */
173
+ getVersionCount(entityId: string): Promise<number>;
174
+ /**
175
+ * Check if entity has versions
176
+ *
177
+ * @param entityId Entity ID
178
+ * @returns True if entity has versions
179
+ */
180
+ hasVersions(entityId: string): Promise<boolean>;
181
+ /**
182
+ * Get latest version of an entity
183
+ *
184
+ * @param entityId Entity ID
185
+ * @returns Latest version metadata or null
186
+ */
187
+ getLatest(entityId: string): Promise<EntityVersion | null>;
188
+ /**
189
+ * Clear all versions for an entity
190
+ *
191
+ * @param entityId Entity ID
192
+ * @returns Number of versions deleted
193
+ */
194
+ clear(entityId: string): Promise<number>;
195
+ }