morph-cli 0.1.0

AST-based codebase migration and codemod tool for JavaScript and TypeScript projects.
Documentation
use anyhow::Result;
use chrono::{TimeZone, Utc};
use std::path::Path;
use crate::core::session::SessionStore;
use crate::utils::terminal;
use colored::Colorize;

pub fn execute(limit: usize, project_root: &Path) -> Result<()> {
    let store = SessionStore::new(project_root);
    let sessions = store.list()?;

    if sessions.is_empty() {
        println!("{} No migration history found.", terminal::info_prefix());
        return Ok(());
    }

    println!("{}", terminal::label("Migration History"));
    println!("{}", terminal::label("".repeat(60).as_str()));

    let display_count = sessions.len().min(limit);
    for session in sessions.iter().take(display_count) {
        let dt = Utc.timestamp_opt(session.started_at as i64, 0).unwrap();
        let timestamp = dt.format("%Y-%m-%d %H:%M:%S UTC").to_string();
        
        let mode_label = if session.options.write { 
            "WRITE".bold().red().to_string() 
        } else { 
            "DRY-RUN".bold().green().to_string() 
        };

        println!();
        println!("{} ID: {}", terminal::bullet(), terminal::label(&session.id));
        println!("  Timestamp: {}", timestamp);
        println!("  Mode:      {}", mode_label);
        println!("  Recipes:   {}", session.recipe_names.join(", ").cyan());
        println!("  Modified:  {} file(s)", session.modified_files.len().to_string().bold());
    }

    if sessions.len() > limit {
        println!("\n... and {} more sessions. Use `-n <limit>` to see more.", sessions.len() - limit);
    }

    Ok(())
}