BREAKING CHANGES: - VFS API changed from brain.vfs() (method) to brain.vfs (property) - VFS now auto-initializes during brain.init() - no separate vfs.init() needed Features: - VFS auto-initialization with property access pattern - Complete TypeAware COW support verification (all 20 methods) - Comprehensive API documentation (docs/api/README.md) - All 7 storage adapters verified with COW support Bug Fixes: - CLI now properly initializes brain before VFS operations - Fixed infinite recursion in VFS initialization - All VFS CLI commands updated to modern API Documentation: - Created comprehensive, verified API reference - Consolidated documentation structure (deleted redundant quick starts) - Updated all VFS docs to v5.1.0 patterns - Fixed all internal documentation links Verification: - Memory Storage: 23/24 tests (95.8%) - FileSystem Storage: 9/9 tests (100%) - VFS Auto-Init: 7/7 tests (100%) - Zero fake code confirmed
9.6 KiB
🚀 VFS Quick Start: 5-Minute File Explorer Setup
Get a working, production-ready file explorer with Brainy VFS in 5 minutes. Avoid common pitfalls and use the correct APIs.
📋 What You'll Build
A file explorer that:
- ✅ Never crashes from infinite recursion
- ✅ Uses filesystem storage correctly
- ✅ Leverages semantic search to find files by content
- ✅ Handles large directories efficiently
- ✅ Follows modern Brainy v3.x APIs
⚡ Step 1: Basic Setup (1 minute)
npm install @soulcraft/brainy
import { Brainy } from '@soulcraft/brainy'
// ✅ CORRECT: Use filesystem storage for production
const brain = new Brainy({
storage: {
type: 'filesystem',
path: './brainy-data' // Your data directory
}
})
await brain.init() // VFS auto-initialized!
console.log('🎉 VFS ready!')
💡 Pro Tip: Always use persistent storage (
filesystem,s3, oropfs) for file explorers - your data persists across process restarts!
📁 Step 2: Safe Directory Listing (2 minutes)
❌ WRONG - This causes infinite recursion:
// DON'T DO THIS - Causes directory to appear as its own child!
const badItems = allNodes.filter(node => node.path.startsWith(dirPath))
✅ CORRECT - Use tree-aware methods:
// ✅ Method 1: Get direct children (recommended for UI)
async function loadDirectoryContents(brain: Brainy, path: string) {
try {
const children = await brain.vfs.getDirectChildren(path)
// Sort directories first, then files
return children.sort((a, b) => {
if (a.metadata.vfsType === 'directory' && b.metadata.vfsType === 'file') return -1
if (a.metadata.vfsType === 'file' && b.metadata.vfsType === 'directory') return 1
return a.metadata.name.localeCompare(b.metadata.name)
})
} catch (error) {
console.error(`Failed to load ${path}:`, error.message)
return []
}
}
// ✅ Method 2: Get complete tree structure (for full trees)
async function loadFullTree(brain: Brainy, path: string) {
const tree = await brain.vfs.getTreeStructure(path, {
maxDepth: 3, // Prevent deep recursion
includeHidden: false, // Skip hidden files
sort: 'name'
})
return tree
}
// ✅ Method 3: Get detailed path info
async function inspectPath(brain: Brainy, path: string) {
const info = await brain.vfs.inspect(path)
return {
isDirectory: info.node.metadata.vfsType === 'directory',
children: info.children,
parent: info.parent,
stats: info.stats
}
}
🔍 Step 3: Add Semantic Search (1 minute)
// ✅ Find files by content, not just filename
async function searchFiles(brain: Brainy, query: string, basePath: string = '/') {
const results = await brain.vfs.search(query, {
path: basePath, // Limit search to specific directory
limit: 50, // Reasonable limit
type: 'file' // Only search files, not directories
})
return results.map(result => ({
path: result.path,
score: result.score,
type: result.type,
size: result.size,
modified: result.modified
}))
}
// Example usage
const reactFiles = await searchFiles('React components with hooks', '/src')
const docs = await searchFiles('API documentation', '/docs')
🖥️ Step 4: Complete File Explorer Component (1 minute)
Here's a complete React component using the correct patterns:
import React, { useState, useEffect } from 'react'
import { Brainy } from '@soulcraft/brainy'
export function FileExplorer() {
const [brain, setBrain] = useState(null)
const [currentPath, setCurrentPath] = useState('/')
const [items, setItems] = useState([])
const [loading, setLoading] = useState(true)
const [searchQuery, setSearchQuery] = useState('')
// Initialize Brainy (VFS auto-initialized!)
useEffect(() => {
async function initBrainy() {
const brainInstance = new Brainy({
storage: { type: 'filesystem', path: './brainy-data' }
})
await brainInstance.init() // VFS ready after this!
setBrain(brainInstance)
setLoading(false)
}
initBrainy()
}, [])
// Load directory contents
const loadDirectory = async (path: string) => {
if (!brain) return
setLoading(true)
try {
// ✅ CORRECT: Use getDirectChildren to prevent recursion
const children = await brain.vfs.getDirectChildren(path)
// Sort directories first
const sorted = children.sort((a, b) => {
if (a.metadata.vfsType === 'directory' && b.metadata.vfsType === 'file') return -1
if (a.metadata.vfsType === 'file' && b.metadata.vfsType === 'directory') return 1
return a.metadata.name.localeCompare(b.metadata.name)
})
setItems(sorted)
setCurrentPath(path)
} catch (error) {
console.error('Failed to load directory:', error)
setItems([])
} finally {
setLoading(false)
}
}
// Search files
const handleSearch = async () => {
if (!brain || !searchQuery.trim()) {
loadDirectory(currentPath)
return
}
setLoading(true)
try {
const results = await brain.vfs.search(searchQuery, {
path: currentPath,
limit: 100
})
setItems(results)
} catch (error) {
console.error('Search failed:', error)
} finally {
setLoading(false)
}
}
// Initial load
useEffect(() => {
if (brain) {
loadDirectory('/')
}
}, [brain])
if (loading && !brain) {
return <div>Initializing Brainy...</div>
}
return (
<div className="file-explorer">
{/* Search bar */}
<div className="search-bar">
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Search files by content..."
onKeyPress={(e) => e.key === 'Enter' && handleSearch()}
/>
<button onClick={handleSearch}>Search</button>
{searchQuery && (
<button onClick={() => { setSearchQuery(''); loadDirectory(currentPath) }}>
Clear
</button>
)}
</div>
{/* Current path */}
<div className="current-path">
📁 {currentPath}
{currentPath !== '/' && (
<button onClick={() => loadDirectory(currentPath.split('/').slice(0, -1).join('/') || '/')}>
⬆️ Up
</button>
)}
</div>
{/* File list */}
{loading ? (
<div>Loading...</div>
) : (
<div className="file-list">
{items.map((item) => (
<div
key={item.id}
className={`file-item ${item.metadata.vfsType}`}
onClick={() => {
if (item.metadata.vfsType === 'directory') {
loadDirectory(item.metadata.path)
} else {
console.log('Open file:', item.metadata.path)
// Add your file opening logic here
}
}}
>
<span className="icon">
{item.metadata.vfsType === 'directory' ? '📁' : '📄'}
</span>
<span className="name">{item.metadata.name}</span>
<span className="size">
{item.metadata.size ? `${Math.round(item.metadata.size / 1024)}KB` : ''}
</span>
</div>
))}
{items.length === 0 && (
<div className="empty">
{searchQuery ? 'No results found' : 'Empty directory'}
</div>
)}
</div>
)}
</div>
)
}
🎯 What We Just Avoided
By using this quick start, you avoided these common mistakes:
❌ Infinite Recursion: Using naive filtering that includes directories as their own children
❌ Memory Storage: Losing data when process restarts
❌ Old APIs: Using deprecated addNoun, getNouns, addVerb methods
❌ Complex Fallbacks: Implementing unnecessary fallback patterns when proper methods exist
❌ Poor Performance: Not using tree-aware methods designed for file explorers
🚀 Next Steps
Your file explorer is now working! Here's what to explore next:
- File Operations - Read, write, and manipulate files
- Semantic Features - Multi-dimensional file access and neural extraction
- Performance Optimization - Handle large directories efficiently
- Advanced Search - Complex queries and filters
🆘 Common Issues & Solutions
"Module not found" errors
# Make sure you're using the right import
npm ls @soulcraft/brainy # Check version
npm install @soulcraft/brainy@latest # Update if needed
"VFS not initialized" errors
// v5.1.0+: Just await brain.init() - VFS is auto-initialized!
await brain.init()
// VFS ready - use brain.vfs directly
await brain.vfs.writeFile('/test.txt', 'data')
Slow directory loading
// Add pagination for large directories
const children = await brain.vfs.getDirectChildren(path, {
limit: 100, // Load only first 100 items
offset: 0 // Start from beginning
})
Search not finding files
// Make sure files are imported into VFS first
await brain.vfs.importDirectory('./my-files', {
recursive: true,
extractMetadata: true // Enable content understanding
})
🎉 Congratulations! You now have a working file explorer that uses modern Brainy APIs correctly. No more infinite recursion, no more deprecated methods, no more confusion.
Need help? Check out our Complete VFS Guide or Common Patterns.