feat(8.0): brain.fillSubtypes migration helper + pre-RC1 gap closure
- brain.fillSubtypes(rules): idempotent subtype back-fill for pre-8.0 data.
One rule per NounType/VerbType (literal default or per-entry function);
fills only entries still missing a subtype through the public update()/
updateRelation() paths; returns { scanned, filled, skipped, errors, byType }.
Full unit suite in tests/unit/brainy/fill-subtypes.test.ts.
- Fix getNouns/getVerbs pagination hasMore (peek one past the window) —
was permanently false, silently truncating every multi-page walk.
- find({ near }) without near.id now throws a teaching error instead of an
opaque storage sharding failure; CLI --threshold without --near applies a
plain score floor.
- CLI init/close audit: every one-shot command init()s, close()s, and exits
explicitly; delete the unmaintained interactive REPL; replace the cloud-era
storage subcommands with status/batch-delete; new types/validate commands.
- requireSubtype JSDoc now documents the 8.0 default-on contract; audit()
recommendation points at fillSubtypes.
- Docs: data-storage-architecture rewritten to the real 8.0 on-disk layout;
README storage section reflects filesystem+memory and snapshots; eli5 and
SEMANTIC_VFS /as-of/ semantics corrected; internal tracker IDs and
.strategy references scrubbed from published files.
This commit is contained in:
parent
9b0f4acd5b
commit
c44678390e
30 changed files with 1517 additions and 3226 deletions
131
src/cli/index.ts
131
src/cli/index.ts
|
|
@ -19,6 +19,7 @@ import { insightsCommands } from './commands/insights.js'
|
|||
import { importCommands } from './commands/import.js'
|
||||
import { snapshotCommands } from './commands/snapshot.js'
|
||||
import { inspectCommands } from './commands/inspect.js'
|
||||
import { types as typesCommand, validate as validateCommand } from './commands/types.js'
|
||||
import { readFileSync } from 'fs'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { dirname, join } from 'path'
|
||||
|
|
@ -70,14 +71,9 @@ ${chalk.cyan('Examples:')}
|
|||
$ brainy vfs similar /code/Button.tsx
|
||||
|
||||
${chalk.dim('# Storage management')}
|
||||
$ brainy storage status --quota
|
||||
$ brainy storage lifecycle set ${chalk.dim('# Interactive mode')}
|
||||
$ brainy storage cost-estimate
|
||||
$ brainy storage status
|
||||
$ brainy storage batch-delete old-ids.txt
|
||||
|
||||
${chalk.dim('# Interactive mode')}
|
||||
$ brainy interactive
|
||||
|
||||
${chalk.cyan('Documentation:')}
|
||||
${chalk.dim('Full docs:')} https://github.com/soulcraftlabs/brainy
|
||||
${chalk.dim('Report issues:')} https://github.com/soulcraftlabs/brainy/issues
|
||||
|
|
@ -109,7 +105,7 @@ program
|
|||
.description('Advanced search with Triple Intelligence™ (interactive if no query)')
|
||||
.option('-k, --limit <number>', 'Number of results', '10')
|
||||
.option('--offset <number>', 'Skip N results (pagination)')
|
||||
.option('-t, --threshold <number>', 'Similarity threshold (0-1)', '0.7')
|
||||
.option('-t, --threshold <number>', 'Minimum similarity score (0-1); with --near, the proximity threshold')
|
||||
.option('--type <types>', 'Filter by type(s) - comma separated')
|
||||
.option('--where <json>', 'Metadata filters (JSON)')
|
||||
.option('--near <id>', 'Find items near this ID')
|
||||
|
|
@ -181,6 +177,23 @@ program
|
|||
.option('--pretty', 'Pretty print JSON')
|
||||
.action(coreCommands.diagnostics)
|
||||
|
||||
// ===== Type Commands =====
|
||||
|
||||
program
|
||||
.command('types')
|
||||
.description('List all NounType and VerbType values')
|
||||
.option('--noun', 'Show noun types only')
|
||||
.option('--verb', 'Show verb types only')
|
||||
.option('--json', 'Output as JSON')
|
||||
.action(typesCommand)
|
||||
|
||||
program
|
||||
.command('validate [type]')
|
||||
.description('Check whether a type string is a valid NounType or VerbType (interactive if no type)')
|
||||
.option('--verb', 'Validate as a verb type (default: noun type)')
|
||||
.option('--json', 'Output as JSON')
|
||||
.action(validateCommand)
|
||||
|
||||
// ===== Neural Commands =====
|
||||
|
||||
program
|
||||
|
|
@ -222,17 +235,6 @@ program
|
|||
.option('--children-only', 'Show only child hierarchy')
|
||||
.action(neuralCommands.hierarchy)
|
||||
|
||||
program
|
||||
.command('path <from> <to>')
|
||||
.description('Find semantic path between items')
|
||||
.option('--steps', 'Show step-by-step path')
|
||||
.option('--max-hops <number>', 'Maximum path length', '5')
|
||||
.action(() => {
|
||||
console.log(chalk.yellow('\n⚠️ Semantic path finding coming soon'))
|
||||
console.log(chalk.dim('This feature requires implementing graph traversal algorithms'))
|
||||
console.log(chalk.dim('Use "brainy neighbors" and "brainy hierarchy" to explore connections'))
|
||||
})
|
||||
|
||||
program
|
||||
.command('outliers')
|
||||
.alias('anomalies')
|
||||
|
|
@ -457,89 +459,26 @@ program
|
|||
|
||||
program
|
||||
.command('storage')
|
||||
.description('💾 Storage management and cost optimization')
|
||||
.description('💾 Storage management (filesystem + memory backends)')
|
||||
.addCommand(
|
||||
new Command('status')
|
||||
.description('Show storage status and health')
|
||||
.option('--detailed', 'Show detailed information')
|
||||
.option('--quota', 'Show quota information (OPFS)')
|
||||
.description('Show storage backend, counts, root directory, and writer lock')
|
||||
.option('--json', 'Output as JSON')
|
||||
.option('--pretty', 'Pretty-print JSON')
|
||||
.action((options) => {
|
||||
storageCommands.status(options)
|
||||
})
|
||||
)
|
||||
.addCommand(
|
||||
new Command('lifecycle')
|
||||
.description('Lifecycle policy management')
|
||||
.addCommand(
|
||||
new Command('set')
|
||||
.argument('[config-file]', 'Policy configuration file (JSON)')
|
||||
.description('Set lifecycle policy (interactive if no file)')
|
||||
.option('--validate', 'Validate before applying')
|
||||
.action((configFile, options) => {
|
||||
storageCommands.lifecycle.set(configFile, options)
|
||||
})
|
||||
)
|
||||
.addCommand(
|
||||
new Command('get')
|
||||
.description('Get current lifecycle policy')
|
||||
.option('-f, --format <type>', 'Output format (json|yaml)', 'json')
|
||||
.action((options) => {
|
||||
storageCommands.lifecycle.get(options)
|
||||
})
|
||||
)
|
||||
.addCommand(
|
||||
new Command('remove')
|
||||
.description('Remove lifecycle policy')
|
||||
.action((options) => {
|
||||
storageCommands.lifecycle.remove(options)
|
||||
})
|
||||
)
|
||||
)
|
||||
.addCommand(
|
||||
new Command('compression')
|
||||
.description('Compression management (FileSystem)')
|
||||
.addCommand(
|
||||
new Command('enable')
|
||||
.description('Enable gzip compression')
|
||||
.action((options) => {
|
||||
storageCommands.compression.enable(options)
|
||||
})
|
||||
)
|
||||
.addCommand(
|
||||
new Command('disable')
|
||||
.description('Disable compression')
|
||||
.action((options) => {
|
||||
storageCommands.compression.disable(options)
|
||||
})
|
||||
)
|
||||
.addCommand(
|
||||
new Command('status')
|
||||
.description('Show compression status')
|
||||
.action((options) => {
|
||||
storageCommands.compression.status(options)
|
||||
})
|
||||
)
|
||||
)
|
||||
.addCommand(
|
||||
new Command('batch-delete')
|
||||
.argument('<file>', 'File containing entity IDs (one per line)')
|
||||
.description('Batch delete with retry logic')
|
||||
.option('--max-retries <n>', 'Maximum retry attempts', '3')
|
||||
.option('--continue-on-error', 'Continue if some deletes fail')
|
||||
.description('Delete a list of entities through the public delete path (with retry)')
|
||||
.option('--max-retries <n>', 'Maximum retry attempts per ID', '3')
|
||||
.option('--continue-on-error', 'Continue past IDs that still fail after retries')
|
||||
.action((file, options) => {
|
||||
storageCommands.batchDelete(file, options)
|
||||
})
|
||||
)
|
||||
.addCommand(
|
||||
new Command('cost-estimate')
|
||||
.description('Estimate cloud storage costs')
|
||||
.option('--provider <type>', 'Cloud provider (aws|gcs|azure|r2)')
|
||||
.option('--size <gb>', 'Data size in GB')
|
||||
.option('--operations <n>', 'Monthly operations')
|
||||
.action((options) => {
|
||||
storageCommands.costEstimate(options)
|
||||
})
|
||||
)
|
||||
|
||||
// ===== Data Management Commands =====
|
||||
|
||||
|
|
@ -742,9 +681,8 @@ program
|
|||
|
||||
program
|
||||
.command('clean')
|
||||
.description('Clean and optimize database')
|
||||
.option('--remove-orphans', 'Remove orphaned items')
|
||||
.option('--rebuild-index', 'Rebuild search index')
|
||||
.description('Clear the database — ALL entities, relationships, and indexes (asks for confirmation)')
|
||||
.option('-f, --force', 'Skip confirmation prompt')
|
||||
.action(utilityCommands.clean)
|
||||
|
||||
program
|
||||
|
|
@ -785,17 +723,6 @@ program
|
|||
.description('Show the store\'s current generation watermark')
|
||||
.action(snapshotCommands.generation)
|
||||
|
||||
// ===== Interactive Mode =====
|
||||
|
||||
program
|
||||
.command('interactive')
|
||||
.alias('i')
|
||||
.description('Start interactive REPL mode')
|
||||
.action(async () => {
|
||||
const { startInteractiveMode } = await import('./interactive.js')
|
||||
await startInteractiveMode()
|
||||
})
|
||||
|
||||
// ===== Error Handling =====
|
||||
|
||||
program.exitOverride()
|
||||
|
|
|
|||
Reference in a new issue