Skip to content
Open
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
11 changes: 4 additions & 7 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
*.sh text eol=lf
.github/workflows/*.yml text eol=lf

# Preserve the original Snow Skin asset line endings for byte-exact bundling.
assets/inject/upstream/snow-skin/*.js text eol=lf
assets/inject/upstream/snow-skin/*.css text eol=lf

# Keep byte-exact macOS theme assets identical on every checkout platform.
assets/inject/upstream/*/macos/*.js text eol=lf
assets/inject/upstream/*/macos/*.css text eol=lf
# Keep every byte-exact upstream theme asset stable on all checkout platforms.
assets/inject/upstream/**/*.js text eol=lf
assets/inject/upstream/**/*.css text eol=lf
assets/inject/upstream/skin-packs/packs/*/theme.json text eol=lf
23 changes: 23 additions & 0 deletions apps/codex-plus-manager/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ export type RelayProfile = {
protocol: RelayProtocol;
relayMode: RelayMode;
officialMixApiKey: boolean;
hideOfficialUsageAlert: boolean;
testModel: string;
configContents: string;
authContents: string;
Expand Down Expand Up @@ -838,6 +839,7 @@ const defaultSettings: BackendSettings = {
protocol: "responses",
relayMode: "official",
officialMixApiKey: false,
hideOfficialUsageAlert: false,
testModel: "",
configContents: "",
authContents: "",
Expand Down Expand Up @@ -5782,6 +5784,21 @@ function RelayProfileEditor({
<span>{t("启用目标功能")}</span>
</label>
</Field>
{profile.relayMode === "official" ? (
<Field className="relay-field-official-usage-alert" label={t("官方登录")}>
<label className="inline-check">
<input
checked={profile.hideOfficialUsageAlert}
onChange={(event) => updateDraft({ hideOfficialUsageAlert: event.currentTarget.checked })}
type="checkbox"
/>
<span>{t("关闭官方低额度提示")}</span>
</label>
<p className="field-hint">
{t("关闭后仍可从 Codex 左下角账户菜单查看官方剩余额度。")}
</p>
</Field>
) : null}
<div className="relay-advanced-toggle">
<Button
aria-expanded={showAdvanced}
Expand Down Expand Up @@ -7895,6 +7912,7 @@ function normalizeSettings(settings: BackendSettings): BackendSettings {
protocol: "responses" as RelayProtocol,
relayMode: "official" as RelayMode,
officialMixApiKey: false,
hideOfficialUsageAlert: false,
testModel: "",
configContents: "",
authContents: "",
Expand Down Expand Up @@ -7975,6 +7993,7 @@ function normalizeRelayProfile(profile: RelayProfile, defaultContextSelection =
protocol: "responses",
relayMode: "aggregate",
officialMixApiKey: false,
hideOfficialUsageAlert: false,
testModel: profile.testModel || "",
configContents: "",
authContents: "",
Expand Down Expand Up @@ -8004,6 +8023,7 @@ function normalizeRelayProfile(profile: RelayProfile, defaultContextSelection =
protocol: profile.protocol === "chatCompletions" ? "chatCompletions" : "responses",
relayMode,
officialMixApiKey,
hideOfficialUsageAlert: profile.hideOfficialUsageAlert === true,
testModel: profile.testModel || "",
configContents: relayMode === "official" && !officialMixApiKey ? "" : profile.configContents || "",
authContents: relayMode === "official" && !officialMixApiKey ? buildOfficialRelayAuthJson(profile.authContents || "") : profile.authContents || "",
Expand Down Expand Up @@ -8650,6 +8670,7 @@ function createRelayProfile(settings: BackendSettings): RelayProfile {
protocol: "responses" as RelayProtocol,
relayMode: "official" as RelayMode,
officialMixApiKey: false,
hideOfficialUsageAlert: false,
testModel: "",
configContents: "",
authContents: "",
Expand Down Expand Up @@ -8686,6 +8707,7 @@ function createAggregateRelayProfile(settings: BackendSettings): RelayProfile {
protocol: "responses",
relayMode: "aggregate",
officialMixApiKey: false,
hideOfficialUsageAlert: false,
testModel: "",
configContents: "",
authContents: "",
Expand Down Expand Up @@ -8821,6 +8843,7 @@ function normalizeAggregateRelayProfile(profile: RelayProfile, settings: Backend
protocol: "responses",
relayMode: "aggregate",
officialMixApiKey: false,
hideOfficialUsageAlert: false,
configContents: "",
authContents: "",
sub2apiEnabled: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type RelayProfile = {
protocol: RelayProtocol;
relayMode: string;
officialMixApiKey: boolean;
hideOfficialUsageAlert: boolean;
testModel: string;
configContents: string;
authContents: string;
Expand Down Expand Up @@ -48,6 +49,7 @@ export function createPresetPatch(preset: ProviderPreset): PresetPatch {
modelList: preset.modelList?.join("\n") ?? "",
relayMode: preset.category === "official" ? "official" : "pureApi",
officialMixApiKey: false,
hideOfficialUsageAlert: false,
};
}

Expand Down
3 changes: 3 additions & 0 deletions apps/codex-plus-manager/src/i18n-en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,9 @@ export const EN_PLAIN: Record<string, string> = {
"深色": "Dark",
"混入 API": "Mixed-in API",
"混入 API KEY": "Mix in API KEY",
"关闭官方低额度提示": "Hide official low-usage alert",
"关闭后仍可从 Codex 左下角账户菜单查看官方剩余额度。":
"When hidden, you can still view the official quota from the account menu in the lower-left corner of Codex.",
"混入 API Key": "Mix in API Key",
"添加供应商": "Add provider",
"添加模型": "Add model",
Expand Down
1 change: 1 addition & 0 deletions apps/codex-plus-manager/src/model-windows.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const _profileTypeCheck: RelayProfile = {
protocol: "responses",
relayMode: "official",
officialMixApiKey: false,
hideOfficialUsageAlert: false,
testModel: "",
configContents: "",
authContents: "",
Expand Down
36 changes: 36 additions & 0 deletions assets/inject/renderer-inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -9805,6 +9805,7 @@

function scanLightweight() {
installStyle();
refreshOfficialUsageAlertVisibility();
installCodexServiceTierDispatcherPatch();
installCodexProjectlessNewTaskButtons();
installCodexPlusMenu();
Expand All @@ -9820,6 +9821,40 @@
refreshCodexServiceTierControls();
}

function officialUsageAlertCards(scope = document) {
const root = scope?.querySelectorAll ? scope : document;
return Array.from(root.querySelectorAll('aside.app-shell-left-panel [role="status"][aria-live="polite"]')).filter((card) => {
if (!(card instanceof HTMLElement)) return false;
const progress = card.querySelector('progress[max="100"]');
if (!progress) return false;
const dismissButton = Array.from(card.querySelectorAll("button")).find((button) =>
/dismiss usage alert|关闭使用量提醒/i.test(button.getAttribute("aria-label") || ""),
);
return !!dismissButton;
});
}

function officialUsageAlertContainer(card) {
const parent = card.parentElement;
return parent?.children.length === 1 && parent.matches("div.w-full") ? parent : card;
}

function refreshOfficialUsageAlertVisibility() {
const hidden = window.__CODEX_PLUS_HIDE_OFFICIAL_USAGE_ALERT__ === true;
officialUsageAlertCards().forEach((card) => {
const container = officialUsageAlertContainer(card);
if (hidden) {
container.dataset.codexPlusUsageAlertHidden = "true";
container.style.setProperty("display", "none", "important");
return;
}
if (container.dataset.codexPlusUsageAlertHidden === "true") {
delete container.dataset.codexPlusUsageAlertHidden;
container.style.removeProperty("display");
}
});
}

let zedRemoteStatusPromise = null;
const zedRemoteMissingHostMessage = "Cannot determine remote SSH host for this file";

Expand Down Expand Up @@ -10464,6 +10499,7 @@
function scanRelevantSelector() {
return [
selectors.sidebarThread,
'aside.app-shell-left-panel [role="status"][aria-live="polite"]',
'[data-app-action-sidebar-section-heading="Chats"]',
'[data-app-action-sidebar-section-heading="Projects"]',
'[data-codex-project-move-row="true"]',
Expand Down
9 changes: 8 additions & 1 deletion crates/codex-plus-core/src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,13 @@ pub fn injection_script_with_settings(helper_port: u16, settings: &BackendSettin
let paste_fix = paste_fix_enabled_config(settings);
let force_chinese_locale = force_chinese_locale_config(settings);
let fast_startup = fast_startup_config(settings);
let hide_official_usage_alert = {
let profile = settings.active_relay_profile();
profile.relay_mode == crate::settings::RelayMode::Official
&& profile.hide_official_usage_alert
};
format!(
"window.__CODEX_SESSION_DELETE_HELPER__ = {};\nwindow.__CODEX_PLUS_SPONSOR_IMAGES__ = {};\nwindow.__CODEX_PLUS_VERSION__ = {};\nwindow.__CODEX_PLUS_BUILD__ = {};\nwindow.__CODEX_PLUS_IMAGE_OVERLAY__ = {};\nwindow.__CODEX_PLUS_PLUGIN_MARKETPLACES__ = {};\nwindow.__CODEX_PLUS_EXTERNAL_DREAM_SKIN_RUNTIME__ = true;\nwindow.__CODEX_PLUS_DREAM_SKIN_PLATFORM__ = {};\nwindow.__CODEX_PLUS_DREAM_SKIN_REVISION__ = {};\nwindow.__CODEX_PLUS_DREAM_SKIN_ART__ = {};\nwindow.__CODEX_PLUS_DREAM_SKIN_ART_SIGNATURE__ = {};\nwindow.__CODEX_PLUS_DREAM_SKIN_THEME__ = {};\nwindow.__CODEX_PLUS_PASTE_FIX__ = {};\nwindow.__CODEX_PLUS_FORCE_CHINESE_LOCALE__ = {};\nwindow.__CODEX_PLUS_FAST_STARTUP__ = {};\n{}\n{}\n{}",
"window.__CODEX_SESSION_DELETE_HELPER__ = {};\nwindow.__CODEX_PLUS_SPONSOR_IMAGES__ = {};\nwindow.__CODEX_PLUS_VERSION__ = {};\nwindow.__CODEX_PLUS_BUILD__ = {};\nwindow.__CODEX_PLUS_IMAGE_OVERLAY__ = {};\nwindow.__CODEX_PLUS_PLUGIN_MARKETPLACES__ = {};\nwindow.__CODEX_PLUS_EXTERNAL_DREAM_SKIN_RUNTIME__ = true;\nwindow.__CODEX_PLUS_DREAM_SKIN_PLATFORM__ = {};\nwindow.__CODEX_PLUS_DREAM_SKIN_REVISION__ = {};\nwindow.__CODEX_PLUS_DREAM_SKIN_ART__ = {};\nwindow.__CODEX_PLUS_DREAM_SKIN_ART_SIGNATURE__ = {};\nwindow.__CODEX_PLUS_DREAM_SKIN_THEME__ = {};\nwindow.__CODEX_PLUS_PASTE_FIX__ = {};\nwindow.__CODEX_PLUS_FORCE_CHINESE_LOCALE__ = {};\nwindow.__CODEX_PLUS_FAST_STARTUP__ = {};\nwindow.__CODEX_PLUS_HIDE_OFFICIAL_USAGE_ALERT__ = {};\n{}\n{}\n{}",
serde_json::to_string(&helper_url).expect("helper URL should serialize"),
serde_json::to_string(&sponsor_images).expect("sponsor images should serialize"),
serde_json::to_string(crate::version::VERSION).expect("version should serialize"),
Expand All @@ -359,6 +364,8 @@ pub fn injection_script_with_settings(helper_port: u16, settings: &BackendSettin
serde_json::to_string(&force_chinese_locale)
.expect("force Chinese locale config should serialize"),
serde_json::to_string(&fast_startup).expect("fast startup config should serialize"),
serde_json::to_string(&hide_official_usage_alert)
.expect("usage alert config should serialize"),
renderer_script(),
stepwise_script(),
dream_skin_target_runtime,
Expand Down
1 change: 1 addition & 0 deletions crates/codex-plus-core/src/ccs_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub fn relay_profile_from_ccs(
protocol: provider.protocol,
relay_mode: RelayMode::PureApi,
official_mix_api_key: false,
hide_official_usage_alert: false,
test_model: String::new(),
config_contents: provider.config_contents.clone(),
auth_contents: provider.auth_contents.clone(),
Expand Down
1 change: 1 addition & 0 deletions crates/codex-plus-core/src/provider_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ fn relay_profile_from_request(
protocol: relay_protocol(&request.wire_api),
relay_mode: relay_mode(&request.relay_mode),
official_mix_api_key: false,
hide_official_usage_alert: false,
test_model: String::new(),
config_contents: request.config_contents.clone(),
auth_contents: request.auth_contents.clone(),
Expand Down
9 changes: 9 additions & 0 deletions crates/codex-plus-core/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pub struct RelayProfile {
pub relay_mode: RelayMode,
#[serde(rename = "officialMixApiKey", default)]
pub official_mix_api_key: bool,
#[serde(rename = "hideOfficialUsageAlert", default)]
pub hide_official_usage_alert: bool,
#[serde(rename = "testModel", default)]
pub test_model: String,
#[serde(rename = "configContents", default)]
Expand Down Expand Up @@ -157,6 +159,7 @@ impl Default for RelayProfile {
protocol: RelayProtocol::Responses,
relay_mode: RelayMode::Official,
official_mix_api_key: false,
hide_official_usage_alert: false,
test_model: String::new(),
config_contents: String::new(),
auth_contents: String::new(),
Expand Down Expand Up @@ -574,6 +577,7 @@ impl BackendSettings {
protocol: RelayProtocol::Responses,
relay_mode: RelayMode::MixedApi,
official_mix_api_key: true,
hide_official_usage_alert: false,
test_model: String::new(),
config_contents: String::new(),
auth_contents: String::new(),
Expand Down Expand Up @@ -625,6 +629,7 @@ impl BackendSettings {
protocol: RelayProtocol::Responses,
relay_mode: RelayMode::Official,
official_mix_api_key: false,
hide_official_usage_alert: false,
test_model: String::new(),
config_contents: String::new(),
auth_contents: String::new(),
Expand Down Expand Up @@ -1696,6 +1701,7 @@ mod tests {

assert_eq!(profile.relay_mode, RelayMode::Official);
assert!(!profile.official_mix_api_key);
assert!(!profile.hide_official_usage_alert);
assert!(profile.test_model.is_empty());
}

Expand Down Expand Up @@ -1834,6 +1840,7 @@ base_url = "http://127.0.0.1:57321/v1"
name: "官方".to_string(),
relay_mode: RelayMode::Official,
official_mix_api_key: false,
hide_official_usage_alert: false,
model: "gpt-5.5".to_string(),
base_url: "https://relay.example/v1".to_string(),
api_key: "sk-test".to_string(),
Expand Down Expand Up @@ -1872,6 +1879,7 @@ requires_openai_auth = true
name: "官方混入".to_string(),
relay_mode: RelayMode::Official,
official_mix_api_key: true,
hide_official_usage_alert: false,
model: "gpt-5.5".to_string(),
base_url: "https://relay.example/v1".to_string(),
api_key: "sk-mix".to_string(),
Expand Down Expand Up @@ -1934,6 +1942,7 @@ experimental_bearer_token = "sk-mix"
name: "官方混入".to_string(),
relay_mode: RelayMode::Official,
official_mix_api_key: true,
hide_official_usage_alert: false,
config_contents: r#"model_provider = "custom"

[model_providers.other]
Expand Down
48 changes: 48 additions & 0 deletions crates/codex-plus-core/tests/cdp_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,52 @@ fn injection_script_exposes_image_overlay_config() {
assert!(script.contains("http://127.0.0.1:57321/overlay/image"));
}

#[test]
fn official_login_usage_alert_setting_controls_renderer_injection() {
use codex_plus_core::settings::{RelayMode, RelayProfile};

let settings = |relay_mode, hide_official_usage_alert, official_mix_api_key| {
codex_plus_core::settings::BackendSettings {
active_relay_id: "official".to_string(),
relay_profiles: vec![RelayProfile {
id: "official".to_string(),
relay_mode,
official_mix_api_key,
hide_official_usage_alert,
..Default::default()
}],
..Default::default()
}
};

assert!(
assets::injection_script_with_settings(57321, &settings(RelayMode::Official, true, false))
.contains("window.__CODEX_PLUS_HIDE_OFFICIAL_USAGE_ALERT__ = true;")
);
assert!(
assets::injection_script_with_settings(57321, &settings(RelayMode::Official, true, true))
.contains("window.__CODEX_PLUS_HIDE_OFFICIAL_USAGE_ALERT__ = true;")
);
assert!(
assets::injection_script_with_settings(57321, &settings(RelayMode::Official, false, false))
.contains("window.__CODEX_PLUS_HIDE_OFFICIAL_USAGE_ALERT__ = false;")
);
assert!(
assets::injection_script_with_settings(57321, &settings(RelayMode::PureApi, true, false))
.contains("window.__CODEX_PLUS_HIDE_OFFICIAL_USAGE_ALERT__ = false;")
);
}

#[test]
fn usage_alert_hider_uses_sidebar_semantics_instead_of_percentage_copy() {
let script = assets::injection_script(57321);

assert!(script.contains("officialUsageAlertCards"));
assert!(script.contains("progress[max=\"100\"]"));
assert!(script.contains("dismiss usage alert|关闭使用量提醒"));
assert!(script.contains("codexPlusUsageAlertHidden"));
}

#[test]
fn injection_script_installs_image_overlay_from_data_uri() {
let script = assets::injection_script(57321);
Expand Down Expand Up @@ -2091,6 +2137,8 @@ fn manager_ui_exposes_pure_api_relay_mode_button() {
std::fs::read_to_string(repo.join("apps/codex-plus-manager/src-tauri/src/lib.rs")).unwrap();

assert!(source.contains("官方混入 API Key"));
assert!(source.contains("关闭官方低额度提示"));
assert!(source.contains("hideOfficialUsageAlert"));
assert!(source.contains("纯 API"));
assert!(source.contains("apply_pure_api_injection"));
assert!(commands.contains("commands::apply_pure_api_injection"));
Expand Down
3 changes: 3 additions & 0 deletions crates/codex-plus-core/tests/launcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,7 @@ async fn official_mix_responses_profile_starts_fixed_protocol_proxy_without_enha
id: "official-mix".to_string(),
relay_mode: RelayMode::Official,
official_mix_api_key: true,
hide_official_usage_alert: false,
protocol: RelayProtocol::Responses,
..RelayProfile::default()
}],
Expand Down Expand Up @@ -1199,6 +1200,7 @@ async fn official_mix_responses_profile_keeps_proxy_when_profile_switching_is_di
id: "official-mix".to_string(),
relay_mode: RelayMode::Official,
official_mix_api_key: true,
hide_official_usage_alert: false,
protocol: RelayProtocol::Responses,
..RelayProfile::default()
}],
Expand Down Expand Up @@ -1437,6 +1439,7 @@ async fn launch_starts_helper_when_chat_protocol_proxy_is_enabled() {
protocol: RelayProtocol::ChatCompletions,
relay_mode: codex_plus_core::settings::RelayMode::MixedApi,
official_mix_api_key: false,
hide_official_usage_alert: false,
test_model: String::new(),
config_contents: String::new(),
auth_contents: String::new(),
Expand Down
1 change: 1 addition & 0 deletions crates/codex-plus-core/tests/protocol_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ async fn responses_compact_request_keeps_compact_path_upstream() {
api_key: "sk-compact".to_string(),
relay_mode: RelayMode::Official,
official_mix_api_key: true,
hide_official_usage_alert: false,
..RelayProfile::default()
}],
..BackendSettings::default()
Expand Down
Loading
Loading