@visionfi/server-cli
Version:
Command-line interface for VisionFI Server SDK
209 lines (208 loc) • 9.53 kB
JavaScript
/**
* VisionFI Server CLI
* Command-line interface for VisionFI Server SDK
* The VisionFI Server CLI provides commands to manage packages and handle authentication.
* It connects to the VisionFI API and allows users to perform various operations from the command line in a service to service pattern.
* Copyright (c) 2024-2025 VisionFI. All Rights Reserved.
*/
import { Command } from 'commander';
import { verifyAuth, configureAuth, getToken, logout, showAuth } from './commands/auth.js';
import { createPackage, listPackages, getPackage, getPackageAudit, addExternalReferences, removeExternalReferences } from './commands/package.js';
import { addDocuments, deleteDocument } from './commands/document.js';
import { executeProcessing, getProcessingHistory, getProcessingResult, getProcessingView, pollProcessing } from './commands/processing.js';
import { getProductTypes, getWorkflows, getClientInfo } from './commands/admin.js';
import { Display } from './utils/display.js';
import { getConfigPath, loadConfig, saveConfig } from './utils/config.js';
import * as dotenv from 'dotenv';
import * as fs from 'fs';
// Load environment variables
dotenv.config();
// Create the main program
const program = new Command();
program
.name('visionfi')
.description('VisionFI Command Line Interface')
.version('1.0.0');
// Auth command group
const auth = program.command('auth')
.description('Authentication commands');
auth.command('verify')
.description('Verify authentication with VisionFI API')
.action(verifyAuth);
auth.command('configure')
.description('Configure authentication settings')
.option('--method <method>', 'Authentication method: file, adc, impersonate, or env')
.option('--service-account-path <path>', 'Path to service account JSON file (when method=file)')
.option('--impersonate-service-account <email>', 'Service account email to impersonate (when method=impersonate)')
.action((options) => configureAuth(options));
auth.command('show')
.description('Show current authentication configuration')
.action(showAuth);
auth.command('logout')
.description('Clear authentication configuration')
.action(logout);
auth.command('token')
.description('Get JWT authentication token')
.action(getToken);
// Package command group
const pkg = program.command('package')
.alias('pkg')
.description('Package management commands');
pkg.command('create')
.description('Create a new package')
.requiredOption('--product-type <type>', 'Product type for the package')
.requiredOption('--description <desc>', 'Package description')
.option('--external-ref <ref...>', 'External reference IDs (array field)')
.option('--ref1 <ref>', 'External reference 1 (exact match field)')
.option('--ref2 <ref>', 'External reference 2 (exact match field)')
.option('--ref3 <ref>', 'External reference 3 (exact match field)')
.option('--ref4 <ref>', 'External reference 4 (exact match field)')
.option('--ref5 <ref>', 'External reference 5 (exact match field)')
.option('--category <category>', 'External category for semantic filtering')
.option('--owner <owner>', 'External owner/department')
.action(createPackage);
pkg.command('list')
.description('List packages')
.option('--external-ref <ref>', 'Filter by external reference (deprecated, use --tags)')
.option('--tags <tags>', 'Filter by tags (comma-separated, OR logic)')
.option('--ref1 <ref>', 'Filter by external reference 1 (exact match)')
.option('--ref2 <ref>', 'Filter by external reference 2 (exact match)')
.option('--ref3 <ref>', 'Filter by external reference 3 (exact match)')
.option('--ref4 <ref>', 'Filter by external reference 4 (exact match)')
.option('--ref5 <ref>', 'Filter by external reference 5 (exact match)')
.option('--category <category>', 'Filter by external category')
.option('--owner <owner>', 'Filter by external owner')
.option('--product-type <type>', 'Filter by product type')
.option('--created-after <date>', 'Filter by creation date')
.action(listPackages);
pkg.command('get <packageId>')
.description('Get package details')
.action(getPackage);
pkg.command('audit <packageId>')
.description('Get package audit history')
.option('--limit <n>', 'Limit number of audit entries')
.action((packageId, options) => getPackageAudit(packageId, options));
// Package reference subcommands
const pkgRef = pkg.command('ref')
.description('External reference management');
pkgRef.command('add <packageId>')
.description('Add external references to a package')
.requiredOption('--refs <refs...>', 'External reference IDs to add')
.action((packageId, options) => addExternalReferences(packageId, options));
pkgRef.command('remove <packageId>')
.description('Remove external references from a package')
.requiredOption('--refs <refs...>', 'External reference IDs to remove')
.action((packageId, options) => removeExternalReferences(packageId, options));
// Package document subcommands
const pkgDoc = pkg.command('document')
.alias('doc')
.description('Document management');
pkgDoc.command('add <packageId>')
.description('Add documents to a package')
.requiredOption('--file <path...>', 'File path(s) to add')
.action((packageId, options) => addDocuments(packageId, options));
pkgDoc.command('delete <packageId> <documentId>')
.description('Delete a document from a package')
.action((packageId, documentId) => deleteDocument(packageId, documentId));
// Package processing subcommands
const pkgProc = pkg.command('processing')
.alias('proc')
.description('Processing operations');
pkgProc.command('execute <packageId>')
.description('Execute processing on a package')
.option('--workflow <workflow>', 'Workflow to use')
.action((packageId, options) => executeProcessing(packageId, options));
pkgProc.command('history <packageId>')
.description('Get processing history')
.option('--limit <n>', 'Limit number of results')
.option('--with-results', 'Include processing results')
.action((packageId, options) => getProcessingHistory(packageId, options));
pkgProc.command('result <packageId> <processingId>')
.description('Get specific processing result')
.action((packageId, processingId) => getProcessingResult(packageId, processingId));
pkgProc.command('view <packageId> <processingId>')
.description('Get processing view')
.option('--format <format>', 'View format')
.action((packageId, processingId, options) => getProcessingView(packageId, processingId, options));
pkgProc.command('poll <packageId> <processingId>')
.description('Poll for processing completion')
.option('--timeout <ms>', 'Maximum wait time in milliseconds')
.option('--interval <ms>', 'Poll interval in milliseconds')
.action((packageId, processingId, options) => pollProcessing(packageId, processingId, options));
// Admin command group
const admin = program.command('admin')
.description('Administrative commands');
admin.command('products')
.description('Get available product types')
.action(getProductTypes);
admin.command('workflows')
.description('Get available workflows')
.action(getWorkflows);
admin.command('client')
.description('Get client information')
.action(getClientInfo);
// Config command group
const configCmd = program.command('config')
.description('Configuration management');
configCmd.command('show')
.description('Show configuration file location and contents')
.action(() => {
const configPath = getConfigPath();
Display.info(`Configuration file: ${configPath}`);
if (fs.existsSync(configPath)) {
try {
const configContent = fs.readFileSync(configPath, 'utf-8');
Display.info('');
Display.info('Contents:');
console.log(configContent);
}
catch (error) {
Display.error(`Failed to read config: ${error.message}`);
}
}
else {
Display.warning('Configuration file does not exist');
}
});
configCmd.command('set')
.description('Set configuration values')
.option('--api-url <url>', 'Set the VisionFI API URL')
.option('--audience <audience>', 'Set the token audience (default: platform.visionfi.ai)')
.action((options) => {
const config = loadConfig();
if (options.apiUrl) {
config.apiUrl = options.apiUrl;
Display.success(`API URL set to: ${options.apiUrl}`);
}
if (options.audience) {
config.audience = options.audience;
Display.success(`Audience set to: ${options.audience}`);
}
if (options.apiUrl || options.audience) {
saveConfig(config);
Display.info('Configuration saved');
}
else {
Display.error('No configuration values provided');
Display.info('Use --api-url or --audience');
process.exit(1);
}
});
configCmd.command('path')
.description('Show configuration file path')
.action(() => {
Display.info(`Configuration file: ${getConfigPath()}`);
});
// Handle unknown commands
program.on('command:*', () => {
Display.error(`Invalid command: ${program.args.join(' ')}`);
Display.info('Run "visionfi --help" for a list of available commands');
process.exit(1);
});
// Parse command line arguments
program.parse();
// Show help if no command provided
if (!process.argv.slice(2).length) {
program.outputHelp();
}