@soulcraft/brainy 5.0.0 → 5.1.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.
@@ -65,6 +65,7 @@ export class MemoryStorage extends BaseStorage {
65
65
  }
66
66
  /**
67
67
  * Save a noun to storage (v4.0.0: pure vector only, no metadata)
68
+ * v5.0.1: COW-aware - uses branch-prefixed paths for fork isolation
68
69
  */
69
70
  async saveNoun_internal(noun) {
70
71
  const isNew = !this.nouns.has(noun.id);
@@ -82,7 +83,12 @@ export class MemoryStorage extends BaseStorage {
82
83
  for (const [level, connections] of noun.connections.entries()) {
83
84
  nounCopy.connections.set(level, new Set(connections));
84
85
  }
85
- // Save the noun directly in the nouns map
86
+ // v5.0.1: COW-aware write using branch-prefixed path
87
+ // Use synthetic path for vector storage (nouns don't have types in standalone mode)
88
+ const path = `hnsw/nouns/${noun.id}.json`;
89
+ await this.writeObjectToBranch(path, nounCopy);
90
+ // ALSO store in nouns Map for fast iteration (getNouns, initializeCounts)
91
+ // This is redundant but maintains backward compatibility
86
92
  this.nouns.set(noun.id, nounCopy);
87
93
  // Count tracking happens in baseStorage.saveNounMetadata_internal (v4.1.2)
88
94
  // This fixes the race condition where metadata didn't exist yet
@@ -90,10 +96,12 @@ export class MemoryStorage extends BaseStorage {
90
96
  /**
91
97
  * Get a noun from storage (v4.0.0: returns pure vector only)
92
98
  * Base class handles combining with metadata
99
+ * v5.0.1: COW-aware - reads from branch-prefixed paths with inheritance
93
100
  */
94
101
  async getNoun_internal(id) {
95
- // Get the noun directly from the nouns map
96
- const noun = this.nouns.get(id);
102
+ // v5.0.1: COW-aware read using branch-prefixed path with inheritance
103
+ const path = `hnsw/nouns/${id}.json`;
104
+ const noun = await this.readWithInheritance(path);
97
105
  // If not found, return null
98
106
  if (!noun) {
99
107
  return null;
@@ -107,9 +115,10 @@ export class MemoryStorage extends BaseStorage {
107
115
  level: noun.level || 0
108
116
  // ✅ NO metadata field in v4.0.0
109
117
  };
110
- // Copy connections
111
- for (const [level, connections] of noun.connections.entries()) {
112
- nounCopy.connections.set(level, new Set(connections));
118
+ // Copy connections (handle both Map and plain object from JSON)
119
+ const connections = noun.connections instanceof Map ? noun.connections : new Map(Object.entries(noun.connections || {}));
120
+ for (const [level, conns] of connections.entries()) {
121
+ nounCopy.connections.set(Number(level), new Set(conns));
113
122
  }
114
123
  return nounCopy;
115
124
  }
@@ -252,6 +261,7 @@ export class MemoryStorage extends BaseStorage {
252
261
  }
253
262
  /**
254
263
  * Delete a noun from storage (v4.0.0)
264
+ * v5.0.1: COW-aware - deletes from branch-prefixed paths
255
265
  */
256
266
  async deleteNoun_internal(id) {
257
267
  // v4.0.0: Get type from separate metadata storage
@@ -260,10 +270,15 @@ export class MemoryStorage extends BaseStorage {
260
270
  const type = metadata.noun || 'default';
261
271
  this.decrementEntityCount(type);
262
272
  }
273
+ // v5.0.1: COW-aware delete using branch-prefixed path
274
+ const path = `hnsw/nouns/${id}.json`;
275
+ await this.deleteObjectFromBranch(path);
276
+ // Also remove from nouns Map for fast iteration
263
277
  this.nouns.delete(id);
264
278
  }
265
279
  /**
266
280
  * Save a verb to storage (v4.0.0: pure vector + core fields, no metadata)
281
+ * v5.0.1: COW-aware - uses branch-prefixed paths for fork isolation
267
282
  */
268
283
  async saveVerb_internal(verb) {
269
284
  const isNew = !this.verbs.has(verb.id);
@@ -283,17 +298,22 @@ export class MemoryStorage extends BaseStorage {
283
298
  for (const [level, connections] of verb.connections.entries()) {
284
299
  verbCopy.connections.set(level, new Set(connections));
285
300
  }
286
- // Save the verb directly in the verbs map
301
+ // v5.0.1: COW-aware write using branch-prefixed path
302
+ const path = `hnsw/verbs/${verb.id}.json`;
303
+ await this.writeObjectToBranch(path, verbCopy);
304
+ // ALSO store in verbs Map for fast iteration (getVerbs, initializeCounts)
287
305
  this.verbs.set(verb.id, verbCopy);
288
306
  // Note: Count tracking happens in saveVerbMetadata since metadata is separate
289
307
  }
290
308
  /**
291
309
  * Get a verb from storage (v4.0.0: returns pure vector + core fields)
292
310
  * Base class handles combining with metadata
311
+ * v5.0.1: COW-aware - reads from branch-prefixed paths with inheritance
293
312
  */
294
313
  async getVerb_internal(id) {
295
- // Get the verb directly from the verbs map
296
- const verb = this.verbs.get(id);
314
+ // v5.0.1: COW-aware read using branch-prefixed path with inheritance
315
+ const path = `hnsw/verbs/${id}.json`;
316
+ const verb = await this.readWithInheritance(path);
297
317
  // If not found, return null
298
318
  if (!verb) {
299
319
  return null;
@@ -310,9 +330,10 @@ export class MemoryStorage extends BaseStorage {
310
330
  targetId: verb.targetId
311
331
  // ✅ NO metadata field in v4.0.0
312
332
  };
313
- // Copy connections
314
- for (const [level, connections] of verb.connections.entries()) {
315
- verbCopy.connections.set(level, new Set(connections));
333
+ // Copy connections (handle both Map and plain object from JSON)
334
+ const connections = verb.connections instanceof Map ? verb.connections : new Map(Object.entries(verb.connections || {}));
335
+ for (const [level, conns] of connections.entries()) {
336
+ verbCopy.connections.set(Number(level), new Set(conns));
316
337
  }
317
338
  return verbCopy;
318
339
  }
@@ -474,10 +495,9 @@ export class MemoryStorage extends BaseStorage {
474
495
  }
475
496
  /**
476
497
  * Delete a verb from storage
498
+ * v5.0.1: COW-aware - deletes from branch-prefixed paths
477
499
  */
478
500
  async deleteVerb_internal(id) {
479
- // Delete the HNSWVerb from the verbs map
480
- this.verbs.delete(id);
481
501
  // CRITICAL: Also delete verb metadata - this is what getVerbs() uses to find verbs
482
502
  // Without this, getVerbsBySource() will still find "deleted" verbs via their metadata
483
503
  const metadata = await this.getVerbMetadata(id);
@@ -487,6 +507,11 @@ export class MemoryStorage extends BaseStorage {
487
507
  // Delete the metadata using the base storage method
488
508
  await this.deleteVerbMetadata(id);
489
509
  }
510
+ // v5.0.1: COW-aware delete using branch-prefixed path
511
+ const path = `hnsw/verbs/${id}.json`;
512
+ await this.deleteObjectFromBranch(path);
513
+ // Also remove from verbs Map for fast iteration
514
+ this.verbs.delete(id);
490
515
  }
491
516
  /**
492
517
  * Primitive operation: Write object to path
@@ -36,7 +36,7 @@
36
36
  * @since Phase 1 - Type-First Implementation
37
37
  */
38
38
  import { BaseStorage } from '../baseStorage.js';
39
- import { HNSWNoun, HNSWVerb, HNSWVerbWithMetadata, NounMetadata, VerbMetadata, StatisticsData } from '../../coreTypes.js';
39
+ import { HNSWNoun, HNSWVerb, HNSWNounWithMetadata, HNSWVerbWithMetadata, NounMetadata, VerbMetadata, StatisticsData } from '../../coreTypes.js';
40
40
  import { NounType, VerbType } from '../../types/graphTypes.js';
41
41
  /**
42
42
  * Options for TypeAwareStorageAdapter
@@ -238,6 +238,36 @@ export declare class TypeAwareStorageAdapter extends BaseStorage {
238
238
  level: number;
239
239
  connections: Record<string, string[]>;
240
240
  } | null>;
241
+ /**
242
+ * Get nouns with pagination (v5.0.1: COW-aware)
243
+ * Required for find() to work with TypeAwareStorage
244
+ */
245
+ getNounsWithPagination(options: {
246
+ limit?: number;
247
+ offset?: number;
248
+ cursor?: string;
249
+ filter?: any;
250
+ }): Promise<{
251
+ items: HNSWNounWithMetadata[];
252
+ totalCount: number;
253
+ hasMore: boolean;
254
+ nextCursor?: string;
255
+ }>;
256
+ /**
257
+ * Get verbs with pagination (v5.0.1: COW-aware)
258
+ * Required for GraphAdjacencyIndex rebuild and find() to work
259
+ */
260
+ getVerbsWithPagination(options: {
261
+ limit?: number;
262
+ offset?: number;
263
+ cursor?: string;
264
+ filter?: any;
265
+ }): Promise<{
266
+ items: HNSWVerbWithMetadata[];
267
+ totalCount: number;
268
+ hasMore: boolean;
269
+ nextCursor?: string;
270
+ }>;
241
271
  /**
242
272
  * Save HNSW system data (entry point, max level)
243
273
  */