diff --git a/src/brainy.ts b/src/brainy.ts index 10b30d10..cb1b5fa3 100644 --- a/src/brainy.ts +++ b/src/brainy.ts @@ -2308,15 +2308,21 @@ export class Brainy implements BrainyInterface { // Update storage currentBranch (this.storage as any).currentBranch = branch - // Reload from new branch - // Clear indexes and reload + // v5.3.5 fix: Reload indexes from new branch WITHOUT recreating storage + // Previous implementation called init() which recreated storage, losing currentBranch this.index = this.setupIndex() this.metadataIndex = new (MetadataIndexManager as any)(this.storage) + await this.metadataIndex.init() this.graphIndex = new GraphAdjacencyIndex(this.storage) - // Re-initialize - this.initialized = false - await this.init() + // Rebuild indexes from new branch data + await this.rebuildIndexesIfNeeded() + + // Re-initialize VFS for new branch + if (this._vfs) { + this._vfs = new VirtualFileSystem(this) + await this._vfs.init() + } }) } diff --git a/src/storage/adapters/fileSystemStorage.ts b/src/storage/adapters/fileSystemStorage.ts index c7c0dcd1..fb1cfb7a 100644 --- a/src/storage/adapters/fileSystemStorage.ts +++ b/src/storage/adapters/fileSystemStorage.ts @@ -870,7 +870,10 @@ export class FileSystemStorage extends BaseStorage { for (const entry of entries) { if (entry.isFile()) { - // Handle both .json and .json.gz files + // v5.3.5: Handle multiple compression formats for broad compatibility + // - .json.gz: Standard entity/metadata files (JSON compressed) + // - .gz: COW files (refs, blobs, commits - raw compressed) + // - .json: Uncompressed JSON files if (entry.name.endsWith('.json.gz')) { // Strip .gz extension and add the .json path const normalizedName = entry.name.slice(0, -3) // Remove .gz @@ -879,6 +882,15 @@ export class FileSystemStorage extends BaseStorage { paths.push(normalizedPath) seen.add(normalizedPath) } + } else if (entry.name.endsWith('.gz')) { + // v5.3.5 fix: COW files stored as .gz (not .json.gz) + // Strip .gz extension and return path + const normalizedName = entry.name.slice(0, -3) // Remove .gz + const normalizedPath = path.join(prefix, normalizedName) + if (!seen.has(normalizedPath)) { + paths.push(normalizedPath) + seen.add(normalizedPath) + } } else if (entry.name.endsWith('.json')) { const filePath = path.join(prefix, entry.name) if (!seen.has(filePath)) { @@ -887,7 +899,8 @@ export class FileSystemStorage extends BaseStorage { } } } else if (entry.isDirectory()) { - const subdirPaths = await this.listObjectsUnderPath(path.join(prefix, entry.name)) + const subpath = path.join(prefix, entry.name) + const subdirPaths = await this.listObjectsUnderPath(subpath) paths.push(...subdirPaths) } } diff --git a/src/storage/baseStorage.ts b/src/storage/baseStorage.ts index 12da72f0..3b64e9b8 100644 --- a/src/storage/baseStorage.ts +++ b/src/storage/baseStorage.ts @@ -279,10 +279,22 @@ export abstract class BaseStorage extends BaseStorageAdapter { list: async (prefix: string): Promise => { try { - const paths = await this.listObjectsUnderPath(`_cow/${prefix}`) + // v5.3.5 fix: Handle file prefixes, not just directory paths + // Refs are stored as files like: _cow/ref:refs/heads/main + // So list('ref:') should find all files starting with '_cow/ref:' + + // List the _cow directory and filter by prefix + const allPaths = await this.listObjectsUnderPath('_cow/') + const filteredPaths = allPaths.filter(p => { + // Remove _cow/ prefix to get the key + const key = p.replace(/^_cow\//, '') + return key.startsWith(prefix) + }) + // Remove _cow/ prefix and return relative keys - return paths.map(p => p.replace(/^_cow\//, '')) - } catch (error) { + return filteredPaths.map(p => p.replace(/^_cow\//, '')) + } catch (error: any) { + // If _cow directory doesn't exist yet, return empty array return [] } }