Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ book/
.env*

run-build.sh
# Amazon Q CLI files
.amazonq/
9 changes: 6 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/alacritty_terminal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ workspace = true
[dependencies]
bitflags.workspace = true
camino.workspace = true
fig_os_shim.workspace = true
serde.workspace = true
serde_yaml = "0.9"
shell-color.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/alacritty_terminal/src/term/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,7 @@ impl<T> Term<T> {
trace!("New command cursor: {:?}", self.shell_state.cmd_cursor);

// Add work around for emojis
if let Ok(cursor_offset) = std::env::var("Q_PROMPT_OFFSET_WORKAROUND") {
if let Ok(cursor_offset) = fig_os_shim::Env::new().q_prompt_offset_workaround() {
if let Ok(offset) = cursor_offset.parse::<i32>() {
self.shell_state.cmd_cursor = self.shell_state.cmd_cursor.map(|cursor| Point {
column: Column((cursor.column.0 as i32 - offset).max(0) as usize),
Expand Down
1 change: 1 addition & 0 deletions crates/fig_api_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ aws-types.workspace = true
bytes.workspace = true
fig_auth.workspace = true
fig_aws_common.workspace = true
fig_os_shim.workspace = true
fig_request.workspace = true
fig_settings.workspace = true
fig_util.workspace = true
Expand Down
4 changes: 1 addition & 3 deletions crates/fig_api_client/src/clients/streaming_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ pub struct StreamingClient {

impl StreamingClient {
pub async fn new() -> Result<Self, Error> {
let client = if fig_util::system_info::in_cloudshell()
|| std::env::var("Q_USE_SENDMESSAGE").is_ok_and(|v| !v.is_empty())
{
let client = if fig_util::system_info::in_cloudshell() || fig_os_shim::Env::new().q_use_sendmessage() {
Self::new_qdeveloper_client(&Endpoint::load_q()).await?
} else {
Self::new_codewhisperer_client(&Endpoint::load_codewhisperer()).await
Expand Down
2 changes: 1 addition & 1 deletion crates/fig_desktop/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ async fn main() -> ExitCode {

#[cfg(target_os = "linux")]
{
match std::env::var("Q_BACKEND").ok().as_deref() {
match fig_os_shim::Env::new().q_backend().ok().as_deref() {
Some("default") => {},
// SAFETY: we are calling set_var in a single-threaded context.
Some(backend) => unsafe { std::env::set_var("GDK_BACKEND", backend) },
Expand Down
2 changes: 1 addition & 1 deletion crates/fig_install/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const DEFAULT_RELEASE_URL: &str = "https://desktop-release.q.us-east-1.amazonaws
/// - The setting `install.releaseUrl`
/// - Falls back to the default or the build time env var `Q_BUILD_DESKTOP_RELEASE_URL`
static RELEASE_URL: LazyLock<Url> = LazyLock::new(|| {
match std::env::var("Q_DESKTOP_RELEASE_URL") {
match fig_os_shim::Env::new().q_desktop_release_url() {
Ok(s) => Url::parse(&s),
Err(_) => match fig_settings::settings::get_string("install.releaseUrl") {
Ok(Some(s)) => Url::parse(&s),
Expand Down
1 change: 1 addition & 0 deletions crates/fig_log/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ default = []
# sentry = ["dep:sentry-tracing"]

[dependencies]
fig_os_shim.workspace = true
fig_util.workspace = true
parking_lot.workspace = true
thiserror.workspace = true
Expand Down
13 changes: 6 additions & 7 deletions crates/fig_log/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::path::Path;
use std::sync::Mutex;

use fig_util::CHAT_BINARY_NAME;
use fig_util::env_var::Q_LOG_LEVEL;
use thiserror::Error;
use tracing::info;
use tracing::level_filters::LevelFilter;
Expand Down Expand Up @@ -192,11 +191,11 @@ pub fn initialize_logging<T: AsRef<Path>>(args: LogArgs<T>) -> Result<LogGuard,
///
/// Returns a string identifying the current log level.
pub fn get_log_level() -> String {
Q_LOG_LEVEL_GLOBAL
.lock()
.unwrap()
.clone()
.unwrap_or_else(|| std::env::var(Q_LOG_LEVEL).unwrap_or_else(|_| DEFAULT_FILTER.to_string()))
Q_LOG_LEVEL_GLOBAL.lock().unwrap().clone().unwrap_or_else(|| {
fig_os_shim::Env::new()
.q_log_level()
.unwrap_or_else(|_| DEFAULT_FILTER.to_string())
})
}

/// Set the log level to the given level.
Expand Down Expand Up @@ -247,7 +246,7 @@ fn create_filter_layer() -> EnvFilter {
.lock()
.unwrap()
.clone()
.or_else(|| std::env::var(Q_LOG_LEVEL).ok());
.or_else(|| fig_os_shim::Env::new().q_log_level().ok());

match log_level {
Some(level) => EnvFilter::builder()
Expand Down
77 changes: 77 additions & 0 deletions crates/fig_os_shim/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,83 @@ impl Env {
pub fn in_appimage(&self) -> bool {
self.get_os("APPIMAGE").is_some()
}

// Q-specific environment variable methods
pub fn q_fake_is_remote(&self) -> bool {
self.get_os("Q_FAKE_IS_REMOTE").is_some()
Copy link
Contributor

@kkashilk kkashilk Oct 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: rename get_os to get_os_env_var

}

pub fn q_log_level(&self) -> Result<String, VarError> {
self.get("Q_LOG_LEVEL")
}

pub fn q_log_stdout(&self) -> bool {
self.get_os("Q_LOG_STDOUT").is_some()
}

pub fn amazon_q_sigv4(&self) -> bool {
self.get("AMAZON_Q_SIGV4").is_ok_and(|v| !v.is_empty())
}

pub fn amazon_q_chat_shell(&self) -> String {
self.get("AMAZON_Q_CHAT_SHELL").unwrap_or_else(|_| "bash".to_string())
}

pub fn q_cli_client_application(&self) -> Result<String, VarError> {
self.get("Q_CLI_CLIENT_APPLICATION")
}

pub fn q_parent(&self) -> Result<String, VarError> {
self.get("Q_PARENT")
}

pub fn q_term(&self) -> Result<String, VarError> {
self.get("Q_TERM")
}

pub fn q_using_zsh_autosuggestions(&self) -> bool {
self.get_os("Q_USING_ZSH_AUTOSUGGESTIONS").is_some()
}

pub fn q_init_snapshot_test(&self) -> bool {
self.get_os("Q_INIT_SNAPSHOT_TEST").is_some()
}

pub fn q_desktop_release_url(&self) -> Result<String, VarError> {
self.get("Q_DESKTOP_RELEASE_URL")
}

pub fn q_inline_shell_completion_cache_enabled(&self) -> bool {
self.get_os("Q_INLINE_SHELL_COMPLETION_CACHE_DISABLE").is_none()
}

pub fn q_inline_shell_completion_history_count(&self) -> Result<String, VarError> {
self.get("Q_INLINE_SHELL_COMPLETION_HISTORY_COUNT")
}

pub fn q_inline_shell_completion_debounce_ms(&self) -> Result<String, VarError> {
self.get("Q_INLINE_SHELL_COMPLETION_DEBOUNCE_MS")
}

pub fn q_backend(&self) -> Result<String, VarError> {
self.get("Q_BACKEND")
}

pub fn q_prompt_offset_workaround(&self) -> Result<String, VarError> {
self.get("Q_PROMPT_OFFSET_WORKAROUND")
}

pub fn q_use_sendmessage(&self) -> bool {
self.get("Q_USE_SENDMESSAGE").is_ok_and(|v| !v.is_empty())
}

pub fn q_custom_cert(&self) -> Result<String, VarError> {
self.get("Q_CUSTOM_CERT")
}

pub fn has_q_parent(&self) -> bool {
self.q_parent().is_ok()
}
}

impl Shim for Env {
Expand Down
1 change: 1 addition & 0 deletions crates/fig_request/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ workspace = true
bytes.workspace = true
cfg-if.workspace = true
cookie = "0.18.0"
fig_os_shim.workspace = true
fig_settings.workspace = true
fig_util.workspace = true
reqwest_cookie_store = "0.8.0"
Expand Down
3 changes: 2 additions & 1 deletion crates/fig_request/src/reqwest_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ pub fn create_default_root_cert_store() -> RootCertStore {
let _ = root_cert_store.add(cert);
}

let custom_cert = std::env::var("Q_CUSTOM_CERT")
let custom_cert = fig_os_shim::Env::new()
.q_custom_cert()
.ok()
.or_else(|| fig_settings::state::get_string("Q_CUSTOM_CERT").ok().flatten());

Expand Down
2 changes: 1 addition & 1 deletion crates/fig_util/src/directories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ pub fn remote_socket_path() -> Result<PathBuf> {
// Normal implementation for non-test code
// TODO(grant): This is only enabled on Linux for now to prevent public dist
if is_remote() && !in_cloudshell() && cfg!(target_os = "linux") {
if let Some(parent_socket) = std::env::var_os(Q_PARENT) {
if let Some(parent_socket) = fig_os_shim::Env::new().get_os(Q_PARENT) {
Ok(PathBuf::from(parent_socket))
} else {
Err(DirectoryError::QParentNotSet)
Expand Down
10 changes: 4 additions & 6 deletions crates/fig_util/src/system_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use sha2::{
};

use crate::Error;
use crate::env_var::Q_PARENT;
use crate::manifest::is_minimal;

/// The support level for different platforms
Expand Down Expand Up @@ -266,13 +265,13 @@ pub fn in_wsl() -> bool {
/// Is the calling binary running on a remote instance
pub fn is_remote() -> bool {
// TODO(chay): Add detection for inside docker container
in_ssh() || in_cloudshell() || in_wsl() || std::env::var_os("Q_FAKE_IS_REMOTE").is_some()
in_ssh() || in_cloudshell() || in_wsl() || fig_os_shim::Env::new().q_fake_is_remote()
}

/// Determines if we have an IPC path to a Desktop app from a remote environment
pub fn has_parent() -> bool {
static HAS_PARENT: OnceLock<bool> = OnceLock::new();
*HAS_PARENT.get_or_init(|| std::env::var_os(Q_PARENT).is_some())
*HAS_PARENT.get_or_init(|| fig_os_shim::Env::new().has_q_parent())
}

/// This true if the env var `AWS_EXECUTION_ENV=CloudShell`
Expand All @@ -283,13 +282,12 @@ pub fn in_cloudshell() -> bool {

pub fn in_codespaces() -> bool {
static IN_CODESPACES: OnceLock<bool> = OnceLock::new();
*IN_CODESPACES
.get_or_init(|| std::env::var_os("CODESPACES").is_some() || std::env::var_os("Q_CODESPACES").is_some())
*IN_CODESPACES.get_or_init(|| fig_os_shim::Env::new().in_codespaces())
}

pub fn in_ci() -> bool {
static IN_CI: OnceLock<bool> = OnceLock::new();
*IN_CI.get_or_init(|| std::env::var_os("CI").is_some() || std::env::var_os("Q_CI").is_some())
*IN_CI.get_or_init(|| fig_os_shim::Env::new().in_ci())
}

#[cfg(target_os = "macos")]
Expand Down
8 changes: 5 additions & 3 deletions crates/figterm/src/inline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,21 @@ static INLINE_ENABLED: Mutex<bool> = Mutex::const_new(true);
static LAST_RECEIVED: Mutex<Option<SystemTime>> = Mutex::const_new(None);

static CACHE_ENABLED: LazyLock<bool> =
LazyLock::new(|| std::env::var_os("Q_INLINE_SHELL_COMPLETION_CACHE_DISABLE").is_none());
LazyLock::new(|| fig_os_shim::Env::new().q_inline_shell_completion_cache_enabled());
static COMPLETION_CACHE: LazyLock<Mutex<CompletionCache>> = LazyLock::new(|| Mutex::new(CompletionCache::new()));

static TELEMETRY_QUEUE: Mutex<TelemetryQueue> = Mutex::const_new(TelemetryQueue::new());

static HISTORY_COUNT: LazyLock<usize> = LazyLock::new(|| {
std::env::var("Q_INLINE_SHELL_COMPLETION_HISTORY_COUNT")
fig_os_shim::Env::new()
.q_inline_shell_completion_history_count()
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(HISTORY_COUNT_DEFAULT)
});
static DEBOUNCE_DURATION: LazyLock<Duration> = LazyLock::new(|| {
std::env::var("Q_INLINE_SHELL_COMPLETION_DEBOUNCE_MS")
fig_os_shim::Env::new()
.q_inline_shell_completion_debounce_ms()
.ok()
.and_then(|s| s.parse().ok())
.map_or(DEBOUNCE_DURATION_DEFAULT, Duration::from_millis)
Expand Down
3 changes: 1 addition & 2 deletions crates/figterm/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ use fig_settings::state;
use fig_util::consts::CLI_BINARY_NAME;
use fig_util::env_var::{
Q_LOG_LEVEL,
Q_PARENT,
Q_SHELL,
Q_TERM,
QTERM_SESSION_ID,
Expand Down Expand Up @@ -491,7 +490,7 @@ fn figterm_main(command: Option<&[String]>) -> Result<()> {
std::env::set_var(QTERM_SESSION_ID, &session_id);
}

let parent_id = std::env::var(Q_PARENT).ok();
let parent_id = fig_os_shim::Env::new().q_parent().ok();

let mut terminal = SystemTerminal::new_from_stdio()?;
let screen_size = terminal.get_screen_size()?;
Expand Down
2 changes: 1 addition & 1 deletion crates/figterm/tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use predicates::prelude::*;

#[test]
fn version_flag_has_status_code_zero() {
let mut cmd = Command::cargo_bin("figterm").unwrap();
let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("figterm"));
cmd.arg("--version");

cmd.assert()
Expand Down
3 changes: 1 addition & 2 deletions crates/q_cli/src/cli/doctor/checks/sshd_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use async_trait::async_trait;
use eyre::Context;
use fig_auth::is_amzn_user;
use fig_util::CLI_BINARY_NAME;
use fig_util::env_var::Q_PARENT;
use fig_util::url::AUTOCOMPLETE_SSH_WIKI;
use owo_colors::OwoColorize;
use regex::Regex;
Expand Down Expand Up @@ -55,7 +54,7 @@ impl DoctorCheck<()> for SshdConfigCheck {

let sshd_config = match std::fs::read_to_string(sshd_config_path).context("Could not read sshd_config") {
Ok(config) => config,
Err(_err) if std::env::var_os(Q_PARENT).is_some() => {
Err(_err) if fig_os_shim::Env::new().q_parent().is_ok() => {
// We will assume amzn users have this configured correctly and warn other users.
if is_amzn_user().await.unwrap_or_default() {
return Ok(());
Expand Down
Loading
Loading