diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml
index 1a6a33961..d3819453e 100644
--- a/.github/workflows/pr-build.yml
+++ b/.github/workflows/pr-build.yml
@@ -26,7 +26,29 @@ jobs:
uses: dtolnay/rust-toolchain@stable
- name: Install NSIS
- run: choco install nsis -y
+ shell: pwsh
+ run: |
+ $makensis = $null
+ for ($attempt = 1; $attempt -le 3; $attempt++) {
+ choco install nsis -y --no-progress
+ # Chocolatey 可能在下载失败后返回成功,必须实际验证编译器。
+ $candidates = @(
+ "${env:ProgramFiles(x86)}\NSIS\makensis.exe",
+ "$env:ProgramFiles\NSIS\makensis.exe"
+ )
+ $makensis = $candidates | Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } | Select-Object -First 1
+ if (-not $makensis) {
+ $command = Get-Command makensis.exe -ErrorAction SilentlyContinue
+ if ($command) { $makensis = $command.Source }
+ }
+ if ($makensis) {
+ & $makensis /VERSION
+ if ($LASTEXITCODE -eq 0) { break }
+ }
+ $makensis = $null
+ if ($attempt -lt 3) { Start-Sleep -Seconds (10 * $attempt) }
+ }
+ if (-not $makensis) { throw "NSIS 安装失败或编译器不可用,停止 PR 构建。" }
- name: Install frontend dependencies
working-directory: apps/codex-plus-manager
@@ -68,13 +90,26 @@ jobs:
if (-not $version -or $version -eq "main") {
$version = "0.0.0-${{ github.run_number }}"
}
- $makensis = "${env:ProgramFiles(x86)}\NSIS\makensis.exe"
- if (-not (Test-Path $makensis)) {
- $makensis = "makensis"
+ # NSIS 的 64 位安装目录与 Chocolatey PATH 更新均需要兼容。
+ $candidates = @(
+ "${env:ProgramFiles(x86)}\NSIS\makensis.exe",
+ "$env:ProgramFiles\NSIS\makensis.exe"
+ )
+ $makensis = $candidates | Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } | Select-Object -First 1
+ if (-not $makensis) {
+ $command = Get-Command makensis.exe -ErrorAction SilentlyContinue
+ if ($command) { $makensis = $command.Source }
+ }
+ if (-not $makensis) {
+ throw "NSIS 编译器未找到,检查 Chocolatey 安装结果。"
}
Push-Location scripts/installer/windows
- & $makensis "/INPUTCHARSET" "UTF8" "/DVERSION=$version" CodexPlusPlus.nsi
- Pop-Location
+ try {
+ & $makensis "/INPUTCHARSET" "UTF8" "/DVERSION=$version" CodexPlusPlus.nsi
+ if ($LASTEXITCODE -ne 0) { throw "NSIS 打包失败,退出码 $LASTEXITCODE" }
+ } finally {
+ Pop-Location
+ }
- name: Upload Windows binaries
uses: actions/upload-artifact@v4
diff --git a/apps/codex-plus-launcher/src/main.rs b/apps/codex-plus-launcher/src/main.rs
index 3c644f197..029ab79ed 100644
--- a/apps/codex-plus-launcher/src/main.rs
+++ b/apps/codex-plus-launcher/src/main.rs
@@ -518,6 +518,7 @@ async fn run_embedded_session(
|| repair_session_index_automatically(hooks.index_repair_checks_setting()),
)
.await;
+ handle.stop_isolated_api_quota_gate().await;
stopped_by_host = host_stop;
result
}
@@ -1818,9 +1819,16 @@ mod tests {
body.matches("repair_session_index_automatically(").count(),
1
);
- assert!(body.contains(
- "wait_for_session_exit_or_stop(handle.wait_for_codex_exit(), &mut stop)"
- ));
+ assert!(
+ body.contains("wait_for_session_exit_or_stop(handle.wait_for_codex_exit(), &mut stop)")
+ );
+ let quota_stop = body
+ .find("handle.stop_isolated_api_quota_gate().await")
+ .unwrap();
+ let helper_stop = body
+ .find("hooks.shutdown_helper(options.helper_port).await")
+ .unwrap();
+ assert!(quota_stop < helper_stop);
let launch_start = source.find("async fn launcher_session(").unwrap();
let launch_end = source[launch_start..]
.find("async fn activate_and_write_running_status(")
diff --git a/apps/codex-plus-manager/src/App.tsx b/apps/codex-plus-manager/src/App.tsx
index 01221b9ac..8d3d2626b 100644
--- a/apps/codex-plus-manager/src/App.tsx
+++ b/apps/codex-plus-manager/src/App.tsx
@@ -300,6 +300,7 @@ type BackendSettings = WhaleBalanceSettings & {
providerSyncLastSelectedProvider: string;
relayProfilesEnabled: boolean;
enhancementsEnabled: boolean;
+ codexAppStandaloneQuotaUnlock: boolean;
codexAppPluginMarketplaceUnlock: boolean;
codexAppModelWhitelistUnlock: boolean;
codexAppSessionDelete: boolean;
@@ -1058,6 +1059,7 @@ const defaultSettings: BackendSettings = {
providerSyncLastSelectedProvider: "",
relayProfilesEnabled: true,
enhancementsEnabled: true,
+ codexAppStandaloneQuotaUnlock: false,
codexAppPluginMarketplaceUnlock: true,
codexAppModelWhitelistUnlock: true,
codexAppSessionDelete: true,
@@ -5705,18 +5707,32 @@ function EnhanceScreen({
-
+
+
+
+
{dirty ? t("有未保存修改") : t("已保存")}