@@ -162,6 +162,10 @@ pub struct Config {
162162 /// Toggle for the bespoke Codex status line rendering.
163163 pub tui_custom_statusline : bool ,
164164
165+ /// 88code API key for usage tracking in status line.
166+ /// Sourced from config file or CODE88_API_KEY environment variable.
167+ pub tui_code88_api_key : Option < String > ,
168+
165169 /// Enable ASCII animations and shimmer effects in the TUI.
166170 pub animations : bool ,
167171
@@ -1112,6 +1116,9 @@ impl Config {
11121116
11131117 let forced_login_method = cfg. forced_login_method ;
11141118
1119+ // Detect 88code API key before codex_home is moved
1120+ let tui_code88_api_key = Self :: detect_88code_api_key ( & codex_home) ;
1121+
11151122 let model = model
11161123 . or ( config_profile. model )
11171124 . or ( cfg. model )
@@ -1268,6 +1275,7 @@ impl Config {
12681275 . as_ref ( )
12691276 . map ( |t| t. custom_statusline )
12701277 . unwrap_or_else ( || Tui :: default ( ) . custom_statusline ) ,
1278+ tui_code88_api_key,
12711279 otel : {
12721280 let t: OtelConfigToml = cfg. otel . unwrap_or_default ( ) ;
12731281 let log_user_prompt = t. log_user_prompt . unwrap_or ( false ) ;
@@ -1300,6 +1308,45 @@ impl Config {
13001308 None
13011309 }
13021310
1311+ /// Detect 88code API key from environment variable or auth.json.
1312+ /// Priority: OPENAI_API_KEY env > key88 env > auth.json
1313+ /// The key is identified by the `88_` prefix.
1314+ fn detect_88code_api_key ( codex_home : & Path ) -> Option < String > {
1315+ // First, check OPENAI_API_KEY environment variable (highest priority)
1316+ if let Ok ( key) = std:: env:: var ( "OPENAI_API_KEY" )
1317+ && key. starts_with ( "88_" )
1318+ {
1319+ return Some ( key) ;
1320+ }
1321+
1322+ // Second, check key88 environment variable (common 88code config)
1323+ if let Ok ( key) = std:: env:: var ( "key88" )
1324+ && key. starts_with ( "88_" )
1325+ {
1326+ return Some ( key) ;
1327+ }
1328+
1329+ // Fallback to auth.json
1330+ let auth_file = codex_home. join ( "auth.json" ) ;
1331+ let contents = std:: fs:: read_to_string ( & auth_file) . ok ( ) ?;
1332+
1333+ #[ derive( serde:: Deserialize ) ]
1334+ struct AuthJson {
1335+ #[ serde( rename = "OPENAI_API_KEY" ) ]
1336+ openai_api_key : Option < String > ,
1337+ }
1338+
1339+ let auth: AuthJson = serde_json:: from_str ( & contents) . ok ( ) ?;
1340+ let key = auth. openai_api_key ?;
1341+
1342+ // Only return the key if it starts with "88_" prefix
1343+ if key. starts_with ( "88_" ) {
1344+ Some ( key)
1345+ } else {
1346+ None
1347+ }
1348+ }
1349+
13031350 fn load_override_from_file (
13041351 path : Option < & PathBuf > ,
13051352 cwd : & Path ,
@@ -3020,6 +3067,7 @@ model_verbosity = "high"
30203067 tui_notifications: Default :: default ( ) ,
30213068 animations: true ,
30223069 tui_custom_statusline: true ,
3070+ tui_code88_api_key: None ,
30233071 otel: OtelConfig :: default ( ) ,
30243072 } ,
30253073 o3_profile_config
@@ -3094,6 +3142,7 @@ model_verbosity = "high"
30943142 tui_notifications : Default :: default ( ) ,
30953143 animations : true ,
30963144 tui_custom_statusline : true ,
3145+ tui_code88_api_key : None ,
30973146 otel : OtelConfig :: default ( ) ,
30983147 } ;
30993148
@@ -3183,6 +3232,7 @@ model_verbosity = "high"
31833232 tui_notifications : Default :: default ( ) ,
31843233 animations : true ,
31853234 tui_custom_statusline : true ,
3235+ tui_code88_api_key : None ,
31863236 otel : OtelConfig :: default ( ) ,
31873237 } ;
31883238
@@ -3258,6 +3308,7 @@ model_verbosity = "high"
32583308 tui_notifications : Default :: default ( ) ,
32593309 animations : true ,
32603310 tui_custom_statusline : true ,
3311+ tui_code88_api_key : None ,
32613312 otel : OtelConfig :: default ( ) ,
32623313 } ;
32633314
0 commit comments