@soulcraft/brainy 5.11.1 → 6.0.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.
- package/CHANGELOG.md +155 -5
- package/README.md +2 -6
- package/dist/api/DataAPI.d.ts +0 -40
- package/dist/api/DataAPI.js +0 -235
- package/dist/brainy.d.ts +28 -106
- package/dist/brainy.js +53 -370
- package/dist/cli/commands/cow.d.ts +1 -9
- package/dist/cli/commands/cow.js +1 -61
- package/dist/cli/commands/data.d.ts +1 -13
- package/dist/cli/commands/data.js +1 -74
- package/dist/cli/index.js +1 -16
- package/dist/neural/embeddedTypeEmbeddings.d.ts +1 -1
- package/dist/neural/embeddedTypeEmbeddings.js +2 -2
- package/dist/storage/adapters/azureBlobStorage.d.ts +21 -7
- package/dist/storage/adapters/azureBlobStorage.js +69 -14
- package/dist/storage/adapters/fileSystemStorage.js +2 -1
- package/dist/storage/adapters/gcsStorage.d.ts +29 -15
- package/dist/storage/adapters/gcsStorage.js +82 -27
- package/dist/storage/adapters/historicalStorageAdapter.js +2 -2
- package/dist/storage/adapters/memoryStorage.d.ts +1 -1
- package/dist/storage/adapters/memoryStorage.js +9 -11
- package/dist/storage/adapters/opfsStorage.js +2 -1
- package/dist/storage/adapters/r2Storage.d.ts +21 -10
- package/dist/storage/adapters/r2Storage.js +73 -17
- package/dist/storage/adapters/s3CompatibleStorage.d.ts +20 -7
- package/dist/storage/adapters/s3CompatibleStorage.js +72 -14
- package/dist/storage/baseStorage.d.ts +153 -24
- package/dist/storage/baseStorage.js +758 -459
- package/dist/vfs/PathResolver.js +6 -2
- package/dist/vfs/VirtualFileSystem.d.ts +46 -24
- package/dist/vfs/VirtualFileSystem.js +176 -156
- package/package.json +1 -1
package/dist/vfs/PathResolver.js
CHANGED
|
@@ -164,9 +164,13 @@ export class PathResolver {
|
|
|
164
164
|
});
|
|
165
165
|
const validChildren = [];
|
|
166
166
|
const childNames = new Set();
|
|
167
|
-
//
|
|
167
|
+
// v5.12.0: Batch fetch all child entities (eliminates N+1 query pattern)
|
|
168
|
+
// This is WIRED UP AND USED - no longer a stub!
|
|
169
|
+
const childIds = relations.map(r => r.to);
|
|
170
|
+
const childrenMap = await this.brain.batchGet(childIds);
|
|
171
|
+
// Process batched results
|
|
168
172
|
for (const relation of relations) {
|
|
169
|
-
const entity =
|
|
173
|
+
const entity = childrenMap.get(relation.to);
|
|
170
174
|
if (entity && entity.metadata?.vfsType && entity.metadata?.name) {
|
|
171
175
|
validChildren.push(entity);
|
|
172
176
|
childNames.add(entity.metadata.name);
|
|
@@ -218,14 +218,6 @@ export declare class VirtualFileSystem implements IVirtualFileSystem {
|
|
|
218
218
|
* Get the current user
|
|
219
219
|
*/
|
|
220
220
|
getCurrentUser(): string;
|
|
221
|
-
/**
|
|
222
|
-
* Get all todos recursively from a path
|
|
223
|
-
*/
|
|
224
|
-
getAllTodos(path?: string): Promise<VFSTodo[]>;
|
|
225
|
-
/**
|
|
226
|
-
* Export directory structure to JSON
|
|
227
|
-
*/
|
|
228
|
-
exportToJSON(path?: string): Promise<any>;
|
|
229
221
|
/**
|
|
230
222
|
* Search for entities with filters
|
|
231
223
|
*/
|
|
@@ -256,23 +248,53 @@ export declare class VirtualFileSystem implements IVirtualFileSystem {
|
|
|
256
248
|
}>;
|
|
257
249
|
}>;
|
|
258
250
|
/**
|
|
259
|
-
*
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
latest: Date;
|
|
274
|
-
} | null;
|
|
251
|
+
* Calculate disk usage for a path (POSIX du command)
|
|
252
|
+
* Returns total bytes used by files in directory tree
|
|
253
|
+
*
|
|
254
|
+
* @param path - Path to calculate usage for
|
|
255
|
+
* @param options - Options including maxDepth for safety
|
|
256
|
+
*/
|
|
257
|
+
du(path?: string, options?: {
|
|
258
|
+
maxDepth?: number;
|
|
259
|
+
humanReadable?: boolean;
|
|
260
|
+
}): Promise<{
|
|
261
|
+
bytes: number;
|
|
262
|
+
files: number;
|
|
263
|
+
directories: number;
|
|
264
|
+
formatted?: string;
|
|
275
265
|
}>;
|
|
266
|
+
/**
|
|
267
|
+
* Check file access permissions (POSIX access command)
|
|
268
|
+
* Verifies if path exists and is accessible with specified mode
|
|
269
|
+
*
|
|
270
|
+
* @param path - Path to check
|
|
271
|
+
* @param mode - Access mode: 'r' (read), 'w' (write), 'x' (execute), or 'f' (exists only)
|
|
272
|
+
*/
|
|
273
|
+
access(path: string, mode?: 'r' | 'w' | 'x' | 'f'): Promise<boolean>;
|
|
274
|
+
/**
|
|
275
|
+
* Find files matching patterns (Unix find command)
|
|
276
|
+
* Pattern-based file search (complements semantic search())
|
|
277
|
+
*
|
|
278
|
+
* @param path - Starting path for search
|
|
279
|
+
* @param options - Search options including pattern matching
|
|
280
|
+
*/
|
|
281
|
+
find(path?: string, options?: {
|
|
282
|
+
name?: string | RegExp;
|
|
283
|
+
type?: 'file' | 'directory' | 'both';
|
|
284
|
+
maxDepth?: number;
|
|
285
|
+
minSize?: number;
|
|
286
|
+
maxSize?: number;
|
|
287
|
+
modified?: {
|
|
288
|
+
after?: Date;
|
|
289
|
+
before?: Date;
|
|
290
|
+
};
|
|
291
|
+
limit?: number;
|
|
292
|
+
}): Promise<Array<{
|
|
293
|
+
path: string;
|
|
294
|
+
type: 'file' | 'directory';
|
|
295
|
+
size?: number;
|
|
296
|
+
modified?: Date;
|
|
297
|
+
}>>;
|
|
276
298
|
/**
|
|
277
299
|
* Get all versions of a file (semantic versioning)
|
|
278
300
|
*/
|
|
@@ -477,19 +477,32 @@ export class VirtualFileSystem {
|
|
|
477
477
|
if (entity.metadata.vfsType !== 'directory') {
|
|
478
478
|
throw new VFSError(VFSErrorCode.ENOTDIR, `Not a directory: ${path}`, path, 'getTreeStructure');
|
|
479
479
|
}
|
|
480
|
-
//
|
|
480
|
+
// v5.12.0: Parallel breadth-first traversal for maximum cloud performance
|
|
481
|
+
// OLD: Sequential depth-first → 12.7s for 12 files (22 sequential calls × 580ms)
|
|
482
|
+
// NEW: Parallel breadth-first → <1s for 12 files (batched levels)
|
|
481
483
|
const allEntities = [];
|
|
482
484
|
const visited = new Set();
|
|
483
|
-
const gatherDescendants = async (
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
485
|
+
const gatherDescendants = async (rootId) => {
|
|
486
|
+
visited.add(rootId); // Mark root as visited
|
|
487
|
+
let currentLevel = [rootId];
|
|
488
|
+
while (currentLevel.length > 0) {
|
|
489
|
+
// v5.12.0: Fetch all directories at this level IN PARALLEL
|
|
490
|
+
// PathResolver.getChildren() uses brain.batchGet() internally - double win!
|
|
491
|
+
const childrenArrays = await Promise.all(currentLevel.map(dirId => this.pathResolver.getChildren(dirId)));
|
|
492
|
+
const nextLevel = [];
|
|
493
|
+
// Process all children from this level
|
|
494
|
+
for (const children of childrenArrays) {
|
|
495
|
+
for (const child of children) {
|
|
496
|
+
allEntities.push(child);
|
|
497
|
+
// Queue subdirectories for next level (breadth-first)
|
|
498
|
+
if (child.metadata.vfsType === 'directory' && !visited.has(child.id)) {
|
|
499
|
+
visited.add(child.id);
|
|
500
|
+
nextLevel.push(child.id);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
492
503
|
}
|
|
504
|
+
// Move to next level
|
|
505
|
+
currentLevel = nextLevel;
|
|
493
506
|
}
|
|
494
507
|
};
|
|
495
508
|
await gatherDescendants(entityId);
|
|
@@ -1765,101 +1778,6 @@ export class VirtualFileSystem {
|
|
|
1765
1778
|
getCurrentUser() {
|
|
1766
1779
|
return this.currentUser;
|
|
1767
1780
|
}
|
|
1768
|
-
/**
|
|
1769
|
-
* Get all todos recursively from a path
|
|
1770
|
-
*/
|
|
1771
|
-
async getAllTodos(path = '/') {
|
|
1772
|
-
await this.ensureInitialized();
|
|
1773
|
-
const allTodos = [];
|
|
1774
|
-
// Get entity for this path
|
|
1775
|
-
try {
|
|
1776
|
-
const entityId = await this.pathResolver.resolve(path);
|
|
1777
|
-
const entity = await this.getEntityById(entityId);
|
|
1778
|
-
// Add todos from this entity
|
|
1779
|
-
if (entity.metadata.todos) {
|
|
1780
|
-
allTodos.push(...entity.metadata.todos);
|
|
1781
|
-
}
|
|
1782
|
-
// If it's a directory, recursively get todos from children
|
|
1783
|
-
if (entity.metadata.vfsType === 'directory') {
|
|
1784
|
-
const children = await this.readdir(path);
|
|
1785
|
-
for (const child of children) {
|
|
1786
|
-
const childPath = path === '/' ? `/${child}` : `${path}/${child}`;
|
|
1787
|
-
const childTodos = await this.getAllTodos(childPath);
|
|
1788
|
-
allTodos.push(...childTodos);
|
|
1789
|
-
}
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
catch (error) {
|
|
1793
|
-
// Path doesn't exist, return empty
|
|
1794
|
-
}
|
|
1795
|
-
return allTodos;
|
|
1796
|
-
}
|
|
1797
|
-
/**
|
|
1798
|
-
* Export directory structure to JSON
|
|
1799
|
-
*/
|
|
1800
|
-
async exportToJSON(path = '/') {
|
|
1801
|
-
await this.ensureInitialized();
|
|
1802
|
-
const result = {};
|
|
1803
|
-
const traverse = async (currentPath, target) => {
|
|
1804
|
-
try {
|
|
1805
|
-
const entityId = await this.pathResolver.resolve(currentPath);
|
|
1806
|
-
const entity = await this.getEntityById(entityId);
|
|
1807
|
-
if (entity.metadata.vfsType === 'directory') {
|
|
1808
|
-
// Add directory metadata
|
|
1809
|
-
target._meta = {
|
|
1810
|
-
type: 'directory',
|
|
1811
|
-
path: currentPath,
|
|
1812
|
-
modified: entity.metadata.modified ? new Date(entity.metadata.modified) : undefined
|
|
1813
|
-
};
|
|
1814
|
-
// Traverse children
|
|
1815
|
-
const children = await this.readdir(currentPath);
|
|
1816
|
-
for (const child of children) {
|
|
1817
|
-
const childName = typeof child === 'string' ? child : child.name;
|
|
1818
|
-
const childPath = currentPath === '/' ? `/${childName}` : `${currentPath}/${childName}`;
|
|
1819
|
-
target[childName] = {};
|
|
1820
|
-
await traverse(childPath, target[childName]);
|
|
1821
|
-
}
|
|
1822
|
-
}
|
|
1823
|
-
else if (entity.metadata.vfsType === 'file') {
|
|
1824
|
-
// For files, include content and metadata
|
|
1825
|
-
try {
|
|
1826
|
-
const content = await this.readFile(currentPath);
|
|
1827
|
-
const textContent = content.toString('utf8');
|
|
1828
|
-
// Try to parse JSON files
|
|
1829
|
-
if (currentPath.endsWith('.json')) {
|
|
1830
|
-
try {
|
|
1831
|
-
target._content = JSON.parse(textContent);
|
|
1832
|
-
}
|
|
1833
|
-
catch {
|
|
1834
|
-
target._content = textContent;
|
|
1835
|
-
}
|
|
1836
|
-
}
|
|
1837
|
-
else {
|
|
1838
|
-
target._content = textContent;
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
|
-
catch {
|
|
1842
|
-
// Binary or unreadable file
|
|
1843
|
-
target._content = '[binary]';
|
|
1844
|
-
}
|
|
1845
|
-
target._meta = {
|
|
1846
|
-
type: 'file',
|
|
1847
|
-
path: currentPath,
|
|
1848
|
-
size: entity.metadata.size || 0,
|
|
1849
|
-
mimeType: entity.metadata.mimeType,
|
|
1850
|
-
modified: entity.metadata.modified ? new Date(entity.metadata.modified) : undefined,
|
|
1851
|
-
todos: entity.metadata.todos || []
|
|
1852
|
-
};
|
|
1853
|
-
}
|
|
1854
|
-
}
|
|
1855
|
-
catch (error) {
|
|
1856
|
-
// Skip inaccessible paths
|
|
1857
|
-
target._error = 'inaccessible';
|
|
1858
|
-
}
|
|
1859
|
-
};
|
|
1860
|
-
await traverse(path, result);
|
|
1861
|
-
return result;
|
|
1862
|
-
}
|
|
1863
1781
|
/**
|
|
1864
1782
|
* Search for entities with filters
|
|
1865
1783
|
*/
|
|
@@ -1937,78 +1855,180 @@ export class VirtualFileSystem {
|
|
|
1937
1855
|
return result;
|
|
1938
1856
|
}
|
|
1939
1857
|
/**
|
|
1940
|
-
*
|
|
1858
|
+
* Calculate disk usage for a path (POSIX du command)
|
|
1859
|
+
* Returns total bytes used by files in directory tree
|
|
1860
|
+
*
|
|
1861
|
+
* @param path - Path to calculate usage for
|
|
1862
|
+
* @param options - Options including maxDepth for safety
|
|
1941
1863
|
*/
|
|
1942
|
-
async
|
|
1864
|
+
async du(path = '/', options) {
|
|
1943
1865
|
await this.ensureInitialized();
|
|
1944
|
-
const
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
};
|
|
1953
|
-
let earliestModified = null;
|
|
1954
|
-
let latestModified = null;
|
|
1955
|
-
const traverse = async (currentPath, isRoot = false) => {
|
|
1866
|
+
const maxDepth = options?.maxDepth ?? 100; // Safety limit
|
|
1867
|
+
let totalBytes = 0;
|
|
1868
|
+
let fileCount = 0;
|
|
1869
|
+
let dirCount = 0;
|
|
1870
|
+
const traverse = async (currentPath, depth) => {
|
|
1871
|
+
if (depth > maxDepth) {
|
|
1872
|
+
throw new Error(`Maximum depth ${maxDepth} exceeded. Use maxDepth option to increase limit.`);
|
|
1873
|
+
}
|
|
1956
1874
|
try {
|
|
1957
1875
|
const entityId = await this.pathResolver.resolve(currentPath);
|
|
1958
1876
|
const entity = await this.getEntityById(entityId);
|
|
1959
1877
|
if (entity.metadata.vfsType === 'directory') {
|
|
1960
|
-
|
|
1961
|
-
if (!isRoot) {
|
|
1962
|
-
stats.directoryCount++;
|
|
1963
|
-
}
|
|
1964
|
-
// Traverse children
|
|
1878
|
+
dirCount++;
|
|
1965
1879
|
const children = await this.readdir(currentPath);
|
|
1966
1880
|
for (const child of children) {
|
|
1967
1881
|
const childPath = currentPath === '/' ? `/${child}` : `${currentPath}/${child}`;
|
|
1968
|
-
await traverse(childPath,
|
|
1882
|
+
await traverse(childPath, depth + 1);
|
|
1969
1883
|
}
|
|
1970
1884
|
}
|
|
1971
1885
|
else if (entity.metadata.vfsType === 'file') {
|
|
1972
|
-
|
|
1886
|
+
fileCount++;
|
|
1887
|
+
totalBytes += entity.metadata.size || 0;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
catch (error) {
|
|
1891
|
+
// Skip inaccessible paths
|
|
1892
|
+
}
|
|
1893
|
+
};
|
|
1894
|
+
await traverse(path, 0);
|
|
1895
|
+
const result = {
|
|
1896
|
+
bytes: totalBytes,
|
|
1897
|
+
files: fileCount,
|
|
1898
|
+
directories: dirCount
|
|
1899
|
+
};
|
|
1900
|
+
if (options?.humanReadable) {
|
|
1901
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
1902
|
+
let size = totalBytes;
|
|
1903
|
+
let unitIndex = 0;
|
|
1904
|
+
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
1905
|
+
size /= 1024;
|
|
1906
|
+
unitIndex++;
|
|
1907
|
+
}
|
|
1908
|
+
result.formatted = `${size.toFixed(2)} ${units[unitIndex]}`;
|
|
1909
|
+
}
|
|
1910
|
+
return result;
|
|
1911
|
+
}
|
|
1912
|
+
/**
|
|
1913
|
+
* Check file access permissions (POSIX access command)
|
|
1914
|
+
* Verifies if path exists and is accessible with specified mode
|
|
1915
|
+
*
|
|
1916
|
+
* @param path - Path to check
|
|
1917
|
+
* @param mode - Access mode: 'r' (read), 'w' (write), 'x' (execute), or 'f' (exists only)
|
|
1918
|
+
*/
|
|
1919
|
+
async access(path, mode = 'f') {
|
|
1920
|
+
await this.ensureInitialized();
|
|
1921
|
+
try {
|
|
1922
|
+
const entityId = await this.pathResolver.resolve(path);
|
|
1923
|
+
const entity = await this.getEntityById(entityId);
|
|
1924
|
+
// Path exists
|
|
1925
|
+
if (mode === 'f') {
|
|
1926
|
+
return true;
|
|
1927
|
+
}
|
|
1928
|
+
// Check permissions based on mode
|
|
1929
|
+
const permissions = entity.metadata.permissions || 0o644;
|
|
1930
|
+
switch (mode) {
|
|
1931
|
+
case 'r':
|
|
1932
|
+
// Check read permission (owner, group, or other)
|
|
1933
|
+
return (permissions & 0o444) !== 0;
|
|
1934
|
+
case 'w':
|
|
1935
|
+
// Check write permission
|
|
1936
|
+
return (permissions & 0o222) !== 0;
|
|
1937
|
+
case 'x':
|
|
1938
|
+
// Check execute permission (only meaningful for directories)
|
|
1939
|
+
return entity.metadata.vfsType === 'directory' || (permissions & 0o111) !== 0;
|
|
1940
|
+
default:
|
|
1941
|
+
return false;
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
catch (error) {
|
|
1945
|
+
// Path doesn't exist or not accessible
|
|
1946
|
+
return false;
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
/**
|
|
1950
|
+
* Find files matching patterns (Unix find command)
|
|
1951
|
+
* Pattern-based file search (complements semantic search())
|
|
1952
|
+
*
|
|
1953
|
+
* @param path - Starting path for search
|
|
1954
|
+
* @param options - Search options including pattern matching
|
|
1955
|
+
*/
|
|
1956
|
+
async find(path = '/', options) {
|
|
1957
|
+
await this.ensureInitialized();
|
|
1958
|
+
const maxDepth = options?.maxDepth ?? 100; // Safety limit
|
|
1959
|
+
const limit = options?.limit ?? 1000; // Prevent unbounded results
|
|
1960
|
+
const results = [];
|
|
1961
|
+
const namePattern = options?.name;
|
|
1962
|
+
const nameRegex = namePattern instanceof RegExp
|
|
1963
|
+
? namePattern
|
|
1964
|
+
: namePattern
|
|
1965
|
+
? new RegExp(namePattern.replace(/\*/g, '.*').replace(/\?/g, '.'))
|
|
1966
|
+
: null;
|
|
1967
|
+
const traverse = async (currentPath, depth) => {
|
|
1968
|
+
if (depth > maxDepth || results.length >= limit) {
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
try {
|
|
1972
|
+
const entityId = await this.pathResolver.resolve(currentPath);
|
|
1973
|
+
const entity = await this.getEntityById(entityId);
|
|
1974
|
+
const vfsType = entity.metadata.vfsType;
|
|
1975
|
+
const fileName = currentPath.split('/').pop() || '';
|
|
1976
|
+
// Check if this file matches criteria
|
|
1977
|
+
let matches = true;
|
|
1978
|
+
// Type filter
|
|
1979
|
+
if (options?.type && options.type !== 'both') {
|
|
1980
|
+
matches = matches && vfsType === options.type;
|
|
1981
|
+
}
|
|
1982
|
+
// Name pattern filter
|
|
1983
|
+
if (nameRegex) {
|
|
1984
|
+
matches = matches && nameRegex.test(fileName);
|
|
1985
|
+
}
|
|
1986
|
+
// Size filters (files only)
|
|
1987
|
+
if (vfsType === 'file') {
|
|
1973
1988
|
const size = entity.metadata.size || 0;
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
if (!stats.largestFile || size > stats.largestFile.size) {
|
|
1977
|
-
stats.largestFile = { path: currentPath, size };
|
|
1989
|
+
if (options?.minSize !== undefined) {
|
|
1990
|
+
matches = matches && size >= options.minSize;
|
|
1978
1991
|
}
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1992
|
+
if (options?.maxSize !== undefined) {
|
|
1993
|
+
matches = matches && size <= options.maxSize;
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
// Modified time filter
|
|
1997
|
+
if (options?.modified && entity.metadata.modified) {
|
|
1998
|
+
const modifiedTime = new Date(entity.metadata.modified);
|
|
1999
|
+
if (options.modified.after) {
|
|
2000
|
+
matches = matches && modifiedTime >= options.modified.after;
|
|
2001
|
+
}
|
|
2002
|
+
if (options.modified.before) {
|
|
2003
|
+
matches = matches && modifiedTime <= options.modified.before;
|
|
1988
2004
|
}
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
2005
|
+
}
|
|
2006
|
+
// Add to results if matches
|
|
2007
|
+
if (matches && currentPath !== path) {
|
|
2008
|
+
results.push({
|
|
2009
|
+
path: currentPath,
|
|
2010
|
+
type: vfsType,
|
|
2011
|
+
size: entity.metadata.size,
|
|
2012
|
+
modified: entity.metadata.modified ? new Date(entity.metadata.modified) : undefined
|
|
2013
|
+
});
|
|
2014
|
+
}
|
|
2015
|
+
// Recurse into directories
|
|
2016
|
+
if (vfsType === 'directory' && results.length < limit) {
|
|
2017
|
+
const children = await this.readdir(currentPath);
|
|
2018
|
+
for (const child of children) {
|
|
2019
|
+
if (results.length >= limit)
|
|
2020
|
+
break;
|
|
2021
|
+
const childPath = currentPath === '/' ? `/${child}` : `${currentPath}/${child}`;
|
|
2022
|
+
await traverse(childPath, depth + 1);
|
|
1992
2023
|
}
|
|
1993
2024
|
}
|
|
1994
2025
|
}
|
|
1995
2026
|
catch (error) {
|
|
1996
|
-
// Skip
|
|
2027
|
+
// Skip inaccessible paths
|
|
1997
2028
|
}
|
|
1998
2029
|
};
|
|
1999
|
-
await traverse(path,
|
|
2000
|
-
|
|
2001
|
-
if (stats.fileCount > 0) {
|
|
2002
|
-
stats.averageFileSize = Math.round(stats.totalSize / stats.fileCount);
|
|
2003
|
-
}
|
|
2004
|
-
// Set date range
|
|
2005
|
-
if (earliestModified && latestModified) {
|
|
2006
|
-
stats.modifiedRange = {
|
|
2007
|
-
earliest: new Date(earliestModified),
|
|
2008
|
-
latest: new Date(latestModified)
|
|
2009
|
-
};
|
|
2010
|
-
}
|
|
2011
|
-
return stats;
|
|
2030
|
+
await traverse(path, 0);
|
|
2031
|
+
return results;
|
|
2012
2032
|
}
|
|
2013
2033
|
/**
|
|
2014
2034
|
* Get all versions of a file (semantic versioning)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soulcraft/brainy",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Universal Knowledge Protocol™ - World's first Triple Intelligence database unifying vector, graph, and document search in one API. Stage 3 CANONICAL: 42 nouns × 127 verbs covering 96-97% of all human knowledge.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|