@soulcraft/brainy 5.12.0 → 6.0.1

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.
@@ -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
- * Get project statistics for a path
260
- */
261
- getProjectStats(path?: string): Promise<{
262
- fileCount: number;
263
- directoryCount: number;
264
- totalSize: number;
265
- todoCount: number;
266
- averageFileSize: number;
267
- largestFile: {
268
- path: string;
269
- size: number;
270
- } | null;
271
- modifiedRange: {
272
- earliest: Date;
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
  */
@@ -1778,101 +1778,6 @@ export class VirtualFileSystem {
1778
1778
  getCurrentUser() {
1779
1779
  return this.currentUser;
1780
1780
  }
1781
- /**
1782
- * Get all todos recursively from a path
1783
- */
1784
- async getAllTodos(path = '/') {
1785
- await this.ensureInitialized();
1786
- const allTodos = [];
1787
- // Get entity for this path
1788
- try {
1789
- const entityId = await this.pathResolver.resolve(path);
1790
- const entity = await this.getEntityById(entityId);
1791
- // Add todos from this entity
1792
- if (entity.metadata.todos) {
1793
- allTodos.push(...entity.metadata.todos);
1794
- }
1795
- // If it's a directory, recursively get todos from children
1796
- if (entity.metadata.vfsType === 'directory') {
1797
- const children = await this.readdir(path);
1798
- for (const child of children) {
1799
- const childPath = path === '/' ? `/${child}` : `${path}/${child}`;
1800
- const childTodos = await this.getAllTodos(childPath);
1801
- allTodos.push(...childTodos);
1802
- }
1803
- }
1804
- }
1805
- catch (error) {
1806
- // Path doesn't exist, return empty
1807
- }
1808
- return allTodos;
1809
- }
1810
- /**
1811
- * Export directory structure to JSON
1812
- */
1813
- async exportToJSON(path = '/') {
1814
- await this.ensureInitialized();
1815
- const result = {};
1816
- const traverse = async (currentPath, target) => {
1817
- try {
1818
- const entityId = await this.pathResolver.resolve(currentPath);
1819
- const entity = await this.getEntityById(entityId);
1820
- if (entity.metadata.vfsType === 'directory') {
1821
- // Add directory metadata
1822
- target._meta = {
1823
- type: 'directory',
1824
- path: currentPath,
1825
- modified: entity.metadata.modified ? new Date(entity.metadata.modified) : undefined
1826
- };
1827
- // Traverse children
1828
- const children = await this.readdir(currentPath);
1829
- for (const child of children) {
1830
- const childName = typeof child === 'string' ? child : child.name;
1831
- const childPath = currentPath === '/' ? `/${childName}` : `${currentPath}/${childName}`;
1832
- target[childName] = {};
1833
- await traverse(childPath, target[childName]);
1834
- }
1835
- }
1836
- else if (entity.metadata.vfsType === 'file') {
1837
- // For files, include content and metadata
1838
- try {
1839
- const content = await this.readFile(currentPath);
1840
- const textContent = content.toString('utf8');
1841
- // Try to parse JSON files
1842
- if (currentPath.endsWith('.json')) {
1843
- try {
1844
- target._content = JSON.parse(textContent);
1845
- }
1846
- catch {
1847
- target._content = textContent;
1848
- }
1849
- }
1850
- else {
1851
- target._content = textContent;
1852
- }
1853
- }
1854
- catch {
1855
- // Binary or unreadable file
1856
- target._content = '[binary]';
1857
- }
1858
- target._meta = {
1859
- type: 'file',
1860
- path: currentPath,
1861
- size: entity.metadata.size || 0,
1862
- mimeType: entity.metadata.mimeType,
1863
- modified: entity.metadata.modified ? new Date(entity.metadata.modified) : undefined,
1864
- todos: entity.metadata.todos || []
1865
- };
1866
- }
1867
- }
1868
- catch (error) {
1869
- // Skip inaccessible paths
1870
- target._error = 'inaccessible';
1871
- }
1872
- };
1873
- await traverse(path, result);
1874
- return result;
1875
- }
1876
1781
  /**
1877
1782
  * Search for entities with filters
1878
1783
  */
@@ -1950,78 +1855,180 @@ export class VirtualFileSystem {
1950
1855
  return result;
1951
1856
  }
1952
1857
  /**
1953
- * Get project statistics for a path
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
1954
1863
  */
1955
- async getProjectStats(path = '/') {
1864
+ async du(path = '/', options) {
1956
1865
  await this.ensureInitialized();
1957
- const stats = {
1958
- fileCount: 0,
1959
- directoryCount: 0,
1960
- totalSize: 0,
1961
- todoCount: 0,
1962
- averageFileSize: 0,
1963
- largestFile: null,
1964
- modifiedRange: null
1965
- };
1966
- let earliestModified = null;
1967
- let latestModified = null;
1968
- 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
+ }
1969
1874
  try {
1970
1875
  const entityId = await this.pathResolver.resolve(currentPath);
1971
1876
  const entity = await this.getEntityById(entityId);
1972
1877
  if (entity.metadata.vfsType === 'directory') {
1973
- // Don't count the root/starting directory itself
1974
- if (!isRoot) {
1975
- stats.directoryCount++;
1976
- }
1977
- // Traverse children
1878
+ dirCount++;
1978
1879
  const children = await this.readdir(currentPath);
1979
1880
  for (const child of children) {
1980
1881
  const childPath = currentPath === '/' ? `/${child}` : `${currentPath}/${child}`;
1981
- await traverse(childPath, false);
1882
+ await traverse(childPath, depth + 1);
1982
1883
  }
1983
1884
  }
1984
1885
  else if (entity.metadata.vfsType === 'file') {
1985
- stats.fileCount++;
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') {
1986
1988
  const size = entity.metadata.size || 0;
1987
- stats.totalSize += size;
1988
- // Track largest file
1989
- if (!stats.largestFile || size > stats.largestFile.size) {
1990
- stats.largestFile = { path: currentPath, size };
1989
+ if (options?.minSize !== undefined) {
1990
+ matches = matches && size >= options.minSize;
1991
1991
  }
1992
- // Track modification times
1993
- const modified = entity.metadata.modified;
1994
- if (modified) {
1995
- if (!earliestModified || modified < earliestModified) {
1996
- earliestModified = modified;
1997
- }
1998
- if (!latestModified || modified > latestModified) {
1999
- latestModified = modified;
2000
- }
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
2001
  }
2002
- // Count todos
2003
- if (entity.metadata.todos) {
2004
- stats.todoCount += entity.metadata.todos.length;
2002
+ if (options.modified.before) {
2003
+ matches = matches && modifiedTime <= options.modified.before;
2004
+ }
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);
2005
2023
  }
2006
2024
  }
2007
2025
  }
2008
2026
  catch (error) {
2009
- // Skip if path doesn't exist
2027
+ // Skip inaccessible paths
2010
2028
  }
2011
2029
  };
2012
- await traverse(path, true);
2013
- // Calculate averages
2014
- if (stats.fileCount > 0) {
2015
- stats.averageFileSize = Math.round(stats.totalSize / stats.fileCount);
2016
- }
2017
- // Set date range
2018
- if (earliestModified && latestModified) {
2019
- stats.modifiedRange = {
2020
- earliest: new Date(earliestModified),
2021
- latest: new Date(latestModified)
2022
- };
2023
- }
2024
- return stats;
2030
+ await traverse(path, 0);
2031
+ return results;
2025
2032
  }
2026
2033
  /**
2027
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": "5.12.0",
3
+ "version": "6.0.1",
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",