/** * Module logs command - show deploy logs for a module */ import { existsSync, readFileSync } from 'node:fs'; import { join } from 'node:path'; import { eq } from 'drizzle-orm'; import { getModuleStoragePath } from '../../config/paths'; import { getDb } from '../../db/client'; import { modules } from '../../db/schema'; import { getArg, hasFlag, validateRequiredArgs } from '../parser'; import type { CommandResult } from '../types'; /** * Handle module logs command * * Usage: celilo module logs [--tail ] */ export async function handleModuleLogs( args: string[], flags: Record, ): Promise { const error = validateRequiredArgs(args, 1); if (error) { return { success: false, error: `${error}\n\nUsage: celilo module logs [--tail ]`, }; } const moduleId = getArg(args, 0); if (!moduleId) { return { success: false, error: 'Module ID is required' }; } const db = getDb(); const module = db.select().from(modules).where(eq(modules.id, moduleId)).get(); if (!module) { return { success: false, error: `Module not found: ${moduleId}` }; } const logPath = join(getModuleStoragePath(), moduleId, 'generated', 'deploy.log'); if (!existsSync(logPath)) { return { success: true, message: `No deploy logs found for ${moduleId}.\nLogs are created on the next deployment.`, }; } const content = readFileSync(logPath, 'utf-8'); // --tail N: show only the last N lines const tailValue = flags.tail; if (typeof tailValue === 'string') { const n = Number.parseInt(tailValue, 10); if (Number.isNaN(n) || n < 1) { return { success: false, error: '--tail requires a positive number' }; } const lines = content.trimEnd().split('\n'); const tail = lines.slice(-n); return { success: true, message: tail.join('\n') }; } // --last: show only the most recent deploy run if (hasFlag(flags, 'last')) { const runs = content.split(/(?=\n--- Ansible deploy )/); const lastRun = runs[runs.length - 1]; return { success: true, message: (lastRun || content).trim() }; } return { success: true, message: content.trim() }; }