aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichelle Tilley <michelle@michelletilley.net>2026-03-17 16:38:45 -0700
committerGitHub <noreply@github.com>2026-03-17 16:38:45 -0700
commit12742e32ed4edf77fe7aeb03bd0e734b3674d086 (patch)
treeb62537b60fc2beedaf10dbaaa583f9fab52a2723
parentchore(ci): use github for macos (diff)
downloadatuin-12742e32ed4edf77fe7aeb03bd0e734b3674d086.zip
feat: Report distro name with OS for distro-specific commands (#3289)
-rw-r--r--crates/atuin-ai/src/commands/inline.rs26
-rw-r--r--crates/atuin-client/src/distro.rs89
-rw-r--r--crates/atuin-client/src/lib.rs1
3 files changed, 108 insertions, 8 deletions
diff --git a/crates/atuin-ai/src/commands/inline.rs b/crates/atuin-ai/src/commands/inline.rs
index e0ee05d6..7cfacc77 100644
--- a/crates/atuin-ai/src/commands/inline.rs
+++ b/crates/atuin-ai/src/commands/inline.rs
@@ -4,6 +4,7 @@ use crate::tui::{
App, AppEvent, AppMode, ConversationEvent, EventLoop, ExitAction, RenderContext, TerminalGuard,
calculate_needed_height, install_panic_hook,
};
+use atuin_client::distro::detect_linux_distribution;
use atuin_client::theme::ThemeManager;
use atuin_common::tls::ensure_crypto_provider;
use crossterm::{
@@ -185,16 +186,25 @@ fn create_chat_stream(
debug!("Sending SSE request to {endpoint}");
+ let os = detect_os();
+ let shell = detect_shell();
+
+ let mut context = serde_json::json!({
+ "os": os,
+ "shell": shell,
+ "pwd": if send_cwd { std::env::current_dir()
+ .ok()
+ .map(|path| path.to_string_lossy().into_owned()) } else { None },
+ });
+
+ if os == "linux" {
+ context["distro"] = serde_json::json!(detect_linux_distribution());
+ }
+
// Build request body
let mut request_body = serde_json::json!({
"messages": messages,
- "context": {
- "os": detect_os(),
- "shell": detect_shell(),
- "pwd": if send_cwd { std::env::current_dir()
- .ok()
- .map(|path| path.to_string_lossy().into_owned()) } else { None },
- }
+ "context": context,
});
// Include session_id only if present (not on first request)
@@ -331,7 +341,7 @@ fn detect_os() -> String {
"macos" => "macos".to_string(),
"linux" => "linux".to_string(),
"windows" => "windows".to_string(),
- _ => "linux".to_string(),
+ other => format!("Other: {other}"),
}
}
diff --git a/crates/atuin-client/src/distro.rs b/crates/atuin-client/src/distro.rs
new file mode 100644
index 00000000..dead8355
--- /dev/null
+++ b/crates/atuin-client/src/distro.rs
@@ -0,0 +1,89 @@
+use std::process::Command;
+
+/// Detect the Linux distribution from the system,
+/// using system-specific release files and falling
+/// back to lsb_release.
+pub fn detect_linux_distribution() -> String {
+ detect_from_os_release()
+ .or_else(detect_from_debian_version)
+ .or_else(detect_from_centos_release)
+ .or_else(detect_from_redhat_release)
+ .or_else(detect_from_fedora_release)
+ .or_else(detect_from_arch_release)
+ .or_else(detect_from_alpine_release)
+ .or_else(detect_from_suse_release)
+ .or_else(detect_from_lsb_release)
+ .unwrap_or_else(|| "Unknown".to_string())
+}
+
+fn detect_from_os_release() -> Option<String> {
+ let content = std::fs::read_to_string("/etc/os-release").ok()?;
+
+ content
+ .lines()
+ .find(|l| l.starts_with("PRETTY_NAME="))
+ .and_then(|l| l.split_once('=').map(|s| s.1))
+ .map(|s| s.trim_matches('"').to_string())
+}
+
+fn detect_from_debian_version() -> Option<String> {
+ std::fs::read_to_string("/etc/debian_version")
+ .ok()
+ .map(|v| format!("Debian {}", v.trim()))
+}
+
+fn detect_from_centos_release() -> Option<String> {
+ std::fs::read_to_string("/etc/centos-release")
+ .ok()
+ .map(|v| v.trim().to_string())
+}
+
+fn detect_from_redhat_release() -> Option<String> {
+ std::fs::read_to_string("/etc/redhat-release")
+ .ok()
+ .map(|v| v.trim().to_string())
+}
+
+fn detect_from_fedora_release() -> Option<String> {
+ std::fs::read_to_string("/etc/fedora-release")
+ .ok()
+ .map(|v| v.trim().to_string())
+}
+
+fn detect_from_arch_release() -> Option<String> {
+ std::fs::read_to_string("/etc/arch-release")
+ .ok()
+ .filter(|v| !v.trim().is_empty())
+ .map(|_| "Arch Linux".to_string())
+}
+
+fn detect_from_alpine_release() -> Option<String> {
+ std::fs::read_to_string("/etc/alpine-release")
+ .ok()
+ .map(|v| format!("Alpine {}", v.trim()))
+}
+
+fn detect_from_suse_release() -> Option<String> {
+ std::fs::read_to_string("/etc/SuSE-release")
+ .ok()
+ .and_then(|content| content.lines().next().map(|l| l.trim().to_string()))
+}
+
+fn detect_from_lsb_release() -> Option<String> {
+ let output = Command::new("lsb_release").arg("-a").output().ok()?;
+
+ if !output.status.success() {
+ return None;
+ }
+
+ let output = String::from_utf8(output.stdout).ok()?;
+ linux_distro_from_lsb_release(&output)
+}
+
+fn linux_distro_from_lsb_release(output: &str) -> Option<String> {
+ output
+ .lines()
+ .find(|line| line.starts_with("Description:"))
+ .and_then(|line| line.split_once(':').map(|s| s.1))
+ .map(|s| s.trim().to_string())
+}
diff --git a/crates/atuin-client/src/lib.rs b/crates/atuin-client/src/lib.rs
index 4609a8e8..7938176a 100644
--- a/crates/atuin-client/src/lib.rs
+++ b/crates/atuin-client/src/lib.rs
@@ -17,6 +17,7 @@ pub mod register;
pub mod sync;
pub mod database;
+pub mod distro;
pub mod encryption;
pub mod history;
pub mod import;