feat: structured startup header with privileges, device, session

This commit is contained in:
Helios Agent 2026-03-05 20:22:58 +01:00
parent b37eec24bc
commit 03d80067a8
No known key found for this signature in database
GPG key ID: C8259547CD8309B5
2 changed files with 22 additions and 20 deletions

View file

@ -100,19 +100,13 @@ pub fn cmd_done(action: &str, name: &str, payload: &str, success: bool, result:
crate::logger::write_line(if success { "OK" } else { "ERROR" }, &format!("{name} {payload}{result}")); crate::logger::write_line(if success { "OK" } else { "ERROR" }, &format!("{name} {payload}{result}"));
} }
/// Plain status line (banner / connection info), not in table format. /// Info line for the startup header (not in table format).
/// Uses 2 leading spaces + emoji + 2 spaces + message (no tab). /// Aligns key to a fixed width so values line up.
pub fn status(emoji: &str, msg: &str) { pub fn info_line(emoji: &str, key: &str, value: &str) {
println!(" {} {}", emoji, msg); println!(" {} {:<12} {}", emoji_cell(emoji), key, value);
}
/// Same as status() but also logs to file.
pub fn ok(emoji: &str, msg: &str) {
println!(" {} {}", emoji, msg);
crate::logger::write_line("OK", msg);
} }
pub fn err(emoji: &str, msg: &str) { pub fn err(emoji: &str, msg: &str) {
println!(" {} {}", emoji, msg.red()); println!(" {} {}", emoji_cell(emoji), msg.red());
crate::logger::write_line("ERROR", msg); crate::logger::write_line("ERROR", msg);
} }

View file

@ -26,16 +26,24 @@ use display::trunc;
fn banner() { fn banner() {
println!(); println!();
println!(" {} HELIOS REMOTE ({})", "".yellow().bold(), env!("GIT_COMMIT")); println!(" {} HELIOS REMOTE ({})", "".yellow().bold(), env!("GIT_COMMIT"));
}
fn print_session_info(label: &str, sid: &uuid::Uuid) {
#[cfg(windows)] #[cfg(windows)]
{ {
let admin = is_admin(); let admin = is_admin();
let (icon, admin_str) = if admin { let priv_str = if admin {
("👑", "admin".green().bold().to_string()) "admin".green().bold().to_string()
} else { } else {
("👤", "user (no admin)".yellow().to_string()) "no admin".yellow().to_string()
}; };
println!(" {} {}", icon, admin_str); display::info_line("👤", "privileges:", &priv_str);
} }
#[cfg(not(windows))]
display::info_line("👤", "privileges:", &"no admin".yellow().to_string());
display::info_line("🖥", "device:", &label.bold().to_string());
display::info_line("#️⃣", "session:", &sid.to_string().dimmed().to_string());
println!(); println!();
} }
@ -154,14 +162,14 @@ async fn main() {
let config = match Config::load() { let config = match Config::load() {
Some(c) => c, Some(c) => c,
None => { None => {
display::status("", "No config found — first-time setup"); display::info_line("", "setup:", "No config found — first-time setup");
println!(); println!();
let c = prompt_config(); let c = prompt_config();
println!(); println!();
if let Err(e) = c.save() { if let Err(e) = c.save() {
display::err("", &format!("Failed to save config: {e}")); display::err("", &format!("Failed to save config: {e}"));
} else { } else {
display::ok("", "Config saved"); display::info_line("", "config:", "saved");
} }
c c
} }
@ -181,6 +189,9 @@ async fn main() {
} }
}; };
let label = config.label.clone().unwrap_or_else(|| hostname());
print_session_info(&label, &sid);
let config = Arc::new(config); let config = Arc::new(config);
let shell = Arc::new(Mutex::new(shell::PersistentShell::new())); let shell = Arc::new(Mutex::new(shell::PersistentShell::new()));
@ -206,10 +217,7 @@ async fn main() {
match connect_async_tls_with_config(&config.relay_url, None, false, Some(connector)).await { match connect_async_tls_with_config(&config.relay_url, None, false, Some(connector)).await {
Ok((ws_stream, _)) => { Ok((ws_stream, _)) => {
let label = config.label.clone().unwrap_or_else(|| hostname());
display::cmd_done("🌐", "connecting", host, true, "connected"); display::cmd_done("🌐", "connecting", host, true, "connected");
display::cmd_start("", "session", &label);
display::cmd_done("", "session", &label, true, &sid.to_string());
println!(); println!();
backoff = Duration::from_secs(1); backoff = Duration::from_secs(1);