@@ -2295,7 +2295,13 @@ fn import_account_struct(account: CodexAccount) -> Result<CodexAccount, String>
22952295 ) ;
22962296 }
22972297
2298- upsert_account ( account. tokens )
2298+ let imported_auth_file_plan_type =
2299+ normalize_auth_file_plan_type ( account. auth_file_plan_type . as_deref ( ) ) ;
2300+ let mut imported = upsert_account ( account. tokens ) ?;
2301+ if apply_auth_file_plan_type ( & mut imported, imported_auth_file_plan_type) {
2302+ save_account ( & imported) ?;
2303+ }
2304+ Ok ( imported)
22992305}
23002306
23012307/// 从 JSON 字符串导入账号
@@ -2468,6 +2474,53 @@ pub struct CodexFileImportFailure {
24682474 pub error : String ,
24692475}
24702476
2477+ fn normalize_auth_file_plan_type ( value : Option < & str > ) -> Option < String > {
2478+ let normalized = normalize_optional_ref ( value) ?
2479+ . to_ascii_lowercase ( )
2480+ . replace ( '_' , "-" )
2481+ . replace ( ' ' , "-" ) ;
2482+
2483+ match normalized. as_str ( ) {
2484+ "prolite" | "pro-lite" => Some ( "prolite" . to_string ( ) ) ,
2485+ "promax" | "pro-max" => Some ( "promax" . to_string ( ) ) ,
2486+ _ => None ,
2487+ }
2488+ }
2489+
2490+ fn detect_auth_file_plan_type_from_path ( path : & std:: path:: Path ) -> Option < String > {
2491+ let stem = path. file_stem ( ) ?. to_str ( ) ?;
2492+ let normalized = stem
2493+ . trim ( )
2494+ . to_ascii_lowercase ( )
2495+ . replace ( '_' , "-" )
2496+ . replace ( ' ' , "-" ) ;
2497+
2498+ if normalized. ends_with ( "-prolite" ) || normalized. ends_with ( "-pro-lite" ) {
2499+ return Some ( "prolite" . to_string ( ) ) ;
2500+ }
2501+ if normalized. ends_with ( "-promax" ) || normalized. ends_with ( "-pro-max" ) {
2502+ return Some ( "promax" . to_string ( ) ) ;
2503+ }
2504+
2505+ None
2506+ }
2507+
2508+ fn apply_auth_file_plan_type (
2509+ account : & mut CodexAccount ,
2510+ auth_file_plan_type : Option < String > ,
2511+ ) -> bool {
2512+ let Some ( normalized) = normalize_auth_file_plan_type ( auth_file_plan_type. as_deref ( ) ) else {
2513+ return false ;
2514+ } ;
2515+
2516+ if account. auth_file_plan_type . as_deref ( ) == Some ( normalized. as_str ( ) ) {
2517+ return false ;
2518+ }
2519+
2520+ account. auth_file_plan_type = Some ( normalized) ;
2521+ true
2522+ }
2523+
24712524/// 从单个 JSON 值中提取 CodexTokens
24722525fn extract_codex_tokens_from_value (
24732526 obj : & serde_json:: Value ,
@@ -2529,9 +2582,10 @@ fn extract_codex_tokens_from_value(
25292582#[ cfg( test) ]
25302583mod tests {
25312584 use super :: {
2532- build_account_storage_id, extract_codex_tokens_from_value, get_accounts_dir,
2533- get_accounts_storage_path, get_current_account, list_accounts_checked, load_account,
2534- load_account_index, read_api_provider_from_config_toml, read_quick_config_from_config_toml,
2585+ build_account_storage_id, detect_auth_file_plan_type_from_path,
2586+ extract_codex_tokens_from_value, get_accounts_dir, get_accounts_storage_path,
2587+ get_current_account, list_accounts_checked, load_account, load_account_index,
2588+ read_api_provider_from_config_toml, read_quick_config_from_config_toml,
25352589 resolve_api_provider_config, save_account, save_account_index, sync_account_from_auth_dir,
25362590 validate_api_key_credentials, write_api_provider_to_config_toml,
25372591 write_quick_config_to_config_toml, ApiProviderConfig , CodexAccountIndex ,
@@ -2737,6 +2791,22 @@ mod tests {
27372791 assert_eq ! ( account_id_hint. as_deref( ) , Some ( "acc_2" ) ) ;
27382792 }
27392793
2794+ #[ test]
2795+ fn detect_auth_file_plan_type_from_filename ( ) {
2796+ let prolite = detect_auth_file_plan_type_from_path ( std:: path:: Path :: new (
2797+ "/tmp/codex-demo@example.com-prolite.json" ,
2798+ ) ) ;
2799+ let promax = detect_auth_file_plan_type_from_path ( std:: path:: Path :: new (
2800+ "/tmp/codex-demo@example.com-pro-max.json" ,
2801+ ) ) ;
2802+ let team =
2803+ detect_auth_file_plan_type_from_path ( std:: path:: Path :: new ( "/tmp/codex-demo-team.json" ) ) ;
2804+
2805+ assert_eq ! ( prolite. as_deref( ) , Some ( "prolite" ) ) ;
2806+ assert_eq ! ( promax. as_deref( ) , Some ( "promax" ) ) ;
2807+ assert_eq ! ( team, None ) ;
2808+ }
2809+
27402810 #[ test]
27412811 fn current_account_syncs_latest_tokens_from_local_auth_json ( ) {
27422812 let _lock = TEST_ENV_LOCK . lock ( ) . unwrap_or_else ( |err| err. into_inner ( ) ) ;
@@ -3057,8 +3127,8 @@ pub fn import_from_files(file_paths: Vec<String>) -> Result<CodexFileImportResul
30573127 file_paths. len( )
30583128 ) ) ;
30593129
3060- // 收集所有候选: (CodexTokens, account_id_hint, label)
3061- let mut candidates: Vec < ( CodexTokens , Option < String > , String ) > = Vec :: new ( ) ;
3130+ // 收集所有候选: (CodexTokens, account_id_hint, label, auth_file_plan_type )
3131+ let mut candidates: Vec < ( CodexTokens , Option < String > , String , Option < String > ) > = Vec :: new ( ) ;
30623132
30633133 for file_path in & file_paths {
30643134 let path = Path :: new ( file_path) ;
@@ -3076,6 +3146,7 @@ pub fn import_from_files(file_paths: Vec<String>) -> Result<CodexFileImportResul
30763146 . and_then ( |s| s. to_str ( ) )
30773147 . unwrap_or ( "unknown" )
30783148 . to_string ( ) ;
3149+ let auth_file_plan_type = detect_auth_file_plan_type_from_path ( path) ;
30793150
30803151 let parsed: serde_json:: Value = match serde_json:: from_str ( & content) {
30813152 Ok ( v) => v,
@@ -3088,7 +3159,7 @@ pub fn import_from_files(file_paths: Vec<String>) -> Result<CodexFileImportResul
30883159 match & parsed {
30893160 serde_json:: Value :: Object ( _) => {
30903161 if let Some ( ( tokens, hint) ) = extract_codex_tokens_from_value ( & parsed) {
3091- candidates. push ( ( tokens, hint, filename_label) ) ;
3162+ candidates. push ( ( tokens, hint, filename_label, auth_file_plan_type . clone ( ) ) ) ;
30923163 } else {
30933164 logger:: log_error ( & format ! ( "未找到有效 Token {:?}" , file_path) ) ;
30943165 }
@@ -3101,7 +3172,7 @@ pub fn import_from_files(file_paths: Vec<String>) -> Result<CodexFileImportResul
31013172 . and_then ( |v| v. as_str ( ) )
31023173 . unwrap_or ( & filename_label)
31033174 . to_string ( ) ;
3104- candidates. push ( ( tokens, hint, label) ) ;
3175+ candidates. push ( ( tokens, hint, label, auth_file_plan_type . clone ( ) ) ) ;
31053176 }
31063177 }
31073178 }
@@ -3124,7 +3195,9 @@ pub fn import_from_files(file_paths: Vec<String>) -> Result<CodexFileImportResul
31243195 let mut failed: Vec < CodexFileImportFailure > = Vec :: new ( ) ;
31253196 let total = candidates. len ( ) ;
31263197
3127- for ( index, ( tokens, account_id_hint, label) ) in candidates. into_iter ( ) . enumerate ( ) {
3198+ for ( index, ( tokens, account_id_hint, label, auth_file_plan_type) ) in
3199+ candidates. into_iter ( ) . enumerate ( )
3200+ {
31283201 // 发送进度事件
31293202 if let Some ( app_handle) = crate :: get_app_handle ( ) {
31303203 use tauri:: Emitter ;
@@ -3139,7 +3212,10 @@ pub fn import_from_files(file_paths: Vec<String>) -> Result<CodexFileImportResul
31393212 }
31403213
31413214 match upsert_account_with_hints ( tokens, account_id_hint, None ) {
3142- Ok ( account) => {
3215+ Ok ( mut account) => {
3216+ if apply_auth_file_plan_type ( & mut account, auth_file_plan_type) {
3217+ save_account ( & account) ?;
3218+ }
31433219 logger:: log_info ( & format ! ( "Codex 导入成功: {}" , account. email) ) ;
31443220 imported. push ( account) ;
31453221 }
0 commit comments