@soulcraft/brainy 5.2.1 → 5.3.1

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 CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [5.3.0](https://github.com/soulcraftlabs/brainy/compare/v5.2.1...v5.3.0) (2025-11-04)
6
+
7
+ - feat: add entity versioning system with critical bug fixes (v5.3.0) (c488fa8)
8
+
9
+
5
10
  ### [5.2.0](https://github.com/soulcraftlabs/brainy/compare/v5.1.2...v5.2.0) (2025-11-03)
6
11
 
7
12
  - fix: update VFS test for v5.2.0 BlobStorage architecture (b3e3e5c)
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Versioning Augmentation (v5.3.0)
3
+ *
4
+ * Provides automatic entity versioning with configurable policies:
5
+ * - Auto-save on update()
6
+ * - Entity filtering
7
+ * - Retention policies
8
+ * - Event hooks
9
+ *
10
+ * NO MOCKS - Production implementation
11
+ */
12
+ import { BaseAugmentation } from './brainyAugmentation.js';
13
+ import { AugmentationManifest } from './manifest.js';
14
+ import type { SaveVersionOptions } from '../versioning/VersionManager.js';
15
+ export interface VersioningAugmentationConfig {
16
+ /** Enable auto-versioning */
17
+ enabled?: boolean;
18
+ /** Auto-save on update() operations */
19
+ onUpdate?: boolean;
20
+ /** Auto-save on add() operations (rarely needed) */
21
+ onAdd?: boolean;
22
+ /** Entity ID patterns to version (glob patterns) */
23
+ entities?: string[];
24
+ /** Entity ID patterns to exclude (glob patterns) */
25
+ excludeEntities?: string[];
26
+ /** Entity types to version */
27
+ types?: string[];
28
+ /** Entity types to exclude */
29
+ excludeTypes?: string[];
30
+ /** Retention policy: Keep N recent versions per entity */
31
+ keepRecent?: number;
32
+ /** Retention policy: Keep versions newer than timestamp */
33
+ keepAfter?: number;
34
+ /** Retention policy: Keep tagged versions (default: true) */
35
+ keepTagged?: boolean;
36
+ /** Tag prefix for auto-generated versions (default: 'auto-') */
37
+ tagPrefix?: string;
38
+ /** Auto-prune old versions after save */
39
+ autoPrune?: boolean;
40
+ /** Prune interval in milliseconds (default: 1 hour) */
41
+ pruneInterval?: number;
42
+ /** Event hooks */
43
+ hooks?: {
44
+ /** Called before saving version */
45
+ beforeSave?: (entityId: string, options: SaveVersionOptions) => Promise<SaveVersionOptions | null>;
46
+ /** Called after saving version */
47
+ afterSave?: (entityId: string, version: any) => Promise<void>;
48
+ /** Called before pruning */
49
+ beforePrune?: (entityId: string) => Promise<boolean>;
50
+ /** Called after pruning */
51
+ afterPrune?: (entityId: string, deleted: number) => Promise<void>;
52
+ };
53
+ }
54
+ /**
55
+ * Versioning Augmentation
56
+ *
57
+ * Automatically versions entities based on configurable policies.
58
+ */
59
+ export declare class VersioningAugmentation extends BaseAugmentation {
60
+ readonly name = "versioning";
61
+ readonly timing: "after";
62
+ readonly metadata: "readonly";
63
+ operations: any;
64
+ readonly priority = 50;
65
+ readonly category: "core";
66
+ readonly description = "Automatic entity versioning with configurable retention policies";
67
+ private versioningAPI?;
68
+ private brain?;
69
+ private pruneTimer?;
70
+ private versionCount;
71
+ constructor(config?: VersioningAugmentationConfig);
72
+ getManifest(): AugmentationManifest;
73
+ onAttach(brain: any): Promise<void>;
74
+ onDetach(): Promise<void>;
75
+ /**
76
+ * Execute method (required by BaseAugmentation)
77
+ */
78
+ execute(operation: string, params: any[], context: any): Promise<any>;
79
+ /**
80
+ * After operation hook - auto-save versions
81
+ */
82
+ after(operation: string, params: any[], result: any): Promise<any>;
83
+ /**
84
+ * Extract entity ID from operation params
85
+ */
86
+ private extractEntityId;
87
+ /**
88
+ * Check if entity should be versioned based on filters
89
+ */
90
+ private shouldVersionEntity;
91
+ /**
92
+ * Simple glob pattern matching
93
+ */
94
+ private matchPattern;
95
+ /**
96
+ * Prune old versions for an entity
97
+ */
98
+ private pruneEntity;
99
+ /**
100
+ * Start auto-prune timer
101
+ */
102
+ private startAutoPrune;
103
+ /**
104
+ * Prune all versioned entities
105
+ */
106
+ private pruneAllEntities;
107
+ /**
108
+ * Get augmentation statistics
109
+ */
110
+ getStats(): {
111
+ enabled: boolean;
112
+ versionsCreated: number;
113
+ entitiesPattern: string[];
114
+ excludePattern: string[];
115
+ retention: number;
116
+ };
117
+ }
118
+ /**
119
+ * Factory function for easy augmentation creation
120
+ */
121
+ export declare function createVersioningAugmentation(config?: VersioningAugmentationConfig): VersioningAugmentation;
@@ -0,0 +1,418 @@
1
+ /**
2
+ * Versioning Augmentation (v5.3.0)
3
+ *
4
+ * Provides automatic entity versioning with configurable policies:
5
+ * - Auto-save on update()
6
+ * - Entity filtering
7
+ * - Retention policies
8
+ * - Event hooks
9
+ *
10
+ * NO MOCKS - Production implementation
11
+ */
12
+ import { BaseAugmentation } from './brainyAugmentation.js';
13
+ /**
14
+ * Versioning Augmentation
15
+ *
16
+ * Automatically versions entities based on configurable policies.
17
+ */
18
+ export class VersioningAugmentation extends BaseAugmentation {
19
+ constructor(config = {}) {
20
+ super(config);
21
+ this.name = 'versioning';
22
+ this.timing = 'after'; // Run after operations complete
23
+ this.metadata = 'readonly';
24
+ this.operations = ['update', 'add']; // Version on update/add
25
+ this.priority = 50; // Medium priority
26
+ // Augmentation metadata
27
+ this.category = 'core';
28
+ this.description = 'Automatic entity versioning with configurable retention policies';
29
+ this.versionCount = 0;
30
+ // Merge with defaults
31
+ this.config = {
32
+ enabled: config.enabled ?? true,
33
+ onUpdate: config.onUpdate ?? true,
34
+ onAdd: config.onAdd ?? false,
35
+ entities: config.entities ?? ['*'], // Version all entities by default
36
+ excludeEntities: config.excludeEntities ?? ['_version:*'], // Exclude version metadata entities
37
+ types: config.types ?? [], // Empty = all types
38
+ excludeTypes: config.excludeTypes ?? [], // No need to exclude types (versions use 'state' type)
39
+ keepRecent: config.keepRecent ?? 10,
40
+ keepTagged: config.keepTagged ?? true,
41
+ tagPrefix: config.tagPrefix ?? 'auto-',
42
+ autoPrune: config.autoPrune ?? true,
43
+ pruneInterval: config.pruneInterval ?? 60 * 60 * 1000, // 1 hour
44
+ hooks: config.hooks ?? {}
45
+ };
46
+ }
47
+ getManifest() {
48
+ return {
49
+ id: 'versioning',
50
+ name: 'Entity Versioning',
51
+ version: '5.3.0',
52
+ description: 'Automatic entity versioning with retention policies',
53
+ longDescription: 'Provides automatic versioning of entities on update/add operations with configurable retention policies, entity filtering, and event hooks.',
54
+ category: 'storage',
55
+ configSchema: {
56
+ type: 'object',
57
+ properties: {
58
+ enabled: {
59
+ type: 'boolean',
60
+ default: true,
61
+ description: 'Enable automatic versioning'
62
+ },
63
+ onUpdate: {
64
+ type: 'boolean',
65
+ default: true,
66
+ description: 'Auto-save version on update()'
67
+ },
68
+ onAdd: {
69
+ type: 'boolean',
70
+ default: false,
71
+ description: 'Auto-save version on add()'
72
+ },
73
+ entities: {
74
+ type: 'array',
75
+ items: { type: 'string' },
76
+ default: ['*'],
77
+ description: 'Entity ID patterns to version (glob patterns)'
78
+ },
79
+ excludeEntities: {
80
+ type: 'array',
81
+ items: { type: 'string' },
82
+ default: ['_version:*'],
83
+ description: 'Entity ID patterns to exclude (version metadata IDs start with _version:)'
84
+ },
85
+ types: {
86
+ type: 'array',
87
+ items: { type: 'string' },
88
+ default: [],
89
+ description: 'Entity types to version (empty = all)'
90
+ },
91
+ excludeTypes: {
92
+ type: 'array',
93
+ items: { type: 'string' },
94
+ default: [],
95
+ description: 'Entity types to exclude (versions use standard state type)'
96
+ },
97
+ keepRecent: {
98
+ type: 'number',
99
+ default: 10,
100
+ minimum: 1,
101
+ description: 'Keep N recent versions per entity'
102
+ },
103
+ keepTagged: {
104
+ type: 'boolean',
105
+ default: true,
106
+ description: 'Keep tagged versions during pruning'
107
+ },
108
+ tagPrefix: {
109
+ type: 'string',
110
+ default: 'auto-',
111
+ description: 'Tag prefix for auto-generated versions'
112
+ },
113
+ autoPrune: {
114
+ type: 'boolean',
115
+ default: true,
116
+ description: 'Automatically prune old versions'
117
+ },
118
+ pruneInterval: {
119
+ type: 'number',
120
+ default: 3600000,
121
+ description: 'Prune interval in milliseconds (default: 1 hour)'
122
+ }
123
+ }
124
+ },
125
+ configDefaults: {
126
+ enabled: true,
127
+ onUpdate: true,
128
+ onAdd: false,
129
+ entities: ['*'],
130
+ excludeEntities: ['_version:*'],
131
+ types: [],
132
+ excludeTypes: [],
133
+ keepRecent: 10,
134
+ keepTagged: true,
135
+ tagPrefix: 'auto-',
136
+ autoPrune: true,
137
+ pruneInterval: 3600000
138
+ },
139
+ minBrainyVersion: '5.3.0',
140
+ keywords: ['versioning', 'history', 'audit', 'backup'],
141
+ documentation: 'https://docs.brainy.dev/versioning',
142
+ status: 'stable',
143
+ performance: {
144
+ memoryUsage: 'low',
145
+ cpuUsage: 'low',
146
+ networkUsage: 'none'
147
+ },
148
+ features: [
149
+ 'auto-versioning',
150
+ 'retention-policies',
151
+ 'entity-filtering',
152
+ 'event-hooks'
153
+ ],
154
+ enhancedOperations: ['update', 'add'],
155
+ metrics: [
156
+ {
157
+ name: 'versions_created',
158
+ type: 'counter',
159
+ description: 'Total versions created by augmentation'
160
+ },
161
+ {
162
+ name: 'versions_pruned',
163
+ type: 'counter',
164
+ description: 'Total versions pruned by retention policies'
165
+ }
166
+ ]
167
+ };
168
+ }
169
+ async onAttach(brain) {
170
+ // Store brain instance for entity fetching
171
+ this.brain = brain;
172
+ // Get VersioningAPI instance
173
+ this.versioningAPI = brain.versions;
174
+ // Start auto-prune timer if enabled
175
+ if (this.config.autoPrune && this.config.pruneInterval) {
176
+ this.startAutoPrune();
177
+ }
178
+ }
179
+ async onDetach() {
180
+ // Stop auto-prune timer
181
+ if (this.pruneTimer) {
182
+ clearInterval(this.pruneTimer);
183
+ this.pruneTimer = undefined;
184
+ }
185
+ }
186
+ /**
187
+ * Execute method (required by BaseAugmentation)
188
+ */
189
+ async execute(operation, params, context) {
190
+ // Versioning augmentation only runs in 'after' mode
191
+ // Actual logic is in after() method
192
+ return context.originalResult;
193
+ }
194
+ /**
195
+ * After operation hook - auto-save versions
196
+ */
197
+ async after(operation, params, result) {
198
+ if (!this.config.enabled || !this.versioningAPI) {
199
+ return result;
200
+ }
201
+ // Check if we should version this operation
202
+ if (operation === 'update' && !this.config.onUpdate) {
203
+ return result;
204
+ }
205
+ if (operation === 'add' && !this.config.onAdd) {
206
+ return result;
207
+ }
208
+ // Extract entity ID from params
209
+ const entityId = this.extractEntityId(operation, params);
210
+ if (!entityId) {
211
+ return result;
212
+ }
213
+ // Check if entity should be versioned
214
+ if (!(await this.shouldVersionEntity(entityId))) {
215
+ return result;
216
+ }
217
+ try {
218
+ // Prepare save options
219
+ let saveOptions = {
220
+ tag: `${this.config.tagPrefix}${Date.now()}`,
221
+ description: `Auto-saved after ${operation}`,
222
+ metadata: {
223
+ augmentation: 'versioning',
224
+ operation,
225
+ timestamp: Date.now()
226
+ }
227
+ };
228
+ // Call before-save hook
229
+ if (this.config.hooks?.beforeSave) {
230
+ const modifiedOptions = await this.config.hooks.beforeSave(entityId, saveOptions);
231
+ if (modifiedOptions === null) {
232
+ // Hook cancelled the save
233
+ return result;
234
+ }
235
+ saveOptions = modifiedOptions;
236
+ }
237
+ // Save version
238
+ const version = await this.versioningAPI.save(entityId, saveOptions);
239
+ this.versionCount++;
240
+ // Call after-save hook
241
+ if (this.config.hooks?.afterSave) {
242
+ await this.config.hooks.afterSave(entityId, version);
243
+ }
244
+ // Auto-prune if enabled
245
+ if (this.config.autoPrune) {
246
+ await this.pruneEntity(entityId);
247
+ }
248
+ }
249
+ catch (error) {
250
+ // Don't fail the operation if versioning fails
251
+ console.error(`Versioning augmentation error for ${entityId}:`, error);
252
+ }
253
+ return result;
254
+ }
255
+ /**
256
+ * Extract entity ID from operation params
257
+ */
258
+ extractEntityId(operation, params) {
259
+ if (operation === 'update') {
260
+ // update(id, data) or update({ id, ... })
261
+ if (typeof params[0] === 'string') {
262
+ return params[0];
263
+ }
264
+ if (params[0]?.id) {
265
+ return params[0].id;
266
+ }
267
+ }
268
+ if (operation === 'add') {
269
+ // add(data) - ID might be in data or result
270
+ if (params[0]?.id) {
271
+ return params[0].id;
272
+ }
273
+ }
274
+ return null;
275
+ }
276
+ /**
277
+ * Check if entity should be versioned based on filters
278
+ */
279
+ async shouldVersionEntity(entityId) {
280
+ // Check exclude patterns first (ID-based)
281
+ if (this.config.excludeEntities) {
282
+ for (const pattern of this.config.excludeEntities) {
283
+ if (this.matchPattern(entityId, pattern)) {
284
+ return false;
285
+ }
286
+ }
287
+ }
288
+ // Check include patterns (ID-based)
289
+ if (this.config.entities && this.config.entities.length > 0) {
290
+ let matched = false;
291
+ for (const pattern of this.config.entities) {
292
+ if (this.matchPattern(entityId, pattern)) {
293
+ matched = true;
294
+ break;
295
+ }
296
+ }
297
+ if (!matched)
298
+ return false;
299
+ }
300
+ // Check entity type filters (requires fetching entity)
301
+ if ((this.config.types && this.config.types.length > 0) ||
302
+ (this.config.excludeTypes && this.config.excludeTypes.length > 0)) {
303
+ try {
304
+ const entity = await this.brain?.getNounMetadata?.(entityId);
305
+ if (!entity)
306
+ return true; // If can't fetch, allow versioning
307
+ const entityType = entity.type;
308
+ // Check exclude types
309
+ if (this.config.excludeTypes && this.config.excludeTypes.includes(entityType)) {
310
+ return false;
311
+ }
312
+ // Check include types
313
+ if (this.config.types && this.config.types.length > 0) {
314
+ if (!this.config.types.includes(entityType)) {
315
+ return false;
316
+ }
317
+ }
318
+ }
319
+ catch (error) {
320
+ // If can't fetch entity, allow versioning (fail open)
321
+ console.error(`Failed to fetch entity ${entityId} for type filtering:`, error);
322
+ return true;
323
+ }
324
+ }
325
+ return true;
326
+ }
327
+ /**
328
+ * Simple glob pattern matching
329
+ */
330
+ matchPattern(value, pattern) {
331
+ if (pattern === '*')
332
+ return true;
333
+ if (!pattern.includes('*'))
334
+ return value === pattern;
335
+ // Convert glob to regex
336
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$');
337
+ return regex.test(value);
338
+ }
339
+ /**
340
+ * Prune old versions for an entity
341
+ */
342
+ async pruneEntity(entityId) {
343
+ if (!this.versioningAPI)
344
+ return;
345
+ try {
346
+ // Call before-prune hook
347
+ if (this.config.hooks?.beforePrune) {
348
+ const shouldPrune = await this.config.hooks.beforePrune(entityId);
349
+ if (!shouldPrune)
350
+ return;
351
+ }
352
+ // Prune versions
353
+ const result = await this.versioningAPI.prune(entityId, {
354
+ keepRecent: this.config.keepRecent,
355
+ keepAfter: this.config.keepAfter,
356
+ keepTagged: this.config.keepTagged
357
+ });
358
+ // Call after-prune hook
359
+ if (result.deleted > 0 && this.config.hooks?.afterPrune) {
360
+ await this.config.hooks.afterPrune(entityId, result.deleted);
361
+ }
362
+ }
363
+ catch (error) {
364
+ console.error(`Failed to prune versions for ${entityId}:`, error);
365
+ }
366
+ }
367
+ /**
368
+ * Start auto-prune timer
369
+ */
370
+ startAutoPrune() {
371
+ if (this.pruneTimer) {
372
+ clearInterval(this.pruneTimer);
373
+ }
374
+ this.pruneTimer = setInterval(async () => {
375
+ await this.pruneAllEntities();
376
+ }, this.config.pruneInterval);
377
+ }
378
+ /**
379
+ * Prune all versioned entities
380
+ */
381
+ async pruneAllEntities() {
382
+ if (!this.versioningAPI)
383
+ return;
384
+ try {
385
+ // Get all versioned entities
386
+ const versionIndex = this.versioningAPI.manager.versionIndex;
387
+ const entities = await versionIndex.getVersionedEntities();
388
+ // Prune each entity
389
+ for (const entityId of entities) {
390
+ if (await this.shouldVersionEntity(entityId)) {
391
+ await this.pruneEntity(entityId);
392
+ }
393
+ }
394
+ }
395
+ catch (error) {
396
+ console.error('Auto-prune failed:', error);
397
+ }
398
+ }
399
+ /**
400
+ * Get augmentation statistics
401
+ */
402
+ getStats() {
403
+ return {
404
+ enabled: this.config.enabled,
405
+ versionsCreated: this.versionCount,
406
+ entitiesPattern: this.config.entities || [],
407
+ excludePattern: this.config.excludeEntities || [],
408
+ retention: this.config.keepRecent || 10
409
+ };
410
+ }
411
+ }
412
+ /**
413
+ * Factory function for easy augmentation creation
414
+ */
415
+ export function createVersioningAugmentation(config = {}) {
416
+ return new VersioningAugmentation(config);
417
+ }
418
+ //# sourceMappingURL=versioningAugmentation.js.map
package/dist/brainy.d.ts CHANGED
@@ -10,6 +10,7 @@ import { NaturalLanguageProcessor } from './neural/naturalLanguageProcessor.js';
10
10
  import { ExtractedEntity } from './neural/entityExtractor.js';
11
11
  import { TripleIntelligenceSystem } from './triple/TripleIntelligenceSystem.js';
12
12
  import { VirtualFileSystem } from './vfs/VirtualFileSystem.js';
13
+ import { VersioningAPI } from './versioning/VersioningAPI.js';
13
14
  import { Entity, Relation, Result, AddParams, UpdateParams, RelateParams, FindParams, SimilarParams, GetRelationsParams, AddManyParams, DeleteManyParams, RelateManyParams, BatchResult, BrainyConfig } from './types/brainy.types.js';
14
15
  import { NounType, VerbType } from './types/graphTypes.js';
15
16
  import { BrainyInterface } from './types/brainyInterface.js';
@@ -39,6 +40,7 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
39
40
  private _nlp?;
40
41
  private _extractor?;
41
42
  private _tripleIntelligence?;
43
+ private _versions?;
42
44
  private _vfs?;
43
45
  private initialized;
44
46
  private dimensions?;
@@ -956,6 +958,32 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
956
958
  * Neural API - Advanced AI operations
957
959
  */
958
960
  neural(): ImprovedNeuralAPI;
961
+ /**
962
+ * Versioning API - Entity version control (v5.3.0)
963
+ *
964
+ * Provides entity-level versioning with:
965
+ * - save() - Create version of entity
966
+ * - restore() - Restore entity to specific version
967
+ * - list() - List all versions of entity
968
+ * - compare() - Deep diff between versions
969
+ * - prune() - Remove old versions (retention policies)
970
+ *
971
+ * @example
972
+ * ```typescript
973
+ * // Save current state
974
+ * const version = await brain.versions.save('user-123', { tag: 'v1.0' })
975
+ *
976
+ * // List versions
977
+ * const versions = await brain.versions.list('user-123')
978
+ *
979
+ * // Restore to previous version
980
+ * await brain.versions.restore('user-123', 5)
981
+ *
982
+ * // Compare versions
983
+ * const diff = await brain.versions.compare('user-123', 2, 5)
984
+ * ```
985
+ */
986
+ get versions(): VersioningAPI;
959
987
  /**
960
988
  * Natural Language Processing API
961
989
  */
package/dist/brainy.js CHANGED
@@ -16,6 +16,7 @@ import { NaturalLanguageProcessor } from './neural/naturalLanguageProcessor.js';
16
16
  import { NeuralEntityExtractor } from './neural/entityExtractor.js';
17
17
  import { TripleIntelligenceSystem } from './triple/TripleIntelligenceSystem.js';
18
18
  import { VirtualFileSystem } from './vfs/VirtualFileSystem.js';
19
+ import { VersioningAPI } from './versioning/VersioningAPI.js';
19
20
  import { MetadataIndexManager } from './utils/metadataIndex.js';
20
21
  import { GraphAdjacencyIndex } from './graph/graphAdjacencyIndex.js';
21
22
  import { CommitBuilder } from './storage/cow/CommitObject.js';
@@ -2026,7 +2027,7 @@ export class Brainy {
2026
2027
  const blobStorage = this.storage.blobStorage;
2027
2028
  const currentBranch = await this.getCurrentBranch();
2028
2029
  // Get current HEAD commit (parent)
2029
- const currentCommitHash = await refManager.resolveRef(`heads/${currentBranch}`);
2030
+ const currentCommitHash = await refManager.resolveRef(currentBranch);
2030
2031
  // Get current state statistics
2031
2032
  const entityCount = await this.getNounCount();
2032
2033
  const relationshipCount = await this.getVerbCount();
@@ -2051,7 +2052,7 @@ export class Brainy {
2051
2052
  // Build and persist commit (returns hash directly)
2052
2053
  const commitHash = await builder.build();
2053
2054
  // Update branch ref to point to new commit
2054
- await refManager.setRef(`heads/${currentBranch}`, commitHash, {
2055
+ await refManager.setRef(currentBranch, commitHash, {
2055
2056
  author: options?.author || 'unknown',
2056
2057
  message: options?.message || 'Snapshot commit'
2057
2058
  });
@@ -2440,7 +2441,7 @@ export class Brainy {
2440
2441
  throw new Error('Cannot delete current branch');
2441
2442
  }
2442
2443
  const refManager = this.storage.refManager;
2443
- await refManager.deleteRef(`heads/${branch}`);
2444
+ await refManager.deleteRef(branch);
2444
2445
  });
2445
2446
  }
2446
2447
  /**
@@ -2465,7 +2466,7 @@ export class Brainy {
2465
2466
  const commitLog = this.storage.commitLog;
2466
2467
  const currentBranch = await this.getCurrentBranch();
2467
2468
  // Get commit history for current branch
2468
- const commits = await commitLog.getHistory(`heads/${currentBranch}`, {
2469
+ const commits = await commitLog.getHistory(currentBranch, {
2469
2470
  maxCount: options?.limit || 10
2470
2471
  });
2471
2472
  // Map to expected format (compute hash for each commit)
@@ -2504,6 +2505,37 @@ export class Brainy {
2504
2505
  }
2505
2506
  return this._neural;
2506
2507
  }
2508
+ /**
2509
+ * Versioning API - Entity version control (v5.3.0)
2510
+ *
2511
+ * Provides entity-level versioning with:
2512
+ * - save() - Create version of entity
2513
+ * - restore() - Restore entity to specific version
2514
+ * - list() - List all versions of entity
2515
+ * - compare() - Deep diff between versions
2516
+ * - prune() - Remove old versions (retention policies)
2517
+ *
2518
+ * @example
2519
+ * ```typescript
2520
+ * // Save current state
2521
+ * const version = await brain.versions.save('user-123', { tag: 'v1.0' })
2522
+ *
2523
+ * // List versions
2524
+ * const versions = await brain.versions.list('user-123')
2525
+ *
2526
+ * // Restore to previous version
2527
+ * await brain.versions.restore('user-123', 5)
2528
+ *
2529
+ * // Compare versions
2530
+ * const diff = await brain.versions.compare('user-123', 2, 5)
2531
+ * ```
2532
+ */
2533
+ get versions() {
2534
+ if (!this._versions) {
2535
+ this._versions = new VersioningAPI(this);
2536
+ }
2537
+ return this._versions;
2538
+ }
2507
2539
  /**
2508
2540
  * Natural Language Processing API
2509
2541
  */