1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! The command-line program a Roder runtime is embedded in.
//!
//! Roder's own CLI is `roder`, but other programs embed the runtime and ship
//! their own command line: a hint such as "run `roder auth login codex`" means
//! nothing to their users. An embedding program sets its identity once at
//! startup with [`set_cli_identity`]; every user-facing sign-in hint and the
//! provider sign-in token folder (Codex, SuperGrok, Kimi Code) then follow
//! it. Until one is set, Roder's defaults apply; reading the identity never
//! fixes it, so setting it later still takes effect.
use std::path::PathBuf;
use std::sync::{LazyLock, OnceLock};
/// The `{provider}` placeholder in [`CliIdentity::auth_login`].
pub const PROVIDER_PLACEHOLDER: &str = "{provider}";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CliIdentity {
/// The program name users type, such as `roder`.
pub name: String,
/// The command that signs in to a provider, with `{provider}` where the
/// provider id goes, such as `roder auth login {provider}`.
pub auth_login: String,
/// The folder provider sign-in tokens are kept in, used as given.
/// `None` keeps them in `auth/` under Roder's data folder
/// (`RODER_DATA_DIR`, else `RODER_CONFIG_DIR`, else `~/.roder`).
pub auth_dir: Option<PathBuf>,
}
impl CliIdentity {
/// The command a user runs to sign in to `provider` (`codex`, `supergrok`, ...).
pub fn auth_login_command(&self, provider: &str) -> String {
self.auth_login.replace(PROVIDER_PLACEHOLDER, provider)
}
}
impl Default for CliIdentity {
fn default() -> Self {
Self {
name: "roder".to_string(),
auth_login: format!("roder auth login {PROVIDER_PLACEHOLDER}"),
auth_dir: None,
}
}
}
static IDENTITY: OnceLock<CliIdentity> = OnceLock::new();
static RODER: LazyLock<CliIdentity> = LazyLock::new(CliIdentity::default);
/// Name the program embedding Roder, before any provider or sign-in runs.
/// The first identity set wins; a later one is returned as the error.
pub fn set_cli_identity(identity: CliIdentity) -> Result<(), CliIdentity> {
IDENTITY.set(identity)
}
/// The embedding program's identity, or Roder's own while none is set.
pub fn cli_identity() -> &'static CliIdentity {
IDENTITY.get().unwrap_or(&RODER)
}
/// The folder provider sign-in tokens go in: the embedding program's
/// `auth_dir`, else `default` (a token store's `auth/` under Roder's data
/// folder).
pub fn auth_dir_or(default: PathBuf) -> PathBuf {
cli_identity().auth_dir.clone().unwrap_or(default)
}
/// The command a user of this program runs to sign in to `provider`.
pub fn auth_login_command(provider: &str) -> String {
cli_identity().auth_login_command(provider)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_sign_in_command_names_the_provider() {
assert_eq!(
CliIdentity::default().auth_login_command("codex"),
"roder auth login codex"
);
let embedded = CliIdentity {
name: "com".to_string(),
auth_login: "com agent login {provider}".to_string(),
auth_dir: None,
};
assert_eq!(
embedded.auth_login_command("codex"),
"com agent login codex"
);
}
#[test]
fn reading_the_identity_leaves_it_settable() {
// The only test in this binary that sets the process-wide identity.
assert_eq!(cli_identity().name, "roder");
assert_eq!(
auth_dir_or(PathBuf::from("/default")),
PathBuf::from("/default")
);
let embedded = CliIdentity {
name: "com".to_string(),
auth_login: "com agent login {provider}".to_string(),
auth_dir: Some(PathBuf::from("/tokens")),
};
set_cli_identity(embedded.clone()).unwrap();
assert_eq!(cli_identity(), &embedded);
assert_eq!(auth_login_command("codex"), "com agent login codex");
assert_eq!(
auth_dir_or(PathBuf::from("/default")),
PathBuf::from("/tokens")
);
assert!(set_cli_identity(CliIdentity::default()).is_err());
}
}