Feat: enhance cli.ts with updated typings and improved search interface

- Introduced `SearchResult` interface to standardize search result handling and improve code readability.
- Added TypeScript type annotations for command arguments and options in CLI methods to enforce stricter type safety.
- Updated `.version()` for CLI to align with best practices by removing redundant description parameter.
- Enhanced search logic with default parameter handling for limits and improved output formatting for results.
- Adjusted `tsconfig.json` to disable `noImplicitAny` while retaining strict typing practices.
- Streamlined CLI processes by parsing command-line arguments explicitly with `program.parse(process.argv)`.

Purpose: Improve developer productivity with better type safety, clearer interfaces, and refined CLI functionality.
This commit is contained in:
David Snelling 2025-07-18 12:00:50 -07:00
parent 3fe2a6e7f0
commit e9aaec89d8
2 changed files with 33 additions and 24 deletions

View file

@ -27,12 +27,25 @@ import { fileURLToPath } from 'url'
import { dirname, join } from 'path'
import fs from 'fs'
import { Command } from 'commander'
// @ts-expect-error - Missing type declarations for omelette
import omelette from 'omelette'
// Get the directory of the current module
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
// Define interface for search results
interface SearchResult {
id: string;
metadata?: {
noun?: string;
label?: string;
[key: string]: any;
};
vector: number[];
score?: number;
}
// Get version from package.json
const packageJsonPath = join(__dirname, '..', 'package.json')
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
@ -93,7 +106,7 @@ program
.description(
'A vector database using HNSW indexing with Origin Private File System storage'
)
.version(VERSION, '-V, --version', 'Output the current version')
.version(VERSION, '-V, --version')
// Create data directory if it doesn't exist
const dataDir = join(process.cwd(), 'data')
@ -128,7 +141,7 @@ program
.description('Add a new noun with the given text and optional metadata')
.argument('<text>', 'Text to add as a noun')
.argument('[metadata]', 'Optional metadata as JSON string')
.action(async (text, metadataStr) => {
.action(async (text: string, metadataStr: string) => {
try {
const db = createDb()
await db.init()
@ -153,27 +166,22 @@ program
.description('Search for nouns similar to the query')
.argument('<query>', 'Search query text')
.option('-l, --limit <number>', 'Maximum number of results to return', '5')
.action(async (query, options) => {
.action(async (query: string, options: { limit?: string, type?: string }) => {
try {
const db = createDb()
await db.init()
const limit = parseInt(options.limit, 10)
const results = await db.searchText(query, limit)
const limit = parseInt(options.limit || '5', 10)
const results: SearchResult[] = await db.searchText(query, limit)
console.log(`Search results for "${query}":`)
results.forEach(
(
result: {
id: string
score: number
metadata: any
vector: number[]
},
result: SearchResult,
index: number
) => {
console.log(`${index + 1}. ID: ${result.id}`)
console.log(` Score: ${result.score.toFixed(4)}`)
console.log(` Score: ${result.score ? result.score.toFixed(4) : 'N/A'}`)
console.log(` Metadata: ${JSON.stringify(result.metadata)}`)
console.log(
` Vector: [${result.vector
@ -194,7 +202,7 @@ program
.command('get')
.description('Get a noun by ID')
.argument('<id>', 'ID of the noun to get')
.action(async (id) => {
.action(async (id: string) => {
try {
const db = createDb()
await db.init()
@ -222,7 +230,7 @@ program
.command('delete')
.description('Delete a noun by ID')
.argument('<id>', 'ID of the noun to delete')
.action(async (id) => {
.action(async (id: string) => {
try {
const db = createDb()
await db.init()
@ -242,7 +250,7 @@ program
.argument('<targetId>', 'ID of the target noun')
.argument('<verbType>', 'Type of relationship')
.argument('[metadata]', 'Optional metadata as JSON string')
.action(async (sourceId, targetId, verbTypeStr, metadataStr) => {
.action(async (sourceId: string, targetId: string, verbTypeStr: string, metadataStr: string) => {
try {
const db = createDb()
await db.init()
@ -268,7 +276,7 @@ program
.command('getVerbs')
.description('Get all relationships for a noun')
.argument('<id>', 'ID of the noun to get relationships for')
.action(async (id) => {
.action(async (id: string) => {
try {
const db = createDb()
await db.init()
@ -367,7 +375,7 @@ program
.command('backup')
.description('Backup all data from the database to a JSON file')
.argument('[filename]', 'Output filename (default: brainy-backup.json)')
.action(async (filename) => {
.action(async (filename: string) => {
try {
const db = createDb()
await db.init()
@ -396,7 +404,7 @@ program
.description('Restore data from a JSON file into the database')
.argument('<filename>', 'Input JSON file')
.option('-c, --clear', 'Clear existing data before restoring', false)
.action(async (filename, options) => {
.action(async (filename: string, options: { clear?: boolean }) => {
try {
const db = createDb()
await db.init()
@ -430,7 +438,7 @@ program
)
.argument('<filename>', 'Input JSON file')
.option('-c, --clear', 'Clear existing data before importing', false)
.action(async (filename, options) => {
.action(async (filename: string, options: { clear?: boolean }) => {
try {
const db = createDb()
await db.init()
@ -488,11 +496,11 @@ program
// Get all nouns if no root is specified
if (!rootId && !nounType) {
// Get all nouns (limited by the limit option)
const allNouns = []
const allNouns: SearchResult[] = []
let count = 0
// Since there's no direct method to get all nouns, we'll use search with a high limit
const searchResults = await db.search('', 1000, {
const searchResults: SearchResult[] = await db.search('', 1000, {
forceEmbed: true
})
@ -561,12 +569,12 @@ program
console.log(`Visualizing nouns of type: ${nounType}\n`)
// Search for nouns of the specified type
const searchResults = await db.search('', 1000, {
const searchResults: SearchResult[] = await db.search('', 1000, {
nounTypes: [nounType],
forceEmbed: true
})
const filteredNouns = searchResults.slice(0, limit)
const filteredNouns: SearchResult[] = searchResults.slice(0, limit)
if (filteredNouns.length === 0) {
console.log(`No nouns found with type: ${nounType}`)
@ -1470,4 +1478,4 @@ program
})
// Parse command line arguments
program.parse()
program.parse(process.argv)