@soulcraft/brainy 5.3.4 → 5.3.6
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 +14 -0
- package/dist/brainy.js +19 -6
- package/dist/storage/adapters/fileSystemStorage.js +16 -2
- package/dist/storage/baseStorage.js +19 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
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.6](https://github.com/soulcraftlabs/brainy/compare/v5.3.5...v5.3.6) (2025-11-05)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### 🐛 Bug Fixes
|
|
9
|
+
|
|
10
|
+
* resolve fork() silent failure on cloud storage adapters ([7977132](https://github.com/soulcraftlabs/brainy/commit/7977132e9f7160af1cb1b9dd1f16f623aa1010f0))
|
|
11
|
+
|
|
12
|
+
### [5.3.5](https://github.com/soulcraftlabs/brainy/compare/v5.3.4...v5.3.5) (2025-11-05)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug Fixes
|
|
16
|
+
|
|
17
|
+
* resolve fork + checkout workflow with COW file listing and branch persistence ([189b1b0](https://github.com/soulcraftlabs/brainy/commit/189b1b05dec4daad28a9ce7e0840ffaaf675ecfa))
|
|
18
|
+
|
|
5
19
|
### [5.3.0](https://github.com/soulcraftlabs/brainy/compare/v5.2.1...v5.3.0) (2025-11-04)
|
|
6
20
|
|
|
7
21
|
- feat: add entity versioning system with critical bug fixes (v5.3.0) (c488fa8)
|
package/dist/brainy.js
CHANGED
|
@@ -1884,7 +1884,15 @@ export class Brainy {
|
|
|
1884
1884
|
}
|
|
1885
1885
|
// Step 2: Copy storage ref (COW layer - instant!)
|
|
1886
1886
|
await refManager.copyRef(currentBranch, branchName);
|
|
1887
|
-
//
|
|
1887
|
+
// CRITICAL FIX (v5.3.6): Verify branch was actually created to prevent silent failures
|
|
1888
|
+
// Without this check, fork() could complete successfully but branch wouldn't exist,
|
|
1889
|
+
// causing subsequent checkout() calls to fail (see Workshop bug report).
|
|
1890
|
+
const verifyBranch = await refManager.getRef(branchName);
|
|
1891
|
+
if (!verifyBranch) {
|
|
1892
|
+
throw new Error(`Fork failed: Branch '${branchName}' was not created. ` +
|
|
1893
|
+
`This indicates a storage adapter configuration issue. Please report this bug.`);
|
|
1894
|
+
}
|
|
1895
|
+
// Step 3: Create new Brainy instance pointing to fork branch
|
|
1888
1896
|
const forkConfig = {
|
|
1889
1897
|
...this.config,
|
|
1890
1898
|
storage: {
|
|
@@ -1993,14 +2001,19 @@ export class Brainy {
|
|
|
1993
2001
|
}
|
|
1994
2002
|
// Update storage currentBranch
|
|
1995
2003
|
this.storage.currentBranch = branch;
|
|
1996
|
-
// Reload from new branch
|
|
1997
|
-
//
|
|
2004
|
+
// v5.3.5 fix: Reload indexes from new branch WITHOUT recreating storage
|
|
2005
|
+
// Previous implementation called init() which recreated storage, losing currentBranch
|
|
1998
2006
|
this.index = this.setupIndex();
|
|
1999
2007
|
this.metadataIndex = new MetadataIndexManager(this.storage);
|
|
2008
|
+
await this.metadataIndex.init();
|
|
2000
2009
|
this.graphIndex = new GraphAdjacencyIndex(this.storage);
|
|
2001
|
-
//
|
|
2002
|
-
this.
|
|
2003
|
-
|
|
2010
|
+
// Rebuild indexes from new branch data
|
|
2011
|
+
await this.rebuildIndexesIfNeeded();
|
|
2012
|
+
// Re-initialize VFS for new branch
|
|
2013
|
+
if (this._vfs) {
|
|
2014
|
+
this._vfs = new VirtualFileSystem(this);
|
|
2015
|
+
await this._vfs.init();
|
|
2016
|
+
}
|
|
2004
2017
|
});
|
|
2005
2018
|
}
|
|
2006
2019
|
/**
|
|
@@ -736,7 +736,10 @@ export class FileSystemStorage extends BaseStorage {
|
|
|
736
736
|
const entries = await fs.promises.readdir(fullPath, { withFileTypes: true });
|
|
737
737
|
for (const entry of entries) {
|
|
738
738
|
if (entry.isFile()) {
|
|
739
|
-
// Handle
|
|
739
|
+
// v5.3.5: Handle multiple compression formats for broad compatibility
|
|
740
|
+
// - .json.gz: Standard entity/metadata files (JSON compressed)
|
|
741
|
+
// - .gz: COW files (refs, blobs, commits - raw compressed)
|
|
742
|
+
// - .json: Uncompressed JSON files
|
|
740
743
|
if (entry.name.endsWith('.json.gz')) {
|
|
741
744
|
// Strip .gz extension and add the .json path
|
|
742
745
|
const normalizedName = entry.name.slice(0, -3); // Remove .gz
|
|
@@ -746,6 +749,16 @@ export class FileSystemStorage extends BaseStorage {
|
|
|
746
749
|
seen.add(normalizedPath);
|
|
747
750
|
}
|
|
748
751
|
}
|
|
752
|
+
else if (entry.name.endsWith('.gz')) {
|
|
753
|
+
// v5.3.5 fix: COW files stored as .gz (not .json.gz)
|
|
754
|
+
// Strip .gz extension and return path
|
|
755
|
+
const normalizedName = entry.name.slice(0, -3); // Remove .gz
|
|
756
|
+
const normalizedPath = path.join(prefix, normalizedName);
|
|
757
|
+
if (!seen.has(normalizedPath)) {
|
|
758
|
+
paths.push(normalizedPath);
|
|
759
|
+
seen.add(normalizedPath);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
749
762
|
else if (entry.name.endsWith('.json')) {
|
|
750
763
|
const filePath = path.join(prefix, entry.name);
|
|
751
764
|
if (!seen.has(filePath)) {
|
|
@@ -755,7 +768,8 @@ export class FileSystemStorage extends BaseStorage {
|
|
|
755
768
|
}
|
|
756
769
|
}
|
|
757
770
|
else if (entry.isDirectory()) {
|
|
758
|
-
const
|
|
771
|
+
const subpath = path.join(prefix, entry.name);
|
|
772
|
+
const subdirPaths = await this.listObjectsUnderPath(subpath);
|
|
759
773
|
paths.push(...subdirPaths);
|
|
760
774
|
}
|
|
761
775
|
}
|
|
@@ -201,11 +201,21 @@ export class BaseStorage extends BaseStorageAdapter {
|
|
|
201
201
|
},
|
|
202
202
|
list: async (prefix) => {
|
|
203
203
|
try {
|
|
204
|
-
|
|
204
|
+
// v5.3.5 fix: Handle file prefixes, not just directory paths
|
|
205
|
+
// Refs are stored as files like: _cow/ref:refs/heads/main
|
|
206
|
+
// So list('ref:') should find all files starting with '_cow/ref:'
|
|
207
|
+
// List the _cow directory and filter by prefix
|
|
208
|
+
const allPaths = await this.listObjectsUnderPath('_cow/');
|
|
209
|
+
const filteredPaths = allPaths.filter(p => {
|
|
210
|
+
// Remove _cow/ prefix to get the key
|
|
211
|
+
const key = p.replace(/^_cow\//, '');
|
|
212
|
+
return key.startsWith(prefix);
|
|
213
|
+
});
|
|
205
214
|
// Remove _cow/ prefix and return relative keys
|
|
206
|
-
return
|
|
215
|
+
return filteredPaths.map(p => p.replace(/^_cow\//, ''));
|
|
207
216
|
}
|
|
208
217
|
catch (error) {
|
|
218
|
+
// If _cow directory doesn't exist yet, return empty array
|
|
209
219
|
return [];
|
|
210
220
|
}
|
|
211
221
|
}
|
|
@@ -264,6 +274,13 @@ export class BaseStorage extends BaseStorageAdapter {
|
|
|
264
274
|
* @protected - Available to subclasses for COW implementation
|
|
265
275
|
*/
|
|
266
276
|
resolveBranchPath(basePath, branch) {
|
|
277
|
+
// CRITICAL FIX (v5.3.6): COW metadata (_cow/*) must NEVER be branch-scoped
|
|
278
|
+
// Refs, commits, and blobs are global metadata with their own internal branching.
|
|
279
|
+
// Branch-scoping COW paths causes fork() to write refs to wrong locations,
|
|
280
|
+
// leading to "Branch does not exist" errors on checkout (see Workshop bug report).
|
|
281
|
+
if (basePath.startsWith('_cow/')) {
|
|
282
|
+
return basePath; // COW metadata is global across all branches
|
|
283
|
+
}
|
|
267
284
|
if (!this.cowEnabled) {
|
|
268
285
|
return basePath; // COW disabled, use direct path
|
|
269
286
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soulcraft/brainy",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.6",
|
|
4
4
|
"description": "Universal Knowledge Protocol™ - World's first Triple Intelligence database unifying vector, graph, and document search in one API. 31 nouns × 40 verbs for infinite expressiveness.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|