use colored::Colorize;
pub(crate) struct Theme;
impl Theme {
pub(crate) fn header(text: &str) -> String {
format!("{}", text.bold().cyan())
}
pub(crate) fn success(text: &str) -> String {
format!("{} {}", "✓".green(), text)
}
pub(crate) fn error(text: &str) -> String {
format!("{} {}", "✗".red(), text.red())
}
pub(crate) fn warning(text: &str) -> String {
format!("{} {}", "!".yellow(), text.yellow())
}
pub(crate) fn info(text: &str) -> String {
format!("{} {}", "i".blue(), text)
}
pub(crate) fn dimmed(text: &str) -> String {
format!("{}", text.dimmed())
}
pub(crate) fn prompt(text: &str) -> String {
format!("{}", text.bold())
}
pub(crate) fn separator() -> String {
"━".repeat(50).dimmed().to_string()
}
pub(crate) fn approval_box(title: &str, content: &str) -> String {
let color_fn = |s: &str| s.yellow().to_string();
let width = 60;
let top = format!("╭{}╮", "─".repeat(width - 2));
let bottom = format!("╰{}╯", "─".repeat(width - 2));
let empty = format!("│{:w$}│", "", w = width - 2);
let pad_line = |text: &str| -> String {
let visible_len = strip_ansi(text).len();
let padding = (width - 4).saturating_sub(visible_len);
format!("│ {text}{:p$} │", "", p = padding)
};
let mut lines = vec![
color_fn(&top),
pad_line(&title.bold().to_string()),
color_fn(&empty),
];
for line in content.lines() {
lines.push(pad_line(line));
}
lines.push(color_fn(&bottom));
lines.join("\n")
}
pub(crate) fn kv(key: &str, value: &str) -> String {
format!("{}: {}", key.bold(), value)
}
pub(crate) fn session_id(id: &str) -> String {
let short = if id.len() > 8 { &id[..8] } else { id };
format!("{}", short.cyan())
}
pub(crate) fn timestamp(dt: &chrono::DateTime<chrono::Utc>) -> String {
dt.format("%Y-%m-%d %H:%M").to_string().dimmed().to_string()
}
}
fn strip_ansi(s: &str) -> String {
let mut result = String::with_capacity(s.len());
let mut in_escape = false;
for c in s.chars() {
if in_escape {
if c.is_ascii_alphabetic() {
in_escape = false;
}
} else if c == '\x1b' {
in_escape = true;
} else {
result.push(c);
}
}
result
}
pub(crate) fn print_banner() {
let version = env!("CARGO_PKG_VERSION");
println!(
"{}",
format!(
r"
_ _ _ _
/_\ ___ | |_ _ __ __ _| (_)___
//_\\ / __|| __| '__/ _` | | / __|
/ _ \\__ \| |_| | | (_| | | \__ \
\_/ \_/|___/ \__|_| \__,_|_|_|___/
v{version}
"
)
.cyan()
);
println!("{}", "Secure Agent Runtime".dimmed());
println!();
}