diff --git a/codex-rs/login/src/api_provision.rs b/codex-rs/login/src/create_api_key.rs similarity index 86% rename from codex-rs/login/src/api_provision.rs rename to codex-rs/login/src/create_api_key.rs index 50a3c775db..1b30ddb457 100644 --- a/codex-rs/login/src/api_provision.rs +++ b/codex-rs/login/src/create_api_key.rs @@ -1,4 +1,4 @@ -//! Browser-based OAuth flow for provisioning OpenAI project API keys. +//! Browser-based OAuth flow for creating OpenAI project API keys. use std::time::Duration; @@ -20,7 +20,7 @@ const CALLBACK_PORT: u16 = 0; const CALLBACK_PATH: &str = "/auth/callback"; const SCOPE: &str = "openid email profile offline_access"; const APP: &str = "api"; -const USER_AGENT: &str = "Codex-API-Provision/1.0"; +const USER_AGENT: &str = "Codex-Create-API-Key/1.0"; const PROJECT_API_KEY_NAME: &str = "Codex CLI"; const PROJECT_POLL_INTERVAL_SECONDS: u64 = 10; const PROJECT_POLL_TIMEOUT_SECONDS: u64 = 60; @@ -28,7 +28,7 @@ const OAUTH_TIMEOUT_SECONDS: u64 = 15 * 60; const HTTP_TIMEOUT_SECONDS: u64 = 30; #[derive(Debug, Clone, PartialEq, Eq)] -struct ApiProvisionOptions { +struct CreateApiKeyOptions { issuer: String, client_id: String, audience: String, @@ -41,15 +41,15 @@ struct ApiProvisionOptions { project_poll_timeout_seconds: u64, } -pub struct PendingApiProvisioning { +pub struct PendingCreateApiKey { client: Client, - options: ApiProvisionOptions, + options: CreateApiKeyOptions, redirect_uri: String, code_verifier: String, callback_server: AuthorizationCodeServer, } -impl PendingApiProvisioning { +impl PendingCreateApiKey { pub fn auth_url(&self) -> &str { &self.callback_server.auth_url } @@ -62,13 +62,13 @@ impl PendingApiProvisioning { self.callback_server.open_browser() } - pub async fn finish(self) -> Result { + pub async fn finish(self) -> Result { let code = self .callback_server .wait_for_code(Duration::from_secs(OAUTH_TIMEOUT_SECONDS)) .await - .map_err(|err| ApiProvisionError::message(err.to_string()))?; - provision_from_authorization_code( + .map_err(|err| CreateApiKeyError::message(err.to_string()))?; + create_api_key_from_authorization_code( &self.client, &self.options, &self.redirect_uri, @@ -80,7 +80,7 @@ impl PendingApiProvisioning { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct ProvisionedApiKey { +pub struct CreatedApiKey { pub organization_id: String, pub organization_title: Option, pub default_project_id: String, @@ -88,8 +88,8 @@ pub struct ProvisionedApiKey { pub project_api_key: String, } -pub fn start_api_provisioning() -> Result { - let options = ApiProvisionOptions { +pub fn start_create_api_key() -> Result { + let options = CreateApiKeyOptions { issuer: AUTH_ISSUER.to_string(), client_id: PLATFORM_HYDRA_CLIENT_ID.to_string(), audience: PLATFORM_AUDIENCE.to_string(), @@ -111,10 +111,10 @@ pub fn start_api_provisioning() -> Result Result Result { +) -> Result { let mut url = Url::parse(&format!( "{}/oauth/authorize", options.issuer.trim_end_matches('/') )) - .map_err(|err| ApiProvisionError::message(format!("invalid issuer URL: {err}")))?; + .map_err(|err| CreateApiKeyError::message(format!("invalid issuer URL: {err}")))?; url.query_pairs_mut() .append_pair("audience", &options.audience) .append_pair("client_id", &options.client_id) @@ -146,20 +146,20 @@ fn build_authorize_url( Ok(url.to_string()) } -fn build_http_client() -> Result { +fn build_http_client() -> Result { build_reqwest_client_with_custom_ca( reqwest::Client::builder().timeout(Duration::from_secs(HTTP_TIMEOUT_SECONDS)), ) - .map_err(|err| ApiProvisionError::message(format!("failed to build HTTP client: {err}"))) + .map_err(|err| CreateApiKeyError::message(format!("failed to build HTTP client: {err}"))) } -async fn provision_from_authorization_code( +async fn create_api_key_from_authorization_code( client: &Client, - options: &ApiProvisionOptions, + options: &CreateApiKeyOptions, redirect_uri: &str, code_verifier: &str, code: &str, -) -> Result { +) -> Result { let tokens = exchange_authorization_code_for_tokens( client, &options.issuer, @@ -195,7 +195,7 @@ async fn provision_from_authorization_code( .key .sensitive_id; - Ok(ProvisionedApiKey { + Ok(CreatedApiKey { organization_id: target.organization_id, organization_title: target.organization_title, default_project_id: target.project_id, @@ -211,7 +211,7 @@ async fn exchange_authorization_code_for_tokens( redirect_uri: &str, code_verifier: &str, code: &str, -) -> Result { +) -> Result { let url = format!("{}/oauth/token", issuer.trim_end_matches('/')); execute_json( client @@ -241,7 +241,7 @@ async fn onboarding_login( api_base: &str, app: &str, access_token: &str, -) -> Result { +) -> Result { let url = format!( "{}/dashboard/onboarding/login", api_base.trim_end_matches('/') @@ -263,7 +263,7 @@ async fn list_organizations( client: &Client, api_base: &str, session_key: &str, -) -> Result, ApiProvisionError> { +) -> Result, CreateApiKeyError> { let url = format!("{}/v1/organizations", api_base.trim_end_matches('/')); let response: DataList = execute_json( client @@ -283,7 +283,7 @@ async fn list_projects( api_base: &str, session_key: &str, organization_id: &str, -) -> Result, ApiProvisionError> { +) -> Result, CreateApiKeyError> { let url = format!( "{}/dashboard/organizations/{}/projects?detail=basic&limit=100", api_base.trim_end_matches('/'), @@ -309,7 +309,7 @@ async fn wait_for_default_project( session_key: &str, poll_interval_seconds: u64, timeout_seconds: u64, -) -> Result { +) -> Result { let deadline = std::time::Instant::now() + Duration::from_secs(timeout_seconds); loop { let organizations = list_organizations(client, api_base, session_key).await?; @@ -333,7 +333,7 @@ async fn wait_for_default_project( }; if std::time::Instant::now() >= deadline { - return Err(ApiProvisionError::message(format!( + return Err(CreateApiKeyError::message(format!( "Timed out waiting for an organization and default project. Last observed state: {last_state}" ))); } @@ -367,7 +367,7 @@ async fn create_project_api_key( session_key: &str, target: &ProvisioningTarget, key_name: &str, -) -> Result { +) -> Result { let url = format!( "{}/dashboard/organizations/{}/projects/{}/api_keys", api_base.trim_end_matches('/'), @@ -394,26 +394,26 @@ async fn execute_json( request: reqwest::RequestBuilder, method: &str, url: &str, -) -> Result +) -> Result where T: for<'de> Deserialize<'de>, { let response = request .send() .await - .map_err(|err| ApiProvisionError::message(format!("Network error calling {url}: {err}")))?; + .map_err(|err| CreateApiKeyError::message(format!("Network error calling {url}: {err}")))?; let status = response.status(); let body = response.bytes().await.map_err(|err| { - ApiProvisionError::message(format!("Failed reading response from {url}: {err}")) + CreateApiKeyError::message(format!("Failed reading response from {url}: {err}")) })?; if !status.is_success() { - return Err(ApiProvisionError::api( + return Err(CreateApiKeyError::api( format!("{method} {url} failed with HTTP {status}"), String::from_utf8_lossy(&body).into_owned(), )); } serde_json::from_slice(&body) - .map_err(|err| ApiProvisionError::message(format!("{url} returned invalid JSON: {err}"))) + .map_err(|err| CreateApiKeyError::message(format!("{url} returned invalid JSON: {err}"))) } #[derive(Debug, Deserialize)] @@ -472,21 +472,21 @@ struct ProvisioningTarget { } #[derive(Debug, Deserialize)] -struct CreateApiKeyResponse { - key: CreatedApiKey, +struct CreateProjectApiKeyResponse { + key: CreatedProjectApiKey, } #[derive(Debug, Deserialize)] -struct CreatedApiKey { +struct CreatedProjectApiKey { sensitive_id: String, } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct ApiProvisionError { +pub struct CreateApiKeyError { message: String, } -impl ApiProvisionError { +impl CreateApiKeyError { fn message(message: String) -> Self { Self { message } } @@ -498,14 +498,14 @@ impl ApiProvisionError { } } -impl std::fmt::Display for ApiProvisionError { +impl std::fmt::Display for CreateApiKeyError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(&self.message) } } -impl std::error::Error for ApiProvisionError {} +impl std::error::Error for CreateApiKeyError {} #[cfg(test)] -#[path = "api_provision_tests.rs"] +#[path = "create_api_key_tests.rs"] mod tests; diff --git a/codex-rs/login/src/api_provision_tests.rs b/codex-rs/login/src/create_api_key_tests.rs similarity index 96% rename from codex-rs/login/src/api_provision_tests.rs rename to codex-rs/login/src/create_api_key_tests.rs index 9d42d83065..a1f2d666ca 100644 --- a/codex-rs/login/src/api_provision_tests.rs +++ b/codex-rs/login/src/create_api_key_tests.rs @@ -59,7 +59,7 @@ fn find_default_project_returns_initial_project() { } #[tokio::test] -async fn provision_from_authorization_code_provisions_api_key() { +async fn create_api_key_from_authorization_code_creates_api_key() { let server = MockServer::start().await; Mock::given(method("POST")) .and(path("/oauth/token")) @@ -129,7 +129,7 @@ async fn provision_from_authorization_code_provisions_api_key() { .mount(&server) .await; - let options = ApiProvisionOptions { + let options = CreateApiKeyOptions { issuer: server.uri(), client_id: "client-123".to_string(), audience: PLATFORM_AUDIENCE.to_string(), @@ -143,7 +143,7 @@ async fn provision_from_authorization_code_provisions_api_key() { }; let client = build_http_client().expect("client"); - let output = provision_from_authorization_code( + let output = create_api_key_from_authorization_code( &client, &options, "http://localhost:5000/auth/callback", @@ -155,7 +155,7 @@ async fn provision_from_authorization_code_provisions_api_key() { assert_eq!( output, - ProvisionedApiKey { + CreatedApiKey { organization_id: "org-default".to_string(), organization_title: Some("Default Org".to_string()), default_project_id: "proj-default".to_string(), diff --git a/codex-rs/login/src/lib.rs b/codex-rs/login/src/lib.rs index 4900dcd0f4..c25d138623 100644 --- a/codex-rs/login/src/lib.rs +++ b/codex-rs/login/src/lib.rs @@ -1,7 +1,7 @@ pub mod auth; pub mod token_data; -mod api_provision; +mod create_api_key; mod device_code_auth; mod oauth_callback_server; mod pkce; @@ -17,10 +17,10 @@ pub use server::LoginServer; pub use server::ServerOptions; pub use server::run_login_server; -pub use api_provision::ApiProvisionError; -pub use api_provision::PendingApiProvisioning; -pub use api_provision::ProvisionedApiKey; -pub use api_provision::start_api_provisioning; +pub use create_api_key::CreateApiKeyError; +pub use create_api_key::CreatedApiKey; +pub use create_api_key::PendingCreateApiKey; +pub use create_api_key::start_create_api_key; pub use auth::AuthConfig; pub use auth::AuthCredentialsStoreMode; pub use auth::AuthDotJson; diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index e5c2fb2f31..f1734ddf6f 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -291,7 +291,7 @@ use crate::status_indicator_widget::STATUS_DETAILS_DEFAULT_MAX_LINES; use crate::status_indicator_widget::StatusDetailsCapitalization; use crate::text_formatting::truncate_text; use crate::tui::FrameRequester; -mod api_provision; +mod create_api_key; mod dotenv_api_key; mod interrupts; use self::interrupts::InterruptManager; @@ -4735,8 +4735,8 @@ impl ChatWidget { tx.send(AppEvent::DiffResult(text)); }); } - SlashCommand::ApiProvision => { - self.start_api_provision(); + SlashCommand::CreateApiKey => { + self.start_create_api_key(); } SlashCommand::Copy => { let Some(text) = self.last_copyable_output.as_deref() else { diff --git a/codex-rs/tui/src/chatwidget/api_provision.rs b/codex-rs/tui/src/chatwidget/create_api_key.rs similarity index 87% rename from codex-rs/tui/src/chatwidget/api_provision.rs rename to codex-rs/tui/src/chatwidget/create_api_key.rs index 871908f76a..a042774b70 100644 --- a/codex-rs/tui/src/chatwidget/api_provision.rs +++ b/codex-rs/tui/src/chatwidget/create_api_key.rs @@ -6,10 +6,10 @@ use codex_core::AuthManager; use codex_core::auth::AuthCredentialsStoreMode; use codex_core::auth::login_with_api_key; use codex_core::auth::read_openai_api_key_from_env; +use codex_login::CreatedApiKey; use codex_login::OPENAI_API_KEY_ENV_VAR; -use codex_login::PendingApiProvisioning; -use codex_login::ProvisionedApiKey; -use codex_login::start_api_provisioning; +use codex_login::PendingCreateApiKey; +use codex_login::start_create_api_key as start_create_api_key_flow; use codex_protocol::config_types::ForcedLoginMethod; use ratatui::style::Stylize; use ratatui::text::Line; @@ -23,8 +23,8 @@ use crate::history_cell; use crate::history_cell::PlainHistoryCell; impl ChatWidget { - pub(crate) fn start_api_provision(&mut self) { - match start_api_provision( + pub(crate) fn start_create_api_key(&mut self) { + match start_create_api_key_command( self.app_event_tx.clone(), self.auth_manager.clone(), self.config.codex_home.clone(), @@ -42,7 +42,7 @@ impl ChatWidget { } } -fn start_api_provision( +fn start_create_api_key_command( app_event_tx: AppEventSender, auth_manager: Arc, codex_home: PathBuf, @@ -61,8 +61,8 @@ fn start_api_provision( ) })?; - let session = start_api_provisioning() - .map_err(|err| format!("Failed to start API provisioning: {err}"))?; + let session = start_create_api_key_flow() + .map_err(|err| format!("Failed to start API key creation: {err}"))?; let browser_opened = session.open_browser(); let start_message = continue_in_browser_message( session.auth_url(), @@ -91,10 +91,10 @@ fn start_api_provision( fn existing_shell_api_key_message() -> PlainHistoryCell { history_cell::new_info_event( format!( - "{OPENAI_API_KEY_ENV_VAR} is already set in this Codex session; skipping API provisioning." + "{OPENAI_API_KEY_ENV_VAR} is already set in this Codex session; skipping API key creation." ), Some(format!( - "This Codex session already inherited {OPENAI_API_KEY_ENV_VAR} from its shell environment. Unset it and run /api-provision again if you want Codex to provision and save a different key." + "This Codex session already inherited {OPENAI_API_KEY_ENV_VAR} from its shell environment. Unset it and run /create-api-key again if you want Codex to create and save a different key." )), ) } @@ -108,7 +108,7 @@ fn continue_in_browser_message( let mut lines = vec![ vec![ "• ".dim(), - "Finish API provisioning via your browser.".into(), + "Finish API key creation via your browser.".into(), ] .into(), "".into(), @@ -122,7 +122,7 @@ fn continue_in_browser_message( ); } else { lines.push( - " Codex couldn't auto-open your browser, but the provisioning flow is still waiting." + " Codex couldn't auto-open your browser, but the API key creation flow is still waiting." .dark_gray() .into(), ); @@ -156,7 +156,7 @@ fn continue_in_browser_message( } async fn complete_command( - session: PendingApiProvisioning, + session: PendingCreateApiKey, dotenv_path: PathBuf, codex_home: PathBuf, forced_login_method: Option, @@ -165,13 +165,13 @@ async fn complete_command( let provisioned = match session.finish().await { Ok(provisioned) => provisioned, Err(err) => { - return history_cell::new_error_event(format!("API provisioning failed: {err}")); + return history_cell::new_error_event(format!("API key creation failed: {err}")); } }; if let Err(err) = upsert_dotenv_api_key(&dotenv_path, &provisioned.project_api_key) { return history_cell::new_error_event(format!( - "Provisioning completed, but Codex could not update {}: {err}", + "API key creation completed, but Codex could not update {}: {err}", dotenv_path.display() )); } @@ -210,7 +210,7 @@ fn live_apply_api_key( } fn success_cell( - provisioned: &ProvisionedApiKey, + provisioned: &CreatedApiKey, dotenv_path: &Path, live_apply_outcome: LiveApplyOutcome, ) -> PlainHistoryCell { @@ -224,7 +224,7 @@ fn success_cell( .unwrap_or_else(|| provisioned.default_project_id.clone()); let hint = match live_apply_outcome { LiveApplyOutcome::Applied => Some( - "Updated this session to use the newly provisioned API key without touching auth.json." + "Updated this session to use the newly created API key without touching auth.json." .to_string(), ), LiveApplyOutcome::Skipped(reason) => Some(reason), @@ -236,7 +236,7 @@ fn success_cell( history_cell::new_info_event( format!( - "Provisioned an API key for {organization} / {project} and saved {OPENAI_API_KEY_ENV_VAR} to {}.", + "Created an API key for {organization} / {project} and saved {OPENAI_API_KEY_ENV_VAR} to {}.", dotenv_path.display() ), hint, @@ -258,7 +258,7 @@ mod tests { #[test] fn success_cell_snapshot() { let cell = success_cell( - &ProvisionedApiKey { + &CreatedApiKey { organization_id: "org-default".to_string(), organization_title: Some("Default Org".to_string()), default_project_id: "proj-default".to_string(), @@ -275,7 +275,7 @@ mod tests { #[test] fn success_cell_snapshot_when_live_apply_is_skipped() { let cell = success_cell( - &ProvisionedApiKey { + &CreatedApiKey { organization_id: "org-default".to_string(), organization_title: None, default_project_id: "proj-default".to_string(), @@ -310,7 +310,7 @@ mod tests { assert_eq!( render_cell(&cell), - "• OPENAI_API_KEY is already set in this Codex session; skipping API provisioning. This Codex session already inherited OPENAI_API_KEY from its shell environment. Unset it and run /api-provision again if you want Codex to provision and save a different key." + "• OPENAI_API_KEY is already set in this Codex session; skipping API key creation. This Codex session already inherited OPENAI_API_KEY from its shell environment. Unset it and run /create-api-key again if you want Codex to create and save a different key." ); } diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__api_provision__tests__success_cell_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__api_provision__tests__success_cell_snapshot.snap deleted file mode 100644 index ec41ee20d1..0000000000 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__api_provision__tests__success_cell_snapshot.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: tui/src/chatwidget/api_provision.rs -expression: render_cell(&cell) ---- -• Provisioned an API key for Default Org / Default Project and saved OPENAI_API_KEY to /tmp/workspace/.env.local. Updated this session to use the newly provisioned API key without touching auth.json. diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__api_provision__tests__success_cell_snapshot_when_live_apply_is_skipped.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__api_provision__tests__success_cell_snapshot_when_live_apply_is_skipped.snap deleted file mode 100644 index bd4f40ed6d..0000000000 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__api_provision__tests__success_cell_snapshot_when_live_apply_is_skipped.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: tui/src/chatwidget/api_provision.rs -expression: render_cell(&cell) ---- -• Provisioned an API key for org-default / proj-default and saved OPENAI_API_KEY to /tmp/workspace/.env.local. Saved OPENAI_API_KEY to .env.local, but left this session unchanged because ChatGPT login is required here. diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__api_provision__tests__continue_in_browser_message_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__create_api_key__tests__continue_in_browser_message_snapshot.snap similarity index 65% rename from codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__api_provision__tests__continue_in_browser_message_snapshot.snap rename to codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__create_api_key__tests__continue_in_browser_message_snapshot.snap index 1ab919ec98..76cafb95c0 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__api_provision__tests__continue_in_browser_message_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__create_api_key__tests__continue_in_browser_message_snapshot.snap @@ -1,10 +1,10 @@ --- -source: tui/src/chatwidget/api_provision.rs +source: tui/src/chatwidget/create_api_key.rs expression: render_cell(&cell) --- -• Finish API provisioning via your browser. +• Finish API key creation via your browser. - Codex couldn't auto-open your browser, but the provisioning flow is still waiting. + Codex couldn't auto-open your browser, but the API key creation flow is still waiting. Open the following link to authenticate: diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__create_api_key__tests__success_cell_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__create_api_key__tests__success_cell_snapshot.snap new file mode 100644 index 0000000000..6e50971277 --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__create_api_key__tests__success_cell_snapshot.snap @@ -0,0 +1,5 @@ +--- +source: tui/src/chatwidget/create_api_key.rs +expression: render_cell(&cell) +--- +• Created an API key for Default Org / Default Project and saved OPENAI_API_KEY to /tmp/workspace/.env.local. Updated this session to use the newly created API key without touching auth.json. diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__create_api_key__tests__success_cell_snapshot_when_live_apply_is_skipped.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__create_api_key__tests__success_cell_snapshot_when_live_apply_is_skipped.snap new file mode 100644 index 0000000000..6acb8e1fb6 --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__create_api_key__tests__success_cell_snapshot_when_live_apply_is_skipped.snap @@ -0,0 +1,5 @@ +--- +source: tui/src/chatwidget/create_api_key.rs +expression: render_cell(&cell) +--- +• Created an API key for org-default / proj-default and saved OPENAI_API_KEY to /tmp/workspace/.env.local. Saved OPENAI_API_KEY to .env.local, but left this session unchanged because ChatGPT login is required here. diff --git a/codex-rs/tui/src/slash_command.rs b/codex-rs/tui/src/slash_command.rs index f90e06caf0..5d5d3f82f6 100644 --- a/codex-rs/tui/src/slash_command.rs +++ b/codex-rs/tui/src/slash_command.rs @@ -34,7 +34,7 @@ pub enum SlashCommand { Agent, // Undo, Diff, - ApiProvision, + CreateApiKey, Copy, Mention, Status, @@ -83,7 +83,7 @@ impl SlashCommand { // SlashCommand::Undo => "ask Codex to undo a turn", SlashCommand::Quit | SlashCommand::Exit => "exit Codex", SlashCommand::Diff => "show git diff (including untracked files)", - SlashCommand::ApiProvision => "provision an API key and save it to .env.local", + SlashCommand::CreateApiKey => "create an API key and save it to .env.local", SlashCommand::Copy => "copy the latest Codex output to your clipboard", SlashCommand::Mention => "mention a file", SlashCommand::Skills => "use skills to improve how Codex performs specific tasks", @@ -157,7 +157,7 @@ impl SlashCommand { | SlashCommand::Experimental | SlashCommand::Review | SlashCommand::Plan - | SlashCommand::ApiProvision + | SlashCommand::CreateApiKey | SlashCommand::Clear | SlashCommand::Logout | SlashCommand::MemoryDrop @@ -225,13 +225,13 @@ mod tests { } #[test] - fn api_provision_command_metadata() { + fn create_api_key_command_metadata() { assert_eq!( - SlashCommand::from_str("api-provision"), - Ok(SlashCommand::ApiProvision) + SlashCommand::from_str("create-api-key"), + Ok(SlashCommand::CreateApiKey) ); - assert_eq!(SlashCommand::ApiProvision.command(), "api-provision"); - assert!(!SlashCommand::ApiProvision.supports_inline_args()); - assert!(!SlashCommand::ApiProvision.available_during_task()); + assert_eq!(SlashCommand::CreateApiKey.command(), "create-api-key"); + assert!(!SlashCommand::CreateApiKey.supports_inline_args()); + assert!(!SlashCommand::CreateApiKey.available_during_task()); } }