fix: exclude __words__ keyword index from corruption detection and getStats()
The __words__ keyword index stores 50-5000 entries per entity (one per word), which inflated avg entries/entity well above the corruption threshold of 100. This caused: 1. validateConsistency() to falsely detect corruption on every startup, triggering unnecessary clearAllIndexData() + rebuild() cycles 2. getStats() to log false "Metadata index may be corrupted" warnings and report inflated totalEntries/totalIds stats Both methods now skip __words__ when counting, so stats and health checks reflect metadata fields only (noun, type, createdAt, etc.). Keyword search is unaffected since the __words__ field index itself is not modified.
This commit is contained in:
parent
32dbdcec61
commit
364360d447
128 changed files with 5637 additions and 5682 deletions
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* MIME Type Detection Service (v5.2.0)
|
||||
* MIME Type Detection Service
|
||||
*
|
||||
* Provides comprehensive MIME type detection using:
|
||||
* 1. Industry-standard `mime` library (2000+ IANA types)
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export class PathResolver {
|
|||
|
||||
/**
|
||||
* Resolve a path to an entity ID
|
||||
* v6.1.0: Uses 3-tier caching + MetadataIndexManager for optimal performance
|
||||
* Uses 3-tier caching + MetadataIndexManager for optimal performance
|
||||
* Works for ALL storage adapters (FileSystem, GCS, S3, Azure, R2, OPFS)
|
||||
*/
|
||||
async resolve(path: string, options?: {
|
||||
|
|
@ -255,14 +255,14 @@ export class PathResolver {
|
|||
// Still need to verify it exists
|
||||
}
|
||||
|
||||
// v4.7.0: Use proper graph traversal to find children
|
||||
// Use proper graph traversal to find children
|
||||
// VFS relationships are now part of the knowledge graph
|
||||
const relations = await this.brain.getRelations({
|
||||
from: parentId,
|
||||
type: VerbType.Contains
|
||||
})
|
||||
|
||||
// v6.0.2: PERFORMANCE FIX - Batch fetch all children (eliminates N+1 pattern)
|
||||
// PERFORMANCE FIX - Batch fetch all children (eliminates N+1 pattern)
|
||||
// Before: N sequential get() calls (10 children = 10 × 300ms = 3000ms on GCS)
|
||||
// After: 1 batch call (10 children = 1 × 300ms = 300ms on GCS)
|
||||
// 10x improvement for cloud storage (GCS, S3, Azure)
|
||||
|
|
@ -292,7 +292,7 @@ export class PathResolver {
|
|||
* Uses proper graph relationships to traverse the tree
|
||||
*/
|
||||
async getChildren(dirId: string): Promise<VFSEntity[]> {
|
||||
// v4.7.0: Use O(1) graph relationships (VFS creates these in mkdir/writeFile)
|
||||
// Use O(1) graph relationships (VFS creates these in mkdir/writeFile)
|
||||
// VFS relationships are now part of the knowledge graph (no special filtering needed)
|
||||
const relations = await this.brain.getRelations({
|
||||
from: dirId,
|
||||
|
|
@ -302,12 +302,12 @@ export class PathResolver {
|
|||
const validChildren: VFSEntity[] = []
|
||||
const childNames = new Set<string>()
|
||||
|
||||
// v5.12.0: Batch fetch all child entities (eliminates N+1 query pattern)
|
||||
// Batch fetch all child entities (eliminates N+1 query pattern)
|
||||
// This is WIRED UP AND USED - no longer a stub!
|
||||
const childIds = relations.map(r => r.to)
|
||||
const childrenMap = await this.brain.batchGet(childIds)
|
||||
|
||||
// v7.4.1: Deduplicate by entity ID to handle duplicate relationship records
|
||||
// Deduplicate by entity ID to handle duplicate relationship records
|
||||
// This can occur when multiple Brainy instances create relationships concurrently
|
||||
// for the same storage path (each instance has its own in-memory GraphAdjacencyIndex).
|
||||
// The Set lookup is O(1), adding negligible overhead.
|
||||
|
|
@ -356,7 +356,7 @@ export class PathResolver {
|
|||
}
|
||||
|
||||
/**
|
||||
* Invalidate ALL caches (v6.3.0)
|
||||
* Invalidate ALL caches
|
||||
* Call this when switching branches (checkout), clearing data (clear), or forking
|
||||
* This ensures no stale data from previous branch/state remains in cache
|
||||
*/
|
||||
|
|
@ -381,13 +381,13 @@ export class PathResolver {
|
|||
|
||||
/**
|
||||
* Invalidate cache entries for a path and its children
|
||||
* v6.2.9 FIX: Also invalidates UnifiedCache to prevent stale entity IDs
|
||||
* FIX: Also invalidates UnifiedCache to prevent stale entity IDs
|
||||
* This fixes the "Source entity not found" bug after delete+recreate operations
|
||||
*/
|
||||
invalidatePath(path: string, recursive = false): void {
|
||||
const normalizedPath = this.normalizePath(path)
|
||||
|
||||
// v6.2.9 FIX: Clear parent cache BEFORE deleting from pathCache
|
||||
// FIX: Clear parent cache BEFORE deleting from pathCache
|
||||
// (we need the entityId from the cache entry)
|
||||
const cached = this.pathCache.get(normalizedPath)
|
||||
if (cached) {
|
||||
|
|
@ -398,7 +398,7 @@ export class PathResolver {
|
|||
this.pathCache.delete(normalizedPath)
|
||||
this.hotPaths.delete(normalizedPath)
|
||||
|
||||
// v6.2.9 CRITICAL FIX: Also invalidate UnifiedCache (global LRU cache)
|
||||
// CRITICAL FIX: Also invalidate UnifiedCache (global LRU cache)
|
||||
// This was missing before, causing stale entity IDs to be returned after delete
|
||||
const cacheKey = `vfs:path:${normalizedPath}`
|
||||
getGlobalCache().delete(cacheKey)
|
||||
|
|
@ -411,12 +411,12 @@ export class PathResolver {
|
|||
if (cachedPath.startsWith(prefix)) {
|
||||
this.pathCache.delete(cachedPath)
|
||||
this.hotPaths.delete(cachedPath)
|
||||
// v6.2.9: Also clear parent cache for this entry
|
||||
// Also clear parent cache for this entry
|
||||
this.parentCache.delete(entry.entityId)
|
||||
}
|
||||
}
|
||||
|
||||
// v6.2.9 CRITICAL FIX: Also invalidate UnifiedCache entries with this prefix
|
||||
// CRITICAL FIX: Also invalidate UnifiedCache entries with this prefix
|
||||
const globalCachePrefix = `vfs:path:${prefix}`
|
||||
getGlobalCache().deleteByPrefix(globalCachePrefix)
|
||||
}
|
||||
|
|
@ -561,7 +561,7 @@ export class PathResolver {
|
|||
|
||||
/**
|
||||
* Get cache statistics
|
||||
* v6.1.0: Added MetadataIndexManager metrics
|
||||
* Added MetadataIndexManager metrics
|
||||
*/
|
||||
getStats(): {
|
||||
cacheSize: number
|
||||
|
|
|
|||
|
|
@ -81,10 +81,10 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
// Mutex for preventing race conditions in directory creation
|
||||
private mkdirLocks: Map<string, Promise<void>> = new Map()
|
||||
|
||||
// v5.8.0: Singleton promise for root initialization (prevents duplicate roots)
|
||||
// Singleton promise for root initialization (prevents duplicate roots)
|
||||
private rootInitPromise: Promise<string> | null = null
|
||||
|
||||
// v5.10.0: Fixed VFS root ID (prevents duplicates across instances)
|
||||
// Fixed VFS root ID (prevents duplicates across instances)
|
||||
// Uses deterministic UUID format for storage compatibility
|
||||
private static readonly VFS_ROOT_ID = '00000000-0000-0000-0000-000000000000'
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
}
|
||||
|
||||
/**
|
||||
* v5.2.0: Access to BlobStorage for unified file storage
|
||||
* Access to BlobStorage for unified file storage
|
||||
*/
|
||||
private get blobStorage() {
|
||||
// TypeScript doesn't know about blobStorage on storage, use type assertion
|
||||
|
|
@ -119,14 +119,14 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
// Merge config with defaults
|
||||
this.config = { ...this.getDefaultConfig(), ...config }
|
||||
|
||||
// v5.0.1: VFS is now auto-initialized during brain.init()
|
||||
// VFS is now auto-initialized during brain.init()
|
||||
// Brain is guaranteed to be initialized when this is called
|
||||
// Removed brain.init() check to prevent infinite recursion
|
||||
|
||||
// Create or find root entity
|
||||
this.rootEntityId = await this.initializeRoot()
|
||||
|
||||
// v5.10.0: Clean up old UUID-based roots from v5.9.0 (one-time migration)
|
||||
// Clean up old UUID-based roots (one-time migration)
|
||||
await this.cleanupOldRoots()
|
||||
|
||||
// Initialize projection registry with auto-discovery of built-in projections
|
||||
|
|
@ -180,7 +180,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
}
|
||||
|
||||
/**
|
||||
* v5.8.0: CRITICAL FIX - Prevent duplicate root creation
|
||||
* CRITICAL FIX - Prevent duplicate root creation
|
||||
* Uses singleton promise pattern to ensure only ONE root initialization
|
||||
* happens even with concurrent init() calls
|
||||
*/
|
||||
|
|
@ -206,7 +206,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
}
|
||||
|
||||
/**
|
||||
* v5.10.0: Atomic root initialization with fixed ID
|
||||
* Atomic root initialization with fixed ID
|
||||
* Uses deterministic ID to prevent duplicates across all VFS instances
|
||||
*
|
||||
* ARCHITECTURAL FIX: Instead of query-then-create (race condition),
|
||||
|
|
@ -266,7 +266,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
}
|
||||
|
||||
/**
|
||||
* v5.10.0: Get standard root metadata
|
||||
* Get standard root metadata
|
||||
* Centralized to ensure consistency
|
||||
*/
|
||||
private getRootMetadata(): VFSMetadata {
|
||||
|
|
@ -286,7 +286,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
}
|
||||
|
||||
/**
|
||||
* v5.10.0: Cleanup old UUID-based VFS roots (migration from v5.9.0)
|
||||
* Cleanup old UUID-based VFS roots
|
||||
* Called during init to remove duplicate roots created before fixed-ID fix
|
||||
*
|
||||
* This is a one-time migration helper that can be removed in future versions.
|
||||
|
|
@ -308,7 +308,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
const duplicates = oldRoots.filter(r => r.id !== VirtualFileSystem.VFS_ROOT_ID)
|
||||
|
||||
if (duplicates.length > 0) {
|
||||
console.log(`VFS: Found ${duplicates.length} old UUID-based root(s) from v5.9.0, cleaning up...`)
|
||||
console.log(`VFS: Found ${duplicates.length} old UUID-based root(s), cleaning up...`)
|
||||
|
||||
for (const duplicate of duplicates) {
|
||||
try {
|
||||
|
|
@ -352,23 +352,23 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
throw new VFSError(VFSErrorCode.EISDIR, `Is a directory: ${path}`, path, 'readFile')
|
||||
}
|
||||
|
||||
// v5.2.0: Unified blob storage - ONE path only
|
||||
// Unified blob storage - ONE path only
|
||||
if (!entity.metadata.storage?.type || entity.metadata.storage.type !== 'blob') {
|
||||
throw new VFSError(
|
||||
VFSErrorCode.EIO,
|
||||
`File has no blob storage: ${path}. Requires v5.2.0+ storage format.`,
|
||||
`File has no blob storage: ${path}. Requires blob storage format.`,
|
||||
path,
|
||||
'readFile'
|
||||
)
|
||||
}
|
||||
|
||||
// v5.8.0: CRITICAL FIX - Isolate blob errors from VFS tree corruption
|
||||
// CRITICAL FIX - Isolate blob errors from VFS tree corruption
|
||||
// Blob read errors MUST NOT cascade to VFS tree structure
|
||||
try {
|
||||
// Read from BlobStorage (handles decompression automatically)
|
||||
const content = await this.blobStorage.read(entity.metadata.storage.hash)
|
||||
|
||||
// v6.2.0: REMOVED updateAccessTime() for performance
|
||||
// REMOVED updateAccessTime() for performance
|
||||
// Access time updates caused 50-100ms GCS write on EVERY file read
|
||||
// Modern file systems use 'noatime' for same reason (performance)
|
||||
// Field 'accessed' still exists in metadata for backward compat but won't update
|
||||
|
|
@ -436,7 +436,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
existingId = null
|
||||
}
|
||||
|
||||
// v5.2.0: Unified blob storage for ALL files (no size-based branching)
|
||||
// Unified blob storage for ALL files (no size-based branching)
|
||||
// Store in BlobStorage (content-addressable, auto-deduplication, streaming)
|
||||
const blobHash = await this.blobStorage.write(buffer)
|
||||
|
||||
|
|
@ -450,7 +450,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
compressed: blobMetadata?.compressed
|
||||
}
|
||||
|
||||
// Detect MIME type (v5.2.0: using comprehensive MimeTypeDetector)
|
||||
// Detect MIME type (using comprehensive MimeTypeDetector)
|
||||
const mimeType = mimeDetector.detectMimeType(name, buffer)
|
||||
|
||||
// Create metadata
|
||||
|
|
@ -459,8 +459,8 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
name,
|
||||
parent: parentId,
|
||||
vfsType: 'file',
|
||||
isVFS: true, // v4.3.3: Mark as VFS entity (internal)
|
||||
isVFSEntity: true, // v5.3.0: Explicit flag for developer filtering
|
||||
isVFS: true, // Mark as VFS entity (internal)
|
||||
isVFSEntity: true, // Explicit flag for developer filtering
|
||||
size: buffer.length,
|
||||
mimeType,
|
||||
extension: this.getExtension(name),
|
||||
|
|
@ -470,7 +470,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
accessed: Date.now(),
|
||||
modified: Date.now(),
|
||||
storage: storageStrategy
|
||||
// v5.2.0: No rawData - content is in BlobStorage
|
||||
// No rawData - content is in BlobStorage
|
||||
// Backward compatibility: readFile() checks for rawData for legacy files
|
||||
}
|
||||
|
||||
|
|
@ -481,7 +481,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
|
||||
if (existingId) {
|
||||
// Update existing file
|
||||
// v5.2.0: No entity.data - content is in BlobStorage
|
||||
// No entity.data - content is in BlobStorage
|
||||
await this.brain.update({
|
||||
id: existingId,
|
||||
metadata
|
||||
|
|
@ -500,7 +500,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
from: parentId,
|
||||
to: existingId,
|
||||
type: VerbType.Contains,
|
||||
metadata: { isVFS: true } // v4.5.1: Mark as VFS relationship
|
||||
metadata: { isVFS: true } // Mark as VFS relationship
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
|
@ -519,7 +519,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
from: parentId,
|
||||
to: entity,
|
||||
type: VerbType.Contains,
|
||||
metadata: { isVFS: true } // v4.5.1: Mark as VFS relationship
|
||||
metadata: { isVFS: true } // Mark as VFS relationship
|
||||
})
|
||||
|
||||
// Update path resolver cache
|
||||
|
|
@ -574,7 +574,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
throw new VFSError(VFSErrorCode.EISDIR, `Is a directory: ${path}`, path, 'unlink')
|
||||
}
|
||||
|
||||
// v5.2.0: Delete blob from BlobStorage (decrements ref count)
|
||||
// Delete blob from BlobStorage (decrements ref count)
|
||||
if (entity.metadata.storage?.type === 'blob') {
|
||||
await this.blobStorage.delete(entity.metadata.storage.hash)
|
||||
}
|
||||
|
|
@ -617,7 +617,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
}
|
||||
|
||||
/**
|
||||
* v6.2.0: Gather descendants using graph traversal + bulk fetch
|
||||
* Gather descendants using graph traversal + bulk fetch
|
||||
*
|
||||
* ARCHITECTURE:
|
||||
* 1. Traverse graph to collect entity IDs (in-memory, fast)
|
||||
|
|
@ -694,7 +694,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
/**
|
||||
* Get a properly structured tree for the given path
|
||||
*
|
||||
* v6.2.0: Graph traversal + ONE batch fetch (55x faster on cloud storage)
|
||||
* Graph traversal + ONE batch fetch (55x faster on cloud storage)
|
||||
*
|
||||
* Architecture:
|
||||
* 1. Resolve path to entity ID
|
||||
|
|
@ -733,7 +733,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
/**
|
||||
* Get all descendants of a directory (flat list)
|
||||
*
|
||||
* v6.2.0: Same optimization as getTreeStructure
|
||||
* Same optimization as getTreeStructure
|
||||
*/
|
||||
async getDescendants(path: string, options?: {
|
||||
includeAncestor?: boolean
|
||||
|
|
@ -876,8 +876,8 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
name,
|
||||
parent: parentId,
|
||||
vfsType: 'directory',
|
||||
isVFS: true, // v4.3.3: Mark as VFS entity (internal)
|
||||
isVFSEntity: true, // v5.3.0: Explicit flag for developer filtering
|
||||
isVFS: true, // Mark as VFS entity (internal)
|
||||
isVFSEntity: true, // Explicit flag for developer filtering
|
||||
size: 0,
|
||||
permissions: options?.mode || this.config.permissions?.defaultDirectory || 0o755,
|
||||
owner: 'user',
|
||||
|
|
@ -900,8 +900,8 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
to: entity,
|
||||
type: VerbType.Contains,
|
||||
metadata: {
|
||||
isVFS: true, // v4.5.1: Mark as VFS relationship
|
||||
relationshipType: 'vfs' // v4.9.0: Standardized relationship type metadata
|
||||
isVFS: true, // Mark as VFS relationship
|
||||
relationshipType: 'vfs' // Standardized relationship type metadata
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -921,7 +921,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
/**
|
||||
* Remove a directory
|
||||
*
|
||||
* v6.4.0: Optimized for cloud storage using batch operations
|
||||
* Optimized for cloud storage using batch operations
|
||||
* - Uses gatherDescendants() for efficient graph traversal + batch fetch
|
||||
* - Uses deleteMany() for chunked transactional deletion
|
||||
* - Parallel blob cleanup with chunking
|
||||
|
|
@ -950,7 +950,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
throw new VFSError(VFSErrorCode.ENOTEMPTY, `Directory not empty: ${path}`, path, 'rmdir')
|
||||
}
|
||||
|
||||
// v6.4.0: OPTIMIZED batch deletion for recursive case
|
||||
// OPTIMIZED batch deletion for recursive case
|
||||
if (options?.recursive && children.length > 0) {
|
||||
// Phase 1: Gather all descendants in ONE batch fetch
|
||||
const descendants = await this.gatherDescendants(entityId, Infinity)
|
||||
|
|
@ -1020,7 +1020,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
children = children.slice(0, options.limit)
|
||||
}
|
||||
|
||||
// v6.2.0: REMOVED updateAccessTime() for performance
|
||||
// REMOVED updateAccessTime() for performance
|
||||
// Directory access time updates caused 50-100ms GCS write on EVERY readdir
|
||||
// await this.updateAccessTime(entityId) // ← REMOVED
|
||||
|
||||
|
|
@ -1117,7 +1117,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
offset: options?.offset,
|
||||
explain: options?.explain,
|
||||
where: {
|
||||
vfsType: 'file' // v4.7.0: Search VFS files
|
||||
vfsType: 'file' // Search VFS files
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1167,7 +1167,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
threshold: options?.threshold || 0.7,
|
||||
type: [NounType.File, NounType.Document, NounType.Media],
|
||||
where: {
|
||||
vfsType: 'file' // v4.7.0: Find similar VFS files
|
||||
vfsType: 'file' // Find similar VFS files
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -1294,7 +1294,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
return filename.substring(lastDot + 1).toLowerCase()
|
||||
}
|
||||
|
||||
// v5.2.0: MIME detection moved to MimeTypeDetector service
|
||||
// MIME detection moved to MimeTypeDetector service
|
||||
// Removed detectMimeType() and isTextFile() - now using mimeDetector singleton
|
||||
|
||||
private getFileNounType(mimeType: string): NounType {
|
||||
|
|
@ -1307,7 +1307,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
return NounType.File
|
||||
}
|
||||
|
||||
// v5.2.0: Removed compression methods (shouldCompress, compress, decompress)
|
||||
// Removed compression methods (shouldCompress, compress, decompress)
|
||||
// BlobStorage handles all compression automatically with zstd
|
||||
|
||||
private async generateEmbedding(buffer: Buffer, mimeType: string): Promise<number[] | undefined> {
|
||||
|
|
@ -1371,7 +1371,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
return metadata
|
||||
}
|
||||
|
||||
// v6.2.0: REMOVED updateAccessTime() method entirely
|
||||
// REMOVED updateAccessTime() method entirely
|
||||
// Access time updates caused 50-100ms GCS write on EVERY file/dir read
|
||||
// Modern file systems use 'noatime' for same reason
|
||||
// Field 'accessed' still exists in metadata for backward compat but won't update
|
||||
|
|
@ -1674,7 +1674,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
from: newParentId,
|
||||
to: entityId,
|
||||
type: VerbType.Contains,
|
||||
metadata: { isVFS: true } // v4.5.1: Mark as VFS relationship
|
||||
metadata: { isVFS: true } // Mark as VFS relationship
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1752,7 +1752,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
from: parentId,
|
||||
to: newEntity,
|
||||
type: VerbType.Contains,
|
||||
metadata: { isVFS: true } // v4.5.1: Mark as VFS relationship
|
||||
metadata: { isVFS: true } // Mark as VFS relationship
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1774,7 +1774,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
/**
|
||||
* Copy a directory recursively
|
||||
*
|
||||
* v6.4.0: Optimized for cloud storage using batch operations
|
||||
* Optimized for cloud storage using batch operations
|
||||
* - Uses gatherDescendants() for efficient graph traversal + batch fetch
|
||||
* - Uses addMany() for batch entity creation
|
||||
* - Uses relateMany() for batch relationship creation
|
||||
|
|
@ -1941,7 +1941,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
from: parentId,
|
||||
to: entity,
|
||||
type: VerbType.Contains,
|
||||
metadata: { isVFS: true } // v4.5.1: Mark as VFS relationship
|
||||
metadata: { isVFS: true } // Mark as VFS relationship
|
||||
})
|
||||
|
||||
// Update path resolver cache
|
||||
|
|
@ -2151,7 +2151,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
from: fromEntityId,
|
||||
to: toEntityId,
|
||||
type: type as any, // Convert string to VerbType
|
||||
metadata: { isVFS: true } // v4.5.1: Mark as VFS relationship
|
||||
metadata: { isVFS: true } // Mark as VFS relationship
|
||||
})
|
||||
|
||||
// Invalidate caches for both paths
|
||||
|
|
@ -2378,7 +2378,7 @@ export class VirtualFileSystem implements IVirtualFileSystem {
|
|||
/**
|
||||
* Bulk write operations for performance
|
||||
*
|
||||
* v6.5.0: Prevents race condition by processing mkdir operations
|
||||
* Prevents race condition by processing mkdir operations
|
||||
* sequentially before parallel batch processing of other operations.
|
||||
*/
|
||||
async bulkWrite(operations: Array<{
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export interface ImportOptions {
|
|||
showProgress?: boolean // Log progress (default: false)
|
||||
filter?: (path: string) => boolean // Custom filter function
|
||||
|
||||
// v4.10.0: Import tracking
|
||||
// Import tracking
|
||||
importId?: string // Unique import identifier (auto-generated if not provided)
|
||||
projectId?: string // Project identifier grouping related imports
|
||||
customMetadata?: Record<string, any> // Custom metadata to attach
|
||||
|
|
@ -66,7 +66,7 @@ export class DirectoryImporter {
|
|||
async import(sourcePath: string, options: ImportOptions = {}): Promise<ImportResult> {
|
||||
const startTime = Date.now()
|
||||
|
||||
// v4.10.0: Generate tracking metadata
|
||||
// Generate tracking metadata
|
||||
const importId = options.importId || uuidv4()
|
||||
const projectId = options.projectId || this.deriveProjectId(options.targetPath || '/')
|
||||
const trackingMetadata = {
|
||||
|
|
@ -225,7 +225,7 @@ export class DirectoryImporter {
|
|||
try {
|
||||
await this.vfs.mkdir(dirPath, {
|
||||
recursive: true,
|
||||
metadata: trackingMetadata // v4.10.0: Add tracking metadata
|
||||
metadata: trackingMetadata // Add tracking metadata
|
||||
})
|
||||
result.directoriesCreated++
|
||||
} catch (error: any) {
|
||||
|
|
@ -332,7 +332,7 @@ export class DirectoryImporter {
|
|||
originalPath: filePath,
|
||||
originalSize: stats.size,
|
||||
originalModified: stats.mtime.getTime(),
|
||||
...trackingMetadata // v4.10.0: Add tracking metadata
|
||||
...trackingMetadata // Add tracking metadata
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -382,6 +382,6 @@ export class DirectoryImporter {
|
|||
return false
|
||||
}
|
||||
|
||||
// v5.2.0: MIME detection moved to MimeTypeDetector service
|
||||
// MIME detection moved to MimeTypeDetector service
|
||||
// Removed detectMimeType() - now using mimeDetector singleton
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ export { VirtualFileSystem } from './VirtualFileSystem.js'
|
|||
export { PathResolver } from './PathResolver.js'
|
||||
export * from './types.js'
|
||||
|
||||
// MIME Type Detection (v5.2.0)
|
||||
// MIME Type Detection
|
||||
export { MimeTypeDetector, mimeDetector } from './MimeTypeDetector.js'
|
||||
|
||||
// fs compatibility layer
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ export class SemanticPathResolver {
|
|||
}
|
||||
|
||||
/**
|
||||
* Invalidate ALL caches (v6.3.0)
|
||||
* Invalidate ALL caches
|
||||
* Clears both traditional path cache AND semantic cache
|
||||
* Call this when switching branches, clearing data, or forking
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export class AuthorProjection extends BaseProjectionStrategy {
|
|||
* Resolve author to entity IDs using REAL Brainy.find()
|
||||
*/
|
||||
async resolve(brain: Brainy, vfs: VirtualFileSystem, authorName: string): Promise<string[]> {
|
||||
// v4.7.0: VFS entities are part of the knowledge graph
|
||||
// VFS entities are part of the knowledge graph
|
||||
const results = await brain.find({
|
||||
where: {
|
||||
vfsType: 'file',
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export class TagProjection extends BaseProjectionStrategy {
|
|||
* Resolve tag to entity IDs using REAL Brainy.find()
|
||||
*/
|
||||
async resolve(brain: Brainy, vfs: VirtualFileSystem, tagName: string): Promise<string[]> {
|
||||
// v4.7.0: VFS entities are part of the knowledge graph
|
||||
// VFS entities are part of the knowledge graph
|
||||
const results = await brain.find({
|
||||
where: {
|
||||
vfsType: 'file',
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export class TemporalProjection extends BaseProjectionStrategy {
|
|||
const endOfDay = new Date(date)
|
||||
endOfDay.setHours(23, 59, 59, 999)
|
||||
|
||||
// v4.7.0: VFS entities are part of the knowledge graph
|
||||
// VFS entities are part of the knowledge graph
|
||||
const results = await brain.find({
|
||||
where: {
|
||||
vfsType: 'file',
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ export interface VFSMetadata {
|
|||
name: string // Filename or directory name
|
||||
parent?: string // Parent directory entity ID
|
||||
vfsType: 'file' | 'directory' | 'symlink'
|
||||
isVFS?: boolean // v4.3.3: Mark as VFS entity (internal, separates from knowledge graph)
|
||||
isVFSEntity?: boolean // v5.3.0: Explicit developer-facing flag for filtering VFS entities
|
||||
isVFS?: boolean // Mark as VFS entity (internal, separates from knowledge graph)
|
||||
isVFSEntity?: boolean // Explicit developer-facing flag for filtering VFS entities
|
||||
|
||||
// File attributes
|
||||
size: number // Size in bytes (0 for directories)
|
||||
|
|
@ -50,7 +50,7 @@ export interface VFSMetadata {
|
|||
accessed: number // Last access timestamp (ms)
|
||||
modified: number // Last modification timestamp (ms)
|
||||
|
||||
// Content storage strategy (v5.2.0: unified blob storage)
|
||||
// Content storage strategy (unified blob storage)
|
||||
storage?: {
|
||||
type: 'blob' // All files now use BlobStorage (was 'inline'|'reference'|'chunked')
|
||||
hash: string // SHA-256 content hash from BlobStorage
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue