import { eq } from 'drizzle-orm'; import { getDb } from '../../db/client'; import { capabilities, capabilitySecrets, modules } from '../../db/schema'; import { getArg, validateRequiredArgs } from '../parser'; import type { CommandResult } from '../types'; /** * Handle capability info command * * Usage: celilo capability info * * @param args - Command arguments * @returns Command result with capability details */ export async function handleCapabilityInfo(args: string[]): Promise { const error = validateRequiredArgs(args, 1); if (error) { return { success: false, error: `${error}\n\nUsage: celilo capability info `, }; } const capabilityName = getArg(args, 0); if (!capabilityName) { return { success: false, error: 'Capability name is required', }; } const db = getDb(); const capability = db .select({ id: capabilities.id, capabilityName: capabilities.capabilityName, version: capabilities.version, data: capabilities.data, moduleId: capabilities.moduleId, moduleState: modules.state, registeredAt: capabilities.registeredAt, }) .from(capabilities) .innerJoin(modules, eq(capabilities.moduleId, modules.id)) .where(eq(capabilities.capabilityName, capabilityName)) .get(); if (!capability) { return { success: false, error: `Capability not found: ${capabilityName}`, }; } // Get capability secrets const secretRows = db .select({ name: capabilitySecrets.name, description: capabilitySecrets.description, hasValue: capabilitySecrets.encryptedValue, }) .from(capabilitySecrets) .where(eq(capabilitySecrets.capabilityId, capability.id)) .all(); const sections: string[] = []; // Section 1: Capability metadata const metaLines = [ `Capability: ${capability.capabilityName}`, `Version: ${capability.version}`, `Provider: ${capability.moduleId} (state: ${capability.moduleState})`, `Registered: ${capability.registeredAt.toISOString()}`, ]; sections.push(metaLines.join('\n')); // Section 2: Capability data if (capability.data && Object.keys(capability.data).length > 0) { const dataLines = ['Data:']; formatData(capability.data, dataLines, 1); sections.push(dataLines.join('\n')); } else { sections.push('Data: (none)'); } // Section 3: Secrets if (secretRows.length > 0) { const secretLines = ['Secrets:']; for (const secret of secretRows) { const status = secret.hasValue ? '[configured]' : '[not set]'; const desc = secret.description ? ` - ${secret.description}` : ''; secretLines.push(` ${secret.name}: ${status}${desc}`); } sections.push(secretLines.join('\n')); } return { success: true, message: sections.join('\n\n'), data: { capability, secrets: secretRows }, }; } /** * Format nested data object for display */ function formatData(data: Record, lines: string[], depth: number): void { const indent = ' '.repeat(depth); for (const [key, value] of Object.entries(data)) { if (value !== null && typeof value === 'object' && !Array.isArray(value)) { lines.push(`${indent}${key}:`); formatData(value as Record, lines, depth + 1); } else if (Array.isArray(value)) { lines.push(`${indent}${key}: [${value.join(', ')}]`); } else { lines.push(`${indent}${key}: ${value}`); } } }