chore(8.0): final pre-RC1 sweep — API consistency, named errors, orphans, zero-cast codebase
This commit is contained in:
parent
970e08c466
commit
1f7e365a4e
237 changed files with 1951 additions and 49413 deletions
|
|
@ -7,10 +7,11 @@
|
|||
*/
|
||||
|
||||
import chalk from 'chalk'
|
||||
import ora from 'ora'
|
||||
import ora, { type Ora } from 'ora'
|
||||
import inquirer from 'inquirer'
|
||||
import { Brainy } from '../../brainy.js'
|
||||
import { BrainyTypes, NounType, VerbType } from '../../index.js'
|
||||
import type { Entity, Result } from '../../types/brainy.types.js'
|
||||
|
||||
interface CoreOptions {
|
||||
verbose?: boolean
|
||||
|
|
@ -87,7 +88,7 @@ export const coreCommands = {
|
|||
* Add data to the neural database
|
||||
*/
|
||||
async add(text: string | undefined, options: AddOptions) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no text provided
|
||||
if (!text) {
|
||||
|
|
@ -222,7 +223,7 @@ export const coreCommands = {
|
|||
* Search the neural database with Triple Intelligence™
|
||||
*/
|
||||
async search(query: string | undefined, options: SearchOptions) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no query provided
|
||||
if (!query) {
|
||||
|
|
@ -407,8 +408,13 @@ export const coreCommands = {
|
|||
if (result.score !== undefined) {
|
||||
console.log(chalk.green(` Score: ${(result.score * 100).toFixed(1)}%`))
|
||||
|
||||
if (options.explain && (result as any).scores) {
|
||||
const scores = (result as any).scores
|
||||
// Per-intelligence sub-scores aren't part of the public Result
|
||||
// contract (the typed breakdown lives on `explanation`) — read
|
||||
// defensively so --explain degrades to no breakdown when absent.
|
||||
const scores = (result as Result & {
|
||||
scores?: { vector?: number; graph?: number; field?: number }
|
||||
}).scores
|
||||
if (options.explain && scores) {
|
||||
if (scores.vector !== undefined) {
|
||||
console.log(chalk.dim(` Vector: ${(scores.vector * 100).toFixed(1)}%`))
|
||||
}
|
||||
|
|
@ -422,24 +428,28 @@ export const coreCommands = {
|
|||
}
|
||||
|
||||
// Show type
|
||||
if ((entity as any).type) {
|
||||
console.log(chalk.dim(` Type: ${(entity as any).type}`))
|
||||
if (entity.type) {
|
||||
console.log(chalk.dim(` Type: ${entity.type}`))
|
||||
}
|
||||
|
||||
// Show content preview
|
||||
if ((entity as any).content) {
|
||||
const preview = (entity as any).content.substring(0, 80)
|
||||
console.log(chalk.dim(` Content: ${preview}${(entity as any).content.length > 80 ? '...' : ''}`))
|
||||
// Show content preview. `content` is not a standard Entity field —
|
||||
// surfaced defensively for records that carry flattened text content.
|
||||
const content = (entity as Entity & { content?: string }).content
|
||||
if (content) {
|
||||
const preview = content.substring(0, 80)
|
||||
console.log(chalk.dim(` Content: ${preview}${content.length > 80 ? '...' : ''}`))
|
||||
}
|
||||
|
||||
// Show metadata
|
||||
if ((entity as any).metadata && Object.keys((entity as any).metadata).length > 0) {
|
||||
console.log(chalk.dim(` Metadata: ${JSON.stringify((entity as any).metadata)}`))
|
||||
if (entity.metadata && Object.keys(entity.metadata).length > 0) {
|
||||
console.log(chalk.dim(` Metadata: ${JSON.stringify(entity.metadata)}`))
|
||||
}
|
||||
|
||||
// Show relationships
|
||||
if (options.includeRelations && (result as any).relations) {
|
||||
const relations = (result as any).relations
|
||||
// Show relationships. `relations` isn't part of the public Result
|
||||
// contract — read defensively so --include-relations degrades to
|
||||
// no output when find() doesn't attach it.
|
||||
const relations = (result as Result & { relations?: unknown[] }).relations
|
||||
if (options.includeRelations && relations) {
|
||||
if (relations.length > 0) {
|
||||
console.log(chalk.dim(` Relations: ${relations.length} connections`))
|
||||
}
|
||||
|
|
@ -487,7 +497,7 @@ export const coreCommands = {
|
|||
* Get item by ID
|
||||
*/
|
||||
async get(id: string | undefined, options: GetOptions) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no ID provided
|
||||
if (!id) {
|
||||
|
|
@ -527,18 +537,25 @@ export const coreCommands = {
|
|||
if (!options.json) {
|
||||
console.log(chalk.cyan('\nItem Details:'))
|
||||
console.log(` ID: ${item.id}`)
|
||||
console.log(` Content: ${(item as any).content || 'N/A'}`)
|
||||
// `content` is not a standard Entity field — see the search() note.
|
||||
console.log(` Content: ${(item as Entity & { content?: string }).content || 'N/A'}`)
|
||||
if (item.metadata) {
|
||||
console.log(` Metadata: ${JSON.stringify(item.metadata, null, 2)}`)
|
||||
}
|
||||
|
||||
if (options.withConnections) {
|
||||
// Get verbs/relationships
|
||||
// Get connections if method exists
|
||||
const connections = (brain as any).getConnections ? await (brain as any).getConnections(id) : []
|
||||
// Brainy's public API has no getConnections() — this optional probe
|
||||
// predates related() and resolves to an empty list on current
|
||||
// builds. Typed to match the legacy edge shape it rendered.
|
||||
const legacyBrain = brain as Brainy & {
|
||||
getConnections?: (id: string | undefined) => Promise<
|
||||
Array<{ source: string; type: string; target: string }>
|
||||
>
|
||||
}
|
||||
const connections = legacyBrain.getConnections ? await legacyBrain.getConnections(id) : []
|
||||
if (connections && connections.length > 0) {
|
||||
console.log(chalk.cyan('\nConnections:'))
|
||||
connections.forEach((conn: any) => {
|
||||
connections.forEach((conn) => {
|
||||
console.log(` ${conn.source} --[${conn.type}]--> ${conn.target}`)
|
||||
})
|
||||
}
|
||||
|
|
@ -561,7 +578,7 @@ export const coreCommands = {
|
|||
* Create relationship between items
|
||||
*/
|
||||
async relate(source: string | undefined, verb: string | undefined, target: string | undefined, options: RelateOptions) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if parameters missing
|
||||
if (!source || !verb || !target) {
|
||||
|
|
@ -630,10 +647,12 @@ export const coreCommands = {
|
|||
// `--subtype <value>` → Brainy default `'cli-relate'`. Same rationale
|
||||
// as `brainy add` — guarantees CLI works under strict-mode brains
|
||||
// (added 7.30.1).
|
||||
// The verb arrives as a raw CLI string; relate() validates it against
|
||||
// the VerbType vocabulary at runtime.
|
||||
const result = await brain.relate({
|
||||
from: source,
|
||||
to: target,
|
||||
type: verb as any,
|
||||
type: verb as VerbType,
|
||||
subtype: options.subtype ?? 'cli-relate',
|
||||
metadata
|
||||
})
|
||||
|
|
@ -664,7 +683,7 @@ export const coreCommands = {
|
|||
* Update an existing entity
|
||||
*/
|
||||
async update(id: string | undefined, options: AddOptions & { content?: string }) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no ID provided
|
||||
if (!id) {
|
||||
|
|
@ -770,10 +789,10 @@ export const coreCommands = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Delete an entity
|
||||
* Remove an entity
|
||||
*/
|
||||
async deleteEntity(id: string | undefined, options: CoreOptions & { force?: boolean }) {
|
||||
let spinner: any = null
|
||||
async removeEntity(id: string | undefined, options: CoreOptions & { force?: boolean }) {
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no ID provided
|
||||
if (!id) {
|
||||
|
|
@ -781,7 +800,7 @@ export const coreCommands = {
|
|||
{
|
||||
type: 'input',
|
||||
name: 'id',
|
||||
message: 'Entity ID to delete:',
|
||||
message: 'Entity ID to remove:',
|
||||
validate: (input: string) => input.trim().length > 0 || 'ID cannot be empty'
|
||||
},
|
||||
{
|
||||
|
|
@ -793,7 +812,7 @@ export const coreCommands = {
|
|||
])
|
||||
|
||||
if (!answers.confirm) {
|
||||
console.log(chalk.yellow('Delete cancelled'))
|
||||
console.log(chalk.yellow('Operation cancelled'))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -803,36 +822,36 @@ export const coreCommands = {
|
|||
const answer = await inquirer.prompt([{
|
||||
type: 'confirm',
|
||||
name: 'confirm',
|
||||
message: `Delete entity ${id}? This cannot be undone.`,
|
||||
message: `Remove entity ${id}? This cannot be undone.`,
|
||||
default: false
|
||||
}])
|
||||
|
||||
if (!answer.confirm) {
|
||||
console.log(chalk.yellow('Delete cancelled'))
|
||||
console.log(chalk.yellow('Operation cancelled'))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
spinner = ora('Deleting entity...').start()
|
||||
spinner = ora('Removing entity...').start()
|
||||
const brain = getBrainy()
|
||||
await brain.init()
|
||||
|
||||
await brain.delete(id)
|
||||
await brain.remove(id)
|
||||
|
||||
spinner.succeed('Entity deleted successfully')
|
||||
spinner.succeed('Entity removed successfully')
|
||||
|
||||
if (!options.json) {
|
||||
console.log(chalk.green(`✓ Deleted entity: ${id}`))
|
||||
console.log(chalk.green(`✓ Removed entity: ${id}`))
|
||||
} else {
|
||||
formatOutput({ id, deleted: true }, options)
|
||||
formatOutput({ id, removed: true }, options)
|
||||
}
|
||||
|
||||
// One-shot command — see add() for why the explicit close + exit.
|
||||
await brain.close()
|
||||
process.exit(0)
|
||||
} catch (error: any) {
|
||||
if (spinner) spinner.fail('Failed to delete entity')
|
||||
console.error(chalk.red('Delete failed:', error.message))
|
||||
if (spinner) spinner.fail('Failed to remove entity')
|
||||
console.error(chalk.red('Remove failed:', error.message))
|
||||
process.exit(1)
|
||||
}
|
||||
},
|
||||
|
|
@ -841,7 +860,7 @@ export const coreCommands = {
|
|||
* Remove a relationship
|
||||
*/
|
||||
async unrelate(id: string | undefined, options: CoreOptions & { force?: boolean }) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no ID provided
|
||||
if (!id) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
* The legacy backup/import/export facade that used to live behind this
|
||||
* command was superseded in 8.0: snapshots are `brainy snapshot` / `brainy
|
||||
* restore` (the Db API's `persist()`/`restore()`), and data ingestion is
|
||||
* `brainy import` (UniversalImportAPI).
|
||||
* `brainy import` (`brain.import()`).
|
||||
*/
|
||||
|
||||
import chalk from 'chalk'
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* @description Import commands — neural import and data import.
|
||||
*
|
||||
* Complete import system exposing ALL Brainy import capabilities:
|
||||
* - UniversalImportAPI: Neural import with AI type matching
|
||||
* - `brain.import()`: universal ingestion with neural type matching
|
||||
* - DirectoryImporter: VFS directory imports
|
||||
*
|
||||
* Supports: files, directories, URLs, all formats. Backup/restore is the
|
||||
|
|
@ -11,19 +11,23 @@
|
|||
*/
|
||||
|
||||
import chalk from 'chalk'
|
||||
import ora from 'ora'
|
||||
import ora, { type Ora } from 'ora'
|
||||
import inquirer from 'inquirer'
|
||||
import { readFileSync, statSync, existsSync } from 'node:fs'
|
||||
import { Brainy } from '../../brainy.js'
|
||||
import { NounType } from '../../types/graphTypes.js'
|
||||
import type { SupportedFormat } from '../../import/FormatDetector.js'
|
||||
|
||||
interface ImportOptions {
|
||||
verbose?: boolean
|
||||
json?: boolean
|
||||
pretty?: boolean
|
||||
quiet?: boolean
|
||||
// Format options
|
||||
format?: 'json' | 'csv' | 'jsonl' | 'yaml' | 'markdown' | 'html' | 'xml' | 'text'
|
||||
// Format options. Populated by commander straight from `--format` with no
|
||||
// validation, so the runtime value is whatever the user typed — kept as a
|
||||
// plain string and narrowed to brain.import()'s SupportedFormat at the call
|
||||
// boundary (the import extractor rejects unsupported values at runtime).
|
||||
format?: string
|
||||
// Import behavior
|
||||
recursive?: boolean
|
||||
batchSize?: string
|
||||
|
|
@ -60,11 +64,11 @@ const formatOutput = (data: any, options: ImportOptions): void => {
|
|||
|
||||
export const importCommands = {
|
||||
/**
|
||||
* Enhanced import using UniversalImportAPI
|
||||
* Supports files, directories, URLs, all formats
|
||||
* Enhanced import via `brain.import()`.
|
||||
* Supports files, directories, URLs, all formats.
|
||||
*/
|
||||
async import(source: string | undefined, options: ImportOptions) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no source provided
|
||||
if (!source) {
|
||||
|
|
@ -260,7 +264,8 @@ export const importCommands = {
|
|||
} else {
|
||||
// File import with progress
|
||||
result = await brain.import(source, {
|
||||
format: options.format as any,
|
||||
// Raw CLI string → SupportedFormat (see ImportOptions.format note).
|
||||
format: options.format as SupportedFormat | undefined,
|
||||
enableNeuralExtraction: options.extractEntities !== false,
|
||||
enableRelationshipInference: options.detectRelationships !== false,
|
||||
enableConceptExtraction: options.extractConcepts || false,
|
||||
|
|
@ -422,7 +427,7 @@ export const importCommands = {
|
|||
* VFS-specific import (files/directories into VFS)
|
||||
*/
|
||||
async vfsImport(source: string | undefined, options: ImportOptions) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no source provided
|
||||
if (!source) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import chalk from 'chalk'
|
||||
import ora from 'ora'
|
||||
import ora, { type Ora } from 'ora'
|
||||
import inquirer from 'inquirer'
|
||||
import Table from 'cli-table3'
|
||||
import { Brainy } from '../../brainy.js'
|
||||
|
|
@ -192,7 +192,7 @@ export const insightsCommands = {
|
|||
* Get field values for a specific field
|
||||
*/
|
||||
async fieldValues(field: string | undefined, options: InsightsOptions & { limit?: string }) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no field provided
|
||||
if (!field) {
|
||||
|
|
@ -274,7 +274,7 @@ export const insightsCommands = {
|
|||
* Get optimal query plan for filters
|
||||
*/
|
||||
async queryPlan(options: InsightsOptions & { filters?: string }) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
let filters: Record<string, any> = {}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
import chalk from 'chalk'
|
||||
import ora from 'ora'
|
||||
import { Brainy } from '../../brainy.js'
|
||||
import type { RelatedParams } from '../../types/brainy.types.js'
|
||||
import type { NounType, VerbType } from '../../types/graphTypes.js'
|
||||
|
||||
interface InspectOptions {
|
||||
fresh?: boolean
|
||||
|
|
@ -109,8 +111,10 @@ export const inspectCommands = {
|
|||
const where = options.where ? JSON.parse(options.where) : undefined
|
||||
const limit = options.limit ? parseInt(options.limit, 10) : 20
|
||||
const offset = options.offset ? parseInt(options.offset, 10) : 0
|
||||
// --type arrives as a raw CLI string; find() resolves it against the
|
||||
// NounType vocabulary at runtime.
|
||||
const results = await brain.find({
|
||||
type: options.type as any,
|
||||
type: options.type as NounType | undefined,
|
||||
where,
|
||||
limit,
|
||||
offset
|
||||
|
|
@ -158,12 +162,16 @@ export const inspectCommands = {
|
|||
if (spinner) spinner.text = 'Walking graph…'
|
||||
const direction = options.direction ?? 'both'
|
||||
const limit = options.limit ? parseInt(options.limit, 10) : 50
|
||||
const rels = await brain.getRelations({
|
||||
// `direction` is accepted by the CLI surface but RelatedParams has
|
||||
// no such filter — related() reads from/to/type/limit and ignores
|
||||
// extras, so the assertion only admits the extra key, it doesn't change
|
||||
// what the query does. --type arrives as a raw CLI string.
|
||||
const rels = await brain.related({
|
||||
from: id,
|
||||
direction,
|
||||
type: options.type as any,
|
||||
type: options.type as VerbType | undefined,
|
||||
limit
|
||||
} as any)
|
||||
} as RelatedParams)
|
||||
spinner?.succeed(`Found ${rels.length} relationship(s)`)
|
||||
emit(rels, options)
|
||||
await brain.close()
|
||||
|
|
@ -185,7 +193,7 @@ export const inspectCommands = {
|
|||
const brain = await openReader(path, options)
|
||||
if (spinner) spinner.text = 'Planning query…'
|
||||
const where = options.where ? JSON.parse(options.where) : {}
|
||||
const plan = await brain.explain({ type: options.type as any, where })
|
||||
const plan = await brain.explain({ type: options.type as NounType | undefined, where })
|
||||
spinner?.succeed('Plan ready')
|
||||
emit(plan, options)
|
||||
await brain.close()
|
||||
|
|
@ -228,7 +236,7 @@ export const inspectCommands = {
|
|||
// dedicated random-sample API in Brainy core for this v1.
|
||||
const window = Math.min(Math.max(n * 10, 50), 1000)
|
||||
const pool = await brain.find({
|
||||
type: options.type as any,
|
||||
type: options.type as NounType | undefined,
|
||||
limit: window
|
||||
})
|
||||
const sample = pool
|
||||
|
|
@ -275,7 +283,7 @@ export const inspectCommands = {
|
|||
let offset = 0
|
||||
while (true) {
|
||||
const page = await brain.find({
|
||||
type: options.type as any,
|
||||
type: options.type as NounType | undefined,
|
||||
limit: batch,
|
||||
offset
|
||||
})
|
||||
|
|
@ -310,7 +318,7 @@ export const inspectCommands = {
|
|||
try {
|
||||
const brain = await openReader(path, { ...options, quiet: true })
|
||||
const page = await brain.find({
|
||||
type: options.type as any,
|
||||
type: options.type as NounType | undefined,
|
||||
limit: 200
|
||||
})
|
||||
for (const e of page) {
|
||||
|
|
|
|||
|
|
@ -10,10 +10,11 @@
|
|||
|
||||
import inquirer from 'inquirer'
|
||||
import chalk from 'chalk'
|
||||
import ora from 'ora'
|
||||
import ora, { type Ora } from 'ora'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { Brainy } from '../../brainy.js'
|
||||
import type { NeuralClusterParams } from '../../types/brainy.types.js'
|
||||
|
||||
interface CommandArguments {
|
||||
action?: string;
|
||||
|
|
@ -113,10 +114,12 @@ async function handleSimilarCommand(neural: any, argv: CommandArguments): Promis
|
|||
}
|
||||
|
||||
async function handleClustersCommand(neural: any, argv: CommandArguments): Promise<void> {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
let options: any = {
|
||||
algorithm: argv.algorithm as any,
|
||||
// --algorithm arrives as a raw CLI string; the interactive prompt below
|
||||
// and neural.clusters() constrain it to the supported algorithms.
|
||||
algorithm: argv.algorithm as NeuralClusterParams['algorithm'],
|
||||
threshold: argv.threshold,
|
||||
maxClusters: argv.limit
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import chalk from 'chalk'
|
||||
import ora from 'ora'
|
||||
import ora, { type Ora } from 'ora'
|
||||
import inquirer from 'inquirer'
|
||||
import Table from 'cli-table3'
|
||||
import { Brainy } from '../../brainy.js'
|
||||
|
|
@ -37,7 +37,7 @@ export const nlpCommands = {
|
|||
* Extract entities from text
|
||||
*/
|
||||
async extract(text: string | undefined, options: NLPOptions) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no text provided
|
||||
if (!text) {
|
||||
|
|
@ -126,7 +126,7 @@ export const nlpCommands = {
|
|||
* Extract concepts from text
|
||||
*/
|
||||
async extractConcepts(text: string | undefined, options: NLPOptions & { threshold?: string }) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no text provided
|
||||
if (!text) {
|
||||
|
|
@ -197,7 +197,7 @@ export const nlpCommands = {
|
|||
* Analyze text with full NLP pipeline
|
||||
*/
|
||||
async analyze(text: string | undefined, options: NLPOptions) {
|
||||
let spinner: any = null
|
||||
let spinner: Ora | null = null
|
||||
try {
|
||||
// Interactive mode if no text provided
|
||||
if (!text) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* - `storage status` — backend, root directory, entity/relationship counts,
|
||||
* writer-lock holder, and operational mode (rendered from `brain.stats()`).
|
||||
* - `storage batch-delete <file>` — delete a newline-separated list of entity
|
||||
* IDs through the public `brain.delete()` path (vectors, metadata, indexes,
|
||||
* IDs through the public `brain.remove()` path (vectors, metadata, indexes,
|
||||
* and statistics all stay consistent), with per-ID retry and an optional
|
||||
* continue-on-error mode.
|
||||
*
|
||||
|
|
@ -144,7 +144,7 @@ export const storageCommands = {
|
|||
|
||||
/**
|
||||
* @description Delete a list of entity IDs (one per line in a file) through
|
||||
* the public `brain.delete()` path so vectors, metadata, graph edges,
|
||||
* the public `brain.remove()` path so vectors, metadata, graph edges,
|
||||
* indexes, and statistics all stay consistent. Asks for confirmation before
|
||||
* deleting; failed IDs are retried up to `--max-retries` times, and
|
||||
* `--continue-on-error` keeps going past IDs that still fail.
|
||||
|
|
@ -204,7 +204,7 @@ export const storageCommands = {
|
|||
|
||||
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
await brain.delete(id)
|
||||
await brain.remove(id)
|
||||
succeeded = true
|
||||
break
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,15 @@ interface BenchmarkOptions extends UtilityOptions {
|
|||
iterations?: string
|
||||
}
|
||||
|
||||
/** Per-operation timing summary produced by `brainy benchmark`. */
|
||||
interface BenchmarkOperationStats {
|
||||
avg: string
|
||||
min: number
|
||||
max: number
|
||||
median: number
|
||||
ops: string
|
||||
}
|
||||
|
||||
let brainyInstance: Brainy | null = null
|
||||
|
||||
const getBrainy = (): Brainy => {
|
||||
|
|
@ -188,7 +197,10 @@ export const utilityCommands = {
|
|||
|
||||
console.log(chalk.cyan(`\n🚀 Running Benchmarks (${iterations} iterations)\n`))
|
||||
|
||||
const results: any = {
|
||||
const results: {
|
||||
operations: Record<string, BenchmarkOperationStats>
|
||||
summary: { totalOperations?: number; averageOpsPerSec?: string }
|
||||
} = {
|
||||
operations: {},
|
||||
summary: {}
|
||||
}
|
||||
|
|
@ -253,7 +265,7 @@ export const utilityCommands = {
|
|||
}
|
||||
|
||||
// Calculate summary
|
||||
const totalOps: number = (Object.values(results.operations) as any[]).reduce((sum: number, op: any) =>
|
||||
const totalOps: number = Object.values(results.operations).reduce((sum: number, op) =>
|
||||
sum + parseFloat(op.ops), 0)
|
||||
|
||||
results.summary = {
|
||||
|
|
@ -277,7 +289,7 @@ export const utilityCommands = {
|
|||
style: { head: [], border: [] }
|
||||
})
|
||||
|
||||
Object.entries(results.operations).forEach(([op, stats]: [string, any]) => {
|
||||
Object.entries(results.operations).forEach(([op, stats]) => {
|
||||
table.push([
|
||||
op,
|
||||
stats.avg,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import ora from 'ora'
|
|||
import Table from 'cli-table3'
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { Brainy } from '../../brainy.js'
|
||||
import type { SearchResult, VFSDirent } from '../../vfs/types.js'
|
||||
|
||||
interface VFSOptions {
|
||||
verbose?: boolean
|
||||
|
|
@ -54,8 +55,9 @@ export const vfsCommands = {
|
|||
try {
|
||||
const brain = await getBrainy() // Await async getBrainy
|
||||
// VFS auto-initialized, no need for vfs.init()
|
||||
// --encoding arrives as a raw CLI string (Node validates it at use time).
|
||||
const buffer = await brain.vfs.readFile(path, {
|
||||
encoding: options.encoding as any
|
||||
encoding: options.encoding as BufferEncoding | undefined
|
||||
})
|
||||
|
||||
spinner.succeed('File read successfully')
|
||||
|
|
@ -103,8 +105,9 @@ export const vfsCommands = {
|
|||
process.exit(1)
|
||||
}
|
||||
|
||||
// --encoding arrives as a raw CLI string (Node validates it at use time).
|
||||
await brain.vfs.writeFile(path, data, {
|
||||
encoding: options.encoding as any
|
||||
encoding: options.encoding as BufferEncoding | undefined
|
||||
})
|
||||
|
||||
spinner.succeed('File written successfully')
|
||||
|
|
@ -135,7 +138,9 @@ export const vfsCommands = {
|
|||
try {
|
||||
const brain = await getBrainy()
|
||||
|
||||
const entries = await brain.vfs.readdir(path, { withFileTypes: true })
|
||||
// withFileTypes: true selects the VFSDirent[] branch of readdir's
|
||||
// `string[] | VFSDirent[]` union return type.
|
||||
const entries = await brain.vfs.readdir(path, { withFileTypes: true }) as VFSDirent[]
|
||||
|
||||
spinner.succeed(`Found ${Array.isArray(entries) ? entries.length : 0} items`)
|
||||
|
||||
|
|
@ -154,13 +159,14 @@ export const vfsCommands = {
|
|||
style: { head: [], border: [] }
|
||||
})
|
||||
|
||||
for (const entry of entries as any[]) {
|
||||
for (const entry of entries) {
|
||||
if (!options.all && entry.name.startsWith('.')) continue
|
||||
|
||||
const isDirectory = entry.type === 'directory'
|
||||
const stat = await brain.vfs.stat(`${path}/${entry.name}`)
|
||||
table.push([
|
||||
entry.isDirectory() ? chalk.blue('DIR') : 'FILE',
|
||||
entry.isDirectory() ? '-' : formatBytes(stat.size),
|
||||
isDirectory ? chalk.blue('DIR') : 'FILE',
|
||||
isDirectory ? '-' : formatBytes(stat.size),
|
||||
formatDate(stat.mtime),
|
||||
entry.name
|
||||
])
|
||||
|
|
@ -170,10 +176,10 @@ export const vfsCommands = {
|
|||
} else {
|
||||
// Simple format
|
||||
console.log()
|
||||
for (const entry of entries as any[]) {
|
||||
for (const entry of entries) {
|
||||
if (!options.all && entry.name.startsWith('.')) continue
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
if (entry.type === 'directory') {
|
||||
console.log(chalk.blue(entry.name + '/'))
|
||||
} else {
|
||||
console.log(entry.name)
|
||||
|
|
@ -322,8 +328,11 @@ export const vfsCommands = {
|
|||
if (result.score) {
|
||||
console.log(chalk.dim(` Score: ${(result.score * 100).toFixed(1)}%`))
|
||||
}
|
||||
if ((result as any).excerpt) {
|
||||
console.log(chalk.dim(` ${(result as any).excerpt}`))
|
||||
// `excerpt` isn't part of the VFS SearchResult contract — search()
|
||||
// doesn't attach it today; read defensively.
|
||||
const excerpt = (result as SearchResult & { excerpt?: string }).excerpt
|
||||
if (excerpt) {
|
||||
console.log(chalk.dim(` ${excerpt}`))
|
||||
}
|
||||
console.log()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ ${chalk.cyan('Examples:')}
|
|||
$ brainy add "React is a JavaScript library"
|
||||
$ brainy find "JavaScript frameworks"
|
||||
$ brainy update <id> --content "Updated content"
|
||||
$ brainy delete <id> ${chalk.dim('# Requires confirmation')}
|
||||
$ brainy remove <id> ${chalk.dim('# Requires confirmation')}
|
||||
$ brainy search "react" --type Component --where '{"tested":true}'
|
||||
|
||||
${chalk.dim('# Neural API')}
|
||||
|
|
@ -143,10 +143,10 @@ program
|
|||
.action(coreCommands.update)
|
||||
|
||||
program
|
||||
.command('delete [id]')
|
||||
.description('Delete an entity (interactive if no ID, requires confirmation)')
|
||||
.command('remove [id]')
|
||||
.description('Remove an entity (interactive if no ID, requires confirmation)')
|
||||
.option('-f, --force', 'Skip confirmation prompt')
|
||||
.action(coreCommands.deleteEntity)
|
||||
.action(coreCommands.removeEntity)
|
||||
|
||||
program
|
||||
.command('unrelate [id]')
|
||||
|
|
@ -472,7 +472,7 @@ program
|
|||
.addCommand(
|
||||
new Command('batch-delete')
|
||||
.argument('<file>', 'File containing entity IDs (one per line)')
|
||||
.description('Delete a list of entities through the public delete path (with retry)')
|
||||
.description('Delete a list of entities through the public remove() 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) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue