use crate::cli::init::ensure_initialized;
use crate::cli::JournalCommands;
use crate::db::Database;
use crate::journal::JournalManager;
use anyhow::Result;
use colored::Colorize;
use std::env;
pub fn run(command: JournalCommands) -> Result<()> {
let project_root = env::current_dir()?;
if matches!(command, JournalCommands::Resume) {
ensure_initialized(&project_root, true)?;
} else {
let needs_minni = !matches!(
command,
JournalCommands::HooksInstall | JournalCommands::HooksUninstall
);
if needs_minni && !Database::minni_dir_exists(&project_root) {
println!(
"{} Minni not initialized. Run {} first.",
"Error:".red(),
"minni init".cyan()
);
return Ok(());
}
}
let journal = JournalManager::new(&project_root);
match command {
JournalCommands::Record => {
match journal.record_commit() {
Ok(entry) => {
println!("{} Recorded commit to journal", "✓".green());
if let Some(msg) = entry.commit_message {
println!(" {}", msg.dimmed());
}
}
Err(e) => {
eprintln!("{} Failed to record: {}", "!".yellow(), e);
}
}
}
JournalCommands::Show { count } => {
let md = journal.to_markdown(count)?;
println!("{}", md);
}
JournalCommands::Note { message } => {
journal.add_note(&message)?;
println!("{} Note added to journal", "✓".green());
}
JournalCommands::Clear => {
journal.clear()?;
println!("{} Journal cleared", "✓".green());
}
JournalCommands::HooksInstall => {
if !Database::minni_dir_exists(&project_root) {
println!(
"{} Minni not initialized. Run {} first.",
"Error:".red(),
"minni init".cyan()
);
return Ok(());
}
match journal.install_hooks() {
Ok(()) => {
println!("{} Git hooks installed!", "✓".green());
println!(" Journal will auto-record on each commit.");
println!(
" Run {} to see recent activity.",
"minni journal show".cyan()
);
}
Err(e) => {
println!("{} Failed to install hooks: {}", "Error:".red(), e);
}
}
}
JournalCommands::HooksUninstall => match journal.uninstall_hooks() {
Ok(()) => {
println!("{} Git hooks removed", "✓".green());
}
Err(e) => {
println!("{} Failed to remove hooks: {}", "Error:".red(), e);
}
},
JournalCommands::Resume => {
let entries = journal.get_recent(10)?;
if entries.is_empty() {
println!("{}", "No recent activity recorded.".dimmed());
return Ok(());
}
println!("{}", "=".repeat(60).dimmed());
println!("{}", "SESSION CONTEXT - Recent Activity".bold());
println!("{}", "=".repeat(60).dimmed());
println!();
if let Some(ref branch) = entries.last().and_then(|e| e.git_branch.clone()) {
println!("{}: {}", "Branch".yellow(), branch);
}
if let Some(ref commit) = entries.last().and_then(|e| e.git_commit.clone()) {
println!("{}: {}", "HEAD".yellow(), &commit[..7.min(commit.len())]);
}
println!();
println!("{}", "Recent commits:".bold());
for entry in entries.iter().rev().take(5) {
if let Some(ref msg) = entry.commit_message {
let hash = entry
.git_commit
.as_ref()
.map(|c| format!("[{}]", &c[..7.min(c.len())]))
.unwrap_or_default();
println!(" {} {}", hash.dimmed(), msg);
}
}
println!();
let mut recent_files: Vec<&str> = vec![];
for entry in entries.iter().rev().take(5) {
for fc in &entry.files_changed {
if !recent_files.contains(&fc.path.as_str()) {
recent_files.push(&fc.path);
}
}
}
if !recent_files.is_empty() {
println!("{}", "Recently modified files:".bold());
for f in recent_files.iter().take(10) {
println!(" {}", f.cyan());
}
println!();
}
let notes: Vec<_> = entries
.iter()
.filter_map(|e| e.user_note.as_ref())
.collect();
if !notes.is_empty() {
println!("{}", "Notes:".bold());
for note in notes.iter().rev().take(3) {
println!(" {}", note);
}
println!();
}
println!("{}", "=".repeat(60).dimmed());
}
}
Ok(())
}