feat: display name in banner + prompt
Banner shows human-readable principal and DID on separate lines: Principal: tking@guildhouse.dev DID: did:web:guildhouse.dev/user/tking Prompt uses short name: [governed] tking@gsh Reads BASCULE_DISPLAY_NAME env. Fallback: parse DID to name@domain. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ff16b5642e
commit
231bed5f92
2 changed files with 30 additions and 4 deletions
|
|
@ -150,7 +150,8 @@ fn print_banner(session: &SessionState) {
|
|||
println!();
|
||||
println!("{}", "╔══════════════════════════════════════════════════════════╗".bright_blue());
|
||||
println!("{} Guildhouse Governed Shell v0.1.0{}", "║".bright_blue(), " ".repeat(24).to_string() + &"║".bright_blue().to_string());
|
||||
println!("{} Principal: {:<44}{}", "║".bright_blue(), session.principal, "║".bright_blue());
|
||||
println!("{} Principal: {:<44}{}", "║".bright_blue(), session.display_name, "║".bright_blue());
|
||||
println!("{} DID: {:<44}{}", "║".bright_blue(), session.principal, "║".bright_blue());
|
||||
println!("{} Corpus: {:<44}{}", "║".bright_blue(), corpus_short, "║".bright_blue());
|
||||
println!("{} Session: {:<44}{}", "║".bright_blue(), format!("{} (expires {})", &session.ac_id[..8.min(session.ac_id.len())], expiry), "║".bright_blue());
|
||||
println!("{} Risk: {:<44}{}", "║".bright_blue(),
|
||||
|
|
@ -199,10 +200,10 @@ fn build_prompt(session: &SessionState) -> DefaultPrompt {
|
|||
_ => "[governed]",
|
||||
};
|
||||
|
||||
let user = session.principal.split('@').next().unwrap_or(&session.principal);
|
||||
let short_name = session.display_name.split('@').next().unwrap_or(&session.display_name);
|
||||
|
||||
DefaultPrompt::new(
|
||||
DefaultPromptSegment::Basic(format!("{} {}@gsh", risk_indicator, user)),
|
||||
DefaultPromptSegment::Basic(format!("{} {}@gsh", risk_indicator, short_name)),
|
||||
DefaultPromptSegment::Empty,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub struct SessionState {
|
|||
pub ac_id: String,
|
||||
pub corpus_cid: String,
|
||||
pub principal: String,
|
||||
pub display_name: String,
|
||||
pub risk_level: String,
|
||||
pub started_at: chrono::DateTime<chrono::Utc>,
|
||||
pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
|
||||
|
|
@ -35,10 +36,15 @@ impl SessionState {
|
|||
.and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok())
|
||||
.map(|dt| dt.with_timezone(&chrono::Utc));
|
||||
|
||||
// Display name: BASCULE_DISPLAY_NAME env, or derive from DID
|
||||
let display_name = std::env::var("BASCULE_DISPLAY_NAME")
|
||||
.unwrap_or_else(|_| display_name_from_did(&principal));
|
||||
|
||||
Self {
|
||||
ac_id: ac.context_id.clone(),
|
||||
corpus_cid: corpus_cid.to_string(),
|
||||
principal,
|
||||
display_name,
|
||||
risk_level: "standard".to_string(), // TODO: read from AC when broker embeds it
|
||||
started_at: chrono::Utc::now(),
|
||||
expires_at,
|
||||
|
|
@ -51,10 +57,14 @@ impl SessionState {
|
|||
|
||||
/// Create a minimal session for ungoverned mode.
|
||||
pub fn ungoverned(corpus_cid: &str) -> Self {
|
||||
let principal = whoami();
|
||||
let display_name = std::env::var("BASCULE_DISPLAY_NAME")
|
||||
.unwrap_or_else(|_| principal.clone());
|
||||
Self {
|
||||
ac_id: "ungoverned".to_string(),
|
||||
corpus_cid: corpus_cid.to_string(),
|
||||
principal: whoami(),
|
||||
principal,
|
||||
display_name,
|
||||
risk_level: "ungoverned".to_string(),
|
||||
started_at: chrono::Utc::now(),
|
||||
expires_at: None,
|
||||
|
|
@ -82,3 +92,18 @@ fn whoami() -> String {
|
|||
.or_else(|_| std::env::var("USERNAME"))
|
||||
.unwrap_or_else(|_| "operator".to_string())
|
||||
}
|
||||
|
||||
/// Derive a human-readable display name from a DID.
|
||||
/// did:web:guildhouse.dev/user/tking → tking@guildhouse.dev
|
||||
/// Fallback: return the full DID.
|
||||
fn display_name_from_did(did: &str) -> String {
|
||||
if let Some(rest) = did.strip_prefix("did:web:") {
|
||||
let parts: Vec<&str> = rest.splitn(2, '/').collect();
|
||||
if parts.len() == 2 {
|
||||
let domain = parts[0];
|
||||
let name = parts[1].rsplit('/').next().unwrap_or(parts[1]);
|
||||
return format!("{}@{}", name, domain);
|
||||
}
|
||||
}
|
||||
did.to_string()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue