diff --git a/.github/workflows/linux-lua.yml b/.github/workflows/linux-lua.yml
index 6c7ac89..f7f477b 100644
--- a/.github/workflows/linux-lua.yml
+++ b/.github/workflows/linux-lua.yml
@@ -34,6 +34,8 @@ jobs:
env:
PYTHONUTF8: "1"
CARGO_TERM_COLOR: always
+ RUST_BACKTRACE: "1"
+ RUST_TOOLCHAIN: "1.97.1"
steps:
- uses: actions/checkout@v4
with:
@@ -61,22 +63,12 @@ jobs:
with:
toolchain: "1.97.1"
- uses: Swatinem/rust-cache@v2
- - name: Test native titlebar alignment
- if: runner.os == 'macOS'
- run: >-
- cargo test --locked -p nebula --bin pebrel --features gpui-test-support platform::window_chrome::macos::tests::
- - name: Test all Python helpers
- if: ${{ !cancelled() }}
- run: python -m unittest discover -s scripts/tests -v
- - name: Test all conformance harness helpers
- if: ${{ !cancelled() }}
- run: python -m unittest discover -s scripts/conformance/tests -v
- - name: Test the full Rust workspace
- if: ${{ !cancelled() }}
- run: cargo test --locked --workspace
- - name: Test all GPUI product and interaction cases
- if: ${{ !cancelled() }}
- run: cargo test --locked -p nebula --bin pebrel --features gpui-test-support
+ with:
+ shared-key: ${{ runner.os == 'Windows' && 'windows' || runner.os == 'Linux' && 'linux' || 'macos' }}
+ cache-workspace-crates: true
+ cache-on-failure: true
+ - name: Test complete workspace and native harness
+ run: python scripts/ci_native_tests.py
- name: Check source architecture
if: ${{ !cancelled() && runner.os == 'Linux' }}
run: python scripts/check_architecture.py
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index fddf61c..4d89fb2 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -106,6 +106,7 @@ jobs:
python3 scripts/check_platform_cfg.py
python3 -m unittest \
scripts.tests.test_stable_release \
+ scripts.tests.test_ci_native_tests \
scripts.tests.test_preview_release \
scripts.tests.test_macos_dmg \
scripts.tests.test_ai_session_probe \
@@ -118,6 +119,66 @@ jobs:
bash -n scripts/package-linux.sh scripts/package-macos.sh
python3 -m py_compile scripts/stable_release.py scripts/preview_release.py
+ native-tests:
+ name: Native tests (${{ matrix.platform }})
+ if: ${{ !inputs.windows_only }}
+ needs: prepare
+ timeout-minutes: 120
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - runner: ubuntu-22.04
+ platform: linux-x64
+ cache: linux
+ - runner: windows-2022
+ platform: windows-x64
+ cache: windows
+ - runner: macos-26
+ platform: macos-arm64
+ cache: macos
+ - runner: macos-26-intel
+ platform: macos-x64
+ cache: macos
+ runs-on: ${{ matrix.runner }}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.13"
+ - name: Install native test dependencies
+ if: runner.os == 'Linux'
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y --no-install-recommends \
+ build-essential cmake pkg-config zsh libasound2-dev libdbus-1-dev libudev-dev \
+ libfontconfig1-dev libfreetype6-dev libegl1-mesa-dev libgl1-mesa-dev \
+ libwayland-dev libxkbcommon-dev libxkbcommon-x11-dev libx11-xcb-dev \
+ libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \
+ libxcb-xinput-dev libxcb-xkb-dev libxi-dev
+ - uses: dtolnay/rust-toolchain@stable
+ with:
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
+ - uses: Swatinem/rust-cache@v2
+ with:
+ shared-key: ${{ matrix.cache }}
+ cache-workspace-crates: true
+ cache-on-failure: true
+ - name: Prepare pinned Windows console runtime
+ if: runner.os == 'Windows'
+ shell: pwsh
+ run: ./scripts/prepare-windows-runtime.ps1 -Destination assets/windows/conhost
+ - name: Test complete workspace and native harness
+ run: python scripts/ci_native_tests.py
+ - name: Upload native compilation timings
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: native-timings-${{ matrix.platform }}
+ path: target/cargo-timings
+ if-no-files-found: warn
+ retention-days: 14
+
linux:
name: Linux x86_64 stable package
if: ${{ !inputs.windows_only }}
@@ -151,15 +212,9 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- - name: Test workspace and startup contracts
- run: |
- cargo test --locked --workspace
- cargo test --locked -p nebula --bin pebrel --features gpui-shell
- python3 -m unittest scripts.tests.test_shell_integration
- cargo test --locked -p nebula --features gpui-test-support dialog
- cargo test --locked -p nebula --bin pebrel --features gpui-test-support gpui_shell::
+ cache-workspace-crates: true
- name: Build GPUI release binary
- run: cargo build --locked --release -p nebula --bin pebrel --features gpui-shell
+ run: cargo build --locked --release -p nebula --bin pebrel --features gpui-shell --timings
- name: Download pinned linuxdeploy
env:
LINUXDEPLOY: ${{ runner.temp }}/linuxdeploy-x86_64.AppImage
@@ -284,15 +339,9 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- - name: Test workspace and native startup contracts
- run: |
- cargo test --locked --workspace
- cargo test --locked -p nebula --bin pebrel --features gpui-shell
- python3 -m unittest scripts.tests.test_shell_integration scripts.conformance.tests.test_posix_lifecycle
- cargo test --locked -p nebula --features gpui-test-support dialog
- cargo test --locked -p nebula --bin pebrel --features gpui-test-support gpui_shell::
+ cache-workspace-crates: true
- name: Build GPUI release binary
- run: cargo build --locked --release -p nebula --bin pebrel --features gpui-shell
+ run: cargo build --locked --release -p nebula --bin pebrel --features gpui-shell --timings
- name: Import Developer ID signing credentials
if: ${{ env.MACOS_SIGNING == 'developer-id' }}
env:
@@ -422,9 +471,9 @@ jobs:
$run = Invoke-RestMethod -Uri "https://api.github.com/repos/$env:GITHUB_REPOSITORY/actions/runs/$env:VALIDATED_RUN" -Headers $headers -ErrorAction Stop
if ($run.head_sha -ne $env:SELECTED_COMMIT) { throw 'Validated run source differs.' }
$jobs = Invoke-RestMethod -Uri "https://api.github.com/repos/$env:GITHUB_REPOSITORY/actions/runs/$env:VALIDATED_RUN/jobs?per_page=100" -Headers $headers -ErrorAction Stop
- $windows = @($jobs.jobs | Where-Object name -eq 'Windows x64 stable package')
- $tests = @($windows.steps | Where-Object { $_.name -eq 'Test workspace and native harness' -and $_.conclusion -eq 'success' })
- if ($windows.Count -ne 1 -or $tests.Count -ne 1) { throw 'Prior Windows native tests did not pass.' }
+ $windows = @($jobs.jobs | Where-Object { $_.name -in @('Windows x64 stable package', 'Native tests (windows-x64)') })
+ $tests = @($windows.steps | Where-Object { $_.name -in @('Test workspace and native harness', 'Test complete workspace and native harness') -and $_.conclusion -eq 'success' })
+ if ($tests.Count -ne 1) { throw 'Prior Windows native tests did not pass.' }
- uses: actions/checkout@v4
if: ${{ inputs.source_commit != '' }}
with:
@@ -438,32 +487,18 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
+ cache-workspace-crates: true
- name: Prepare pinned Windows console runtime
shell: pwsh
run: |
& "$env:RUNNER_TEMP/prepare-windows-runtime.ps1" -Destination assets/windows/conhost
& "$env:RUNNER_TEMP/runtime-tests/windows-runtime.tests.ps1" -ArchivePath (Join-Path ([IO.Path]::GetTempPath()) 'pebrel-conpty-source-v1.5.0.zip')
- name: Test workspace and native harness
- if: ${{ inputs.source_commit == '' }}
- shell: pwsh
- run: |
- python -m unittest scripts.conformance.tests.test_lifecycle scripts.conformance.tests.test_scrollback
- if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- cargo test --locked --workspace
- if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- cargo test --locked -p nebula --bin pebrel --features gpui-shell
- if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- cargo test --locked -p nebula --features gpui-test-support dialog
- if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- cargo test --locked -p nebula --bin pebrel --features gpui-test-support gpui_shell::
- if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
+ if: ${{ inputs.windows_only && inputs.source_commit == '' }}
+ run: python scripts/ci_native_tests.py
- name: Build GPUI release binary
shell: pwsh
- run: |
- cargo build --locked --release -p nebula_hook --bin pebrel-hook
- if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- cargo build --locked --release -p nebula --bin pebrel --features gpui-shell
- exit $LASTEXITCODE
+ run: ./scripts/build-windows-product.ps1 -Configuration release -TargetDirectory target
- name: Retain built Windows runtime before packaging
uses: actions/upload-artifact@v4
with:
@@ -519,7 +554,7 @@ jobs:
aggregate:
name: Verify stable assets and upload complete set
if: ${{ !inputs.windows_only }}
- needs: [prepare, linux, macos, windows]
+ needs: [prepare, native-tests, linux, macos, windows]
runs-on: ubuntu-22.04
env:
PACKAGE_VERSION: ${{ needs.prepare.outputs.version }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a7cad15..499770b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,7 @@ Every release entry is provided in English and Simplified Chinese.
每个版本条目均同时提供英文和简体中文说明。
-## Unreleased / 未发布
+## 1.8.0 - 2026-09-14
### English
@@ -20,29 +20,68 @@ Every release entry is provided in English and Simplified Chinese.
- Fixed Windows terminal focus consuming `Alt+F4` and `Alt+Space`. `Alt+F4` now uses the normal window-close flow, and `Alt+Space`, followed by `N`, uses the system menu to minimize the window.
- Fixed the top Settings tab disappearing when switching to another tab. It now remains available until explicitly closed, including when tabs overflow or the tab layout changes.
- Fixed `Alt+1–9` and `Ctrl+1–9` tab shortcuts losing priority to terminal input. They now work while a terminal or CLI has focus and respect custom shortcut changes without restarting.
+- Fixed WSL filename search failing when the directory path contains spaces or shell punctuation. Cancelling a search stops its own directory scan.
+- Aligned macOS native window controls with the sidebar and Settings buttons, and preserved their reserved space in the top tab layout. Window controls follow the system appearance. Contributed by [@WilliamWang1721](https://github.com/WilliamWang1721) in [#114](https://github.com/Kuddev/pebrel/pull/114).
+- Fixed the Git drawer retaining Chinese labels when the application resolves to English. Controls, history timestamps and application notices follow the selected language; switching languages preserves the commit draft and text selection. Contributed by [@gao-jian-bin](https://github.com/gao-jian-bin) in [#118](https://github.com/Kuddev/pebrel/pull/118).
+- Fixed explicitly configured terminal selection text colors being ignored. Themes without their own selection foreground preserve that setting; themes with an explicit foreground retain their precedence. Contributed by [@Aschenbath](https://github.com/Aschenbath) in [#125](https://github.com/Kuddev/pebrel/pull/125).
#### Improved
+- Reduced file browsing and filename-search memory use by starting recursive searches only when a query is entered, reusing a bounded cache and streaming paths beyond that cache. Repeated panel use releases obsolete results and cancels superseded searches. Case, whole-word and regular-expression options remain available, with visible feedback for incomplete searches and errors.
+- Reduced background-image memory use with bounded image loading and reuse while resizing the window. Replacing an image releases the previous resources; extended backgrounds retain their fit, alignment and text readability.
- Replaced the low-resolution Claude Code icon with artwork exported from SVG at 1024 pixels, and prepared Agent icons at their display size for smoother tab edges.
+Windows packages include a Pebrel installer and portable ZIP. Linux x64 packages and macOS Apple Silicon/Intel DMGs retain their Preview designation. macOS requires version 14 or later. Molecular structure rendering remains disabled.
+
### 中文
#### 新增
-- 在“设置 → 交互”中加入“焦点跟随鼠标”,默认关闭;在“设置 → 外观”中加入“调暗非活动窗格”,默认开启。两项设置均即时生效。
-- Shell 启动菜单新增右键操作,可设为默认 Shell;Windows 下还可在新的管理员 Pebrel 窗口内打开所选 Shell。
-- SSH 启动菜单新增“连接、编辑、删除”右键操作;删除沿用已有的确认与撤销流程。
-- 新增 Trae CLI 识别与标签图标,并为 Oh My Pi 加入独立图标。
+- 新增:在“设置 → 交互”中加入“焦点跟随鼠标”,默认关闭;在“设置 → 外观”中加入“调暗非活动窗格”,默认开启。两项设置均即时生效。
+- 新增:Shell 启动菜单新增右键操作,可设为默认 Shell;Windows 下还可在新的管理员 Pebrel 窗口内打开所选 Shell。
+- 新增:SSH 启动菜单新增“连接、编辑、删除”右键操作;删除沿用已有的确认与撤销流程。
+- 新增: Trae CLI 识别与标签图标,并为 Oh My Pi 加入独立图标。
#### 修复
-- 修复 Windows 终端获得焦点时吞掉 `Alt+F4` 和 `Alt+Space` 的问题。`Alt+F4` 现在进入正常窗口关闭流程,`Alt+Space` 后按 `N` 可通过系统菜单最小化窗口。
-- 修复顶部设置标签在切换到其他标签后消失的问题。现在只有主动关闭才会移除,标签溢出或切换标签布局时也会保留。
-- 修复 `Alt+1–9` 和 `Ctrl+1–9` 标签快捷键优先级低于终端输入的问题。终端或 CLI 获得焦点时仍可切换标签,自定义快捷键的修改也无需重启即可生效。
+- 修复: Windows 终端获得焦点时吞掉 `Alt+F4` 和 `Alt+Space` 的问题。`Alt+F4` 现在进入正常窗口关闭流程,`Alt+Space` 后按 `N` 可通过系统菜单最小化窗口。
+- 修复:顶部设置标签在切换到其他标签后消失的问题。现在只有主动关闭才会移除,标签溢出或切换标签布局时也会保留。
+- 修复: `Alt+1–9` 和 `Ctrl+1–9` 标签快捷键优先级低于终端输入的问题。终端或 CLI 获得焦点时仍可切换标签,自定义快捷键的修改也无需重启即可生效。
+- 修复:目录路径含空格或 Shell 特殊符号时 WSL 文件名搜索失败的问题;取消搜索会停止该次目录扫描。
+- 修复:对齐 macOS 原生窗口按钮与侧栏、设置按钮,并在顶部标签布局中保留窗口按钮所需空间;窗口按钮外观跟随系统。由 [@WilliamWang1721](https://github.com/WilliamWang1721) 在 [#114](https://github.com/Kuddev/pebrel/pull/114) 中贡献。
+- 修复:应用解析为英文时 Git 面板仍保留中文标签的问题。控件、历史时间和应用提示跟随所选语言,切换语言时保留提交草稿和文字选区。由 [@gao-jian-bin](https://github.com/gao-jian-bin) 在 [#118](https://github.com/Kuddev/pebrel/pull/118) 中贡献。
+- 修复:终端忽略用户明确设置的选中文字颜色的问题。未指定选中文字颜色的主题会保留该设置;已明确指定的主题仍保持自身优先级。由 [@Aschenbath](https://github.com/Aschenbath) 在 [#125](https://github.com/Kuddev/pebrel/pull/125) 中贡献。
#### 改进
-- 将 Claude Code 的低分辨率图标替换为从 SVG 导出的 1024 像素图像,并按显示尺寸处理 Agent 图标,使标签图标边缘更平滑。
+- 改进:降低文件浏览与文件名搜索的内存占用:输入关键词后才开始递归搜索,复用有容量上限的缓存,并流式查找缓存之外的路径。重复使用文件面板时释放过期结果、取消已被替代的搜索;保留大小写、整词和正则选项,并明确提示搜索未覆盖全部文件或发生错误。
+- 改进:降低背景图内存占用,限制图片加载成本,并在调整窗口大小时复用图像资源;替换背景图会释放旧资源,扩展背景仍保持原有的适配、对齐和文字可读性。
+- 改进:将 Claude Code 的低分辨率图标替换为从 SVG 导出的 1024 像素图像,并按显示尺寸处理 Agent 图标,使标签图标边缘更平滑。
+
+Windows 提供 Pebrel 安装器和 ZIP 便携包;Linux x64 包以及 macOS Apple Silicon/Intel DMG 继续标记为 Preview。macOS 最低运行版本为 14。分子结构渲染仍处于禁用状态。
+
+### Contributors
+
+

+
+**[@WilliamWang1721](https://github.com/WilliamWang1721)** - Aligned macOS native window controls and expanded native test coverage. / 对齐 macOS 原生窗口按钮,并扩展原生测试覆盖。([#114](https://github.com/Kuddev/pebrel/pull/114))
+
+**[@gao-jian-bin](https://github.com/gao-jian-bin)** - Made Git drawer language follow application preferences while preserving editing state. / 让 Git 面板语言跟随应用设置,同时保留编辑状态。([#118](https://github.com/Kuddev/pebrel/pull/118))
+
+**[@Aschenbath](https://github.com/Aschenbath)** - Preserved explicit terminal selection foreground colors. / 修正终端选中文字颜色的配置与主题优先级。([#125](https://github.com/Kuddev/pebrel/pull/125))
+
+
+---
+
+**SHA256**
+
+- 改进:`Pebrel-v1.8.0-windows-x64.zip`: `PENDING FINAL BUILD`
+- 改进:`Pebrel-v1.8.0-windows-x64-setup.exe`: `PENDING FINAL BUILD`
+- 改进:`Pebrel-v1.8.0-linux-x64-preview.AppImage`: `PENDING FINAL BUILD`
+- 改进:`Pebrel-v1.8.0-linux-x64-preview.deb`: `PENDING FINAL BUILD`
+- 改进:`Pebrel-v1.8.0-linux-x64-preview.tar.gz`: `PENDING FINAL BUILD`
+- 改进:`Pebrel-v1.8.0-macos-arm64-preview.dmg`: `PENDING FINAL BUILD`
+- 改进:`Pebrel-v1.8.0-macos-x64-preview.dmg`: `PENDING FINAL BUILD`
## 1.7.0 - 2026-09-12
diff --git a/Cargo.lock b/Cargo.lock
index 32399d6..a2c7305 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5087,7 +5087,7 @@ dependencies = [
[[package]]
name = "nebula"
-version = "1.7.0"
+version = "1.8.0"
dependencies = [
"ab_glyph_rasterizer",
"aes-gcm",
@@ -5174,7 +5174,7 @@ dependencies = [
[[package]]
name = "nebula-completions"
-version = "1.7.0"
+version = "1.8.0"
dependencies = [
"lscolors",
"nu-ansi-term",
@@ -5195,15 +5195,15 @@ dependencies = [
[[package]]
name = "nebula-settings"
-version = "1.7.0"
+version = "1.8.0"
[[package]]
name = "nebula-split"
-version = "1.7.0"
+version = "1.8.0"
[[package]]
name = "nebula_config"
-version = "1.7.0"
+version = "1.8.0"
dependencies = [
"log",
"nebula_config_derive",
@@ -5213,7 +5213,7 @@ dependencies = [
[[package]]
name = "nebula_config_derive"
-version = "1.7.0"
+version = "1.8.0"
dependencies = [
"log",
"nebula_config",
@@ -5230,7 +5230,7 @@ version = "0.6.0"
[[package]]
name = "nebula_terminal"
-version = "1.7.0"
+version = "1.8.0"
dependencies = [
"base64",
"bitflags 2.13.0",
diff --git a/Cargo.toml b/Cargo.toml
index 454a063..d98a66b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,8 +17,8 @@ edition = "2024"
rust-version = "1.97.1"
[profile.release]
-# fat LTO 会用顶层 opt-level 重跑全程序 codegen,把下面的热路径 O3 钉子
-# 冲掉;thin + codegen-units=1 保住钉子,体积差距只有个位数百分点。
+# Thin LTO preserves package-specific optimization levels. Dependencies retain
+# one codegen unit; the application uses parallel codegen with the same O3 level.
lto = "thin"
debug = 0
strip = "symbols"
@@ -38,7 +38,7 @@ smol = { opt-level = 3 }
gpui = { opt-level = 3 }
gpui-component = { opt-level = 3 }
nebula_terminal = { opt-level = 3 }
-nebula = { opt-level = 3 }
+nebula = { opt-level = 3, codegen-units = 16 }
image = { opt-level = 3 }
# Debug 壳仍要承担真实终端负载:GPUI 布局/字体塑形和 VT 解析若以
diff --git a/docs/architecture-decisions.md b/docs/architecture-decisions.md
index bf67bb8..c9b7ca4 100644
--- a/docs/architecture-decisions.md
+++ b/docs/architecture-decisions.md
@@ -420,3 +420,36 @@ settings files.
- **Replacement condition:** Revisit the budgets or an OS-backed index only with
measured query latency, completeness and sustained allocation evidence. Do not
restore eager full-tree indexing to improve a synthetic latency number.
+
+## ADR-0014 — Parallel release validation with one product build graph
+
+- **Date:** 2026-09-14
+- **Context:** The 1.7.0 Windows release job took 41m28s despite a full dependency
+ cache hit. Its logs show three application test compilations (4m44s, 9m16s and
+ 4m07s), a 15m08s release build, and 4m16s of additional dependency compilation
+ during packaging. The user requested a slowest-job target of ten minutes.
+- **Decision:** Run the complete Rust workspace with the product interaction
+ feature enabled in one unfiltered invocation. Run native tests independently
+ from package construction; asset aggregation depends on both. Each native
+ platform still runs the complete Python helper and harness suites. Cache keys
+ preserve the existing platform namespace and retain workspace crates. Cargo
+ still validates source, profile and feature fingerprints before reuse.
+- **Product compilation:** The application keeps O3 and Thin LTO and uses 16
+ codegen units to parallelize its large translation unit. Other package settings
+ retain their existing values. Both Windows packagers call one explicit builder
+ for the product and its packaged hook, preserving the same feature graph.
+ Packaging still invokes Cargo and validates source freshness and binary identity.
+- **Contract clarification:** The old packaging test required the literal
+ `--workspace --exclude nebula`, rejecting a valid explicit selection of the two
+ shipped binaries. It now verifies the actual selected packages, binaries and
+ product feature, plus failure propagation and restoration of the caller's target.
+ No test filtering, freshness bypass, size-budget increase or dependency change
+ is part of this decision.
+- **Validation:** The release pipeline runs native tests, packaging fixtures,
+ package-size/identity checks and installed or mounted conformance on all four
+ platforms. Actual job timings determine whether the target is met; cache input
+ changes and first compilation must be reported separately. A configured timeout
+ or parallel scheduling alone is not evidence of a ten-minute successful build.
+- **Revisit condition:** Retain only changes whose complete CI run and package
+ checks pass. Reconsider codegen partitioning if artifact size or runtime
+ measurements regress, and remove redundant caches if restore/save cost grows.
diff --git a/docs/release-notes/v1.8.0.md b/docs/release-notes/v1.8.0.md
new file mode 100644
index 0000000..c402f79
--- /dev/null
+++ b/docs/release-notes/v1.8.0.md
@@ -0,0 +1,78 @@
+# Pebrel 1.8.0
+
+## English
+
+### Added
+
+- Added “Focus follows mouse” in Settings → Interaction, off by default, and “Dim inactive panes” in Settings → Appearance, on by default. Both preferences take effect immediately.
+- Added right-click actions to the Shell launcher for choosing the default Shell and, on Windows, opening the selected Shell inside a new administrator Pebrel window.
+- Added Connect, Edit, and Delete to SSH launcher context menus. Delete uses the existing confirmation and undo flow.
+- Added Trae CLI recognition and its tab icon, plus a dedicated Oh My Pi icon.
+
+### Fixed
+
+- Fixed Windows terminal focus consuming `Alt+F4` and `Alt+Space`. `Alt+F4` now uses the normal window-close flow, and `Alt+Space`, followed by `N`, uses the system menu to minimize the window.
+- Fixed the top Settings tab disappearing when switching to another tab. It now remains available until explicitly closed, including when tabs overflow or the tab layout changes.
+- Fixed `Alt+1–9` and `Ctrl+1–9` tab shortcuts losing priority to terminal input. They now work while a terminal or CLI has focus and respect custom shortcut changes without restarting.
+- Fixed WSL filename search failing when the directory path contains spaces or shell punctuation. Cancelling a search stops its own directory scan.
+- Aligned macOS native window controls with the sidebar and Settings buttons, and preserved their reserved space in the top tab layout. Window controls follow the system appearance. Contributed by [@WilliamWang1721](https://github.com/WilliamWang1721) in [#114](https://github.com/Kuddev/pebrel/pull/114).
+- Fixed the Git drawer retaining Chinese labels when the application resolves to English. Controls, history timestamps and application notices follow the selected language; switching languages preserves the commit draft and text selection. Contributed by [@gao-jian-bin](https://github.com/gao-jian-bin) in [#118](https://github.com/Kuddev/pebrel/pull/118).
+- Fixed explicitly configured terminal selection text colors being ignored. Themes without their own selection foreground preserve that setting; themes with an explicit foreground retain their precedence. Contributed by [@Aschenbath](https://github.com/Aschenbath) in [#125](https://github.com/Kuddev/pebrel/pull/125).
+
+### Improved
+
+- Reduced file browsing and filename-search memory use by starting recursive searches only when a query is entered, reusing a bounded cache and streaming paths beyond that cache. Repeated panel use releases obsolete results and cancels superseded searches. Case, whole-word and regular-expression options remain available, with visible feedback for incomplete searches and errors.
+- Reduced background-image memory use with bounded image loading and reuse while resizing the window. Replacing an image releases the previous resources; extended backgrounds retain their fit, alignment and text readability.
+- Replaced the low-resolution Claude Code icon with artwork exported from SVG at 1024 pixels, and prepared Agent icons at their display size for smoother tab edges.
+
+Windows packages include a Pebrel installer and portable ZIP. Linux x64 packages and macOS Apple Silicon/Intel DMGs retain their Preview designation. macOS requires version 14 or later. Molecular structure rendering remains disabled.
+
+## 中文
+
+### 新增
+
+- 新增:在“设置 → 交互”中加入“焦点跟随鼠标”,默认关闭;在“设置 → 外观”中加入“调暗非活动窗格”,默认开启。两项设置均即时生效。
+- 新增:Shell 启动菜单新增右键操作,可设为默认 Shell;Windows 下还可在新的管理员 Pebrel 窗口内打开所选 Shell。
+- 新增:SSH 启动菜单新增“连接、编辑、删除”右键操作;删除沿用已有的确认与撤销流程。
+- 新增: Trae CLI 识别与标签图标,并为 Oh My Pi 加入独立图标。
+
+### 修复
+
+- 修复: Windows 终端获得焦点时吞掉 `Alt+F4` 和 `Alt+Space` 的问题。`Alt+F4` 现在进入正常窗口关闭流程,`Alt+Space` 后按 `N` 可通过系统菜单最小化窗口。
+- 修复:顶部设置标签在切换到其他标签后消失的问题。现在只有主动关闭才会移除,标签溢出或切换标签布局时也会保留。
+- 修复: `Alt+1–9` 和 `Ctrl+1–9` 标签快捷键优先级低于终端输入的问题。终端或 CLI 获得焦点时仍可切换标签,自定义快捷键的修改也无需重启即可生效。
+- 修复:目录路径含空格或 Shell 特殊符号时 WSL 文件名搜索失败的问题;取消搜索会停止该次目录扫描。
+- 修复:对齐 macOS 原生窗口按钮与侧栏、设置按钮,并在顶部标签布局中保留窗口按钮所需空间;窗口按钮外观跟随系统。由 [@WilliamWang1721](https://github.com/WilliamWang1721) 在 [#114](https://github.com/Kuddev/pebrel/pull/114) 中贡献。
+- 修复:应用解析为英文时 Git 面板仍保留中文标签的问题。控件、历史时间和应用提示跟随所选语言,切换语言时保留提交草稿和文字选区。由 [@gao-jian-bin](https://github.com/gao-jian-bin) 在 [#118](https://github.com/Kuddev/pebrel/pull/118) 中贡献。
+- 修复:终端忽略用户明确设置的选中文字颜色的问题。未指定选中文字颜色的主题会保留该设置;已明确指定的主题仍保持自身优先级。由 [@Aschenbath](https://github.com/Aschenbath) 在 [#125](https://github.com/Kuddev/pebrel/pull/125) 中贡献。
+
+### 改进
+
+- 改进:降低文件浏览与文件名搜索的内存占用:输入关键词后才开始递归搜索,复用有容量上限的缓存,并流式查找缓存之外的路径。重复使用文件面板时释放过期结果、取消已被替代的搜索;保留大小写、整词和正则选项,并明确提示搜索未覆盖全部文件或发生错误。
+- 改进:降低背景图内存占用,限制图片加载成本,并在调整窗口大小时复用图像资源;替换背景图会释放旧资源,扩展背景仍保持原有的适配、对齐和文字可读性。
+- 改进:将 Claude Code 的低分辨率图标替换为从 SVG 导出的 1024 像素图像,并按显示尺寸处理 Agent 图标,使标签图标边缘更平滑。
+
+Windows 提供 Pebrel 安装器和 ZIP 便携包;Linux x64 包以及 macOS Apple Silicon/Intel DMG 继续标记为 Preview。macOS 最低运行版本为 14。分子结构渲染仍处于禁用状态。
+
+## Contributors
+
+

+
+**[@WilliamWang1721](https://github.com/WilliamWang1721)** - Aligned macOS native window controls and expanded native test coverage. / 对齐 macOS 原生窗口按钮,并扩展原生测试覆盖。([#114](https://github.com/Kuddev/pebrel/pull/114))
+
+**[@gao-jian-bin](https://github.com/gao-jian-bin)** - Made Git drawer language follow application preferences while preserving editing state. / 让 Git 面板语言跟随应用设置,同时保留编辑状态。([#118](https://github.com/Kuddev/pebrel/pull/118))
+
+**[@Aschenbath](https://github.com/Aschenbath)** - Preserved explicit terminal selection foreground colors. / 修正终端选中文字颜色的配置与主题优先级。([#125](https://github.com/Kuddev/pebrel/pull/125))
+
+
+---
+
+**SHA256**
+
+- `Pebrel-v1.8.0-windows-x64.zip`: `PENDING FINAL BUILD`
+- `Pebrel-v1.8.0-windows-x64-setup.exe`: `PENDING FINAL BUILD`
+- `Pebrel-v1.8.0-linux-x64-preview.AppImage`: `PENDING FINAL BUILD`
+- `Pebrel-v1.8.0-linux-x64-preview.deb`: `PENDING FINAL BUILD`
+- `Pebrel-v1.8.0-linux-x64-preview.tar.gz`: `PENDING FINAL BUILD`
+- `Pebrel-v1.8.0-macos-arm64-preview.dmg`: `PENDING FINAL BUILD`
+- `Pebrel-v1.8.0-macos-x64-preview.dmg`: `PENDING FINAL BUILD`
diff --git a/nebula-completions/Cargo.toml b/nebula-completions/Cargo.toml
index 75e2541..d550f62 100644
--- a/nebula-completions/Cargo.toml
+++ b/nebula-completions/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "nebula-completions"
-version = "1.7.0"
+version = "1.8.0"
edition.workspace = true
[features]
diff --git a/nebula_app/Cargo.toml b/nebula_app/Cargo.toml
index 451a293..93a8151 100644
--- a/nebula_app/Cargo.toml
+++ b/nebula_app/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "nebula"
-version = "1.7.0"
+version = "1.8.0"
license = "GPL-3.0-or-later"
description = "Pebrel — a GPU-accelerated terminal emulator"
readme = "README.md"
@@ -15,15 +15,15 @@ path = "src/main.rs"
[dependencies.nebula_terminal]
path = "../nebula_terminal"
-version = "1.7.0"
+version = "1.8.0"
[dependencies.nebula_config_derive]
path = "../nebula_config_derive"
-version = "1.7.0"
+version = "1.8.0"
[dependencies.nebula_config]
path = "../nebula_config"
-version = "1.7.0"
+version = "1.8.0"
# 可选:GPUI UI 层(feature = "gpui-shell",模块 src/gpui_shell/)。
# GPUI/component 的版本和 Git 来源由根 Cargo.toml 统一精确固定。
@@ -67,7 +67,7 @@ optional = true
[dependencies.nebula-completions]
path = "../nebula-completions"
-version = "1.7.0"
+version = "1.8.0"
[dependencies]
ahash = { version = "0.8.6", features = ["no-rng"] }
@@ -141,7 +141,7 @@ rusqlite = { version = "0.40.2", features = ["bundled"] }
sha1 = "0.11.0"
[build-dependencies]
-nebula-settings = { path = "../nebula_settings", version = "1.7.0" }
+nebula-settings = { path = "../nebula_settings", version = "1.8.0" }
gl_generator = { version = "0.14.0", optional = true }
serde = "1"
serde_json = "1"
diff --git a/nebula_app/windows/nebula.rc b/nebula_app/windows/nebula.rc
index e167b42..5ed706b 100644
--- a/nebula_app/windows/nebula.rc
+++ b/nebula_app/windows/nebula.rc
@@ -10,8 +10,8 @@ APP_MANIFEST RT_MANIFEST nebula.manifest
#endif
1 VERSIONINFO
-FILEVERSION 1,7,0,0
-PRODUCTVERSION 1,7,0,0
+FILEVERSION 1,8,0,0
+PRODUCTVERSION 1,8,0,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
@@ -24,11 +24,11 @@ BEGIN
BEGIN
VALUE "CompanyName", "Kuddev"
VALUE "FileDescription", "Pebrel"
- VALUE "FileVersion", "1.7.0"
+ VALUE "FileVersion", "1.8.0"
VALUE "InternalName", "nebula"
VALUE "OriginalFilename", "pebrel.exe"
VALUE "ProductName", "Pebrel"
- VALUE "ProductVersion", "1.7.0"
+ VALUE "ProductVersion", "1.8.0"
END
END
BLOCK "VarFileInfo"
diff --git a/nebula_config/Cargo.toml b/nebula_config/Cargo.toml
index dbd27a6..dc15094 100644
--- a/nebula_config/Cargo.toml
+++ b/nebula_config/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "nebula_config"
-version = "1.7.0"
+version = "1.8.0"
license = "GPL-3.0-or-later"
description = "Nebula configuration abstractions"
homepage = "https://github.com/Kuddev/pebrel"
@@ -14,5 +14,5 @@ serde = "1.0.163"
toml.workspace = true
[dev-dependencies]
-nebula_config_derive = { version = "1.7.0", path = "../nebula_config_derive" }
+nebula_config_derive = { version = "1.8.0", path = "../nebula_config_derive" }
serde = { version = "1.0.163", features = ["derive"] }
diff --git a/nebula_config_derive/Cargo.toml b/nebula_config_derive/Cargo.toml
index fc5d038..2828977 100644
--- a/nebula_config_derive/Cargo.toml
+++ b/nebula_config_derive/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "nebula_config_derive"
-version = "1.7.0"
+version = "1.8.0"
license = "GPL-3.0-or-later"
description = "Failure resistant deserialization derive"
homepage = "https://github.com/Kuddev/pebrel"
@@ -18,7 +18,7 @@ syn = { version = "2.0.16", features = ["derive", "parsing", "proc-macro", "prin
[dev-dependencies.nebula_config]
path = "../nebula_config"
-version = "1.7.0"
+version = "1.8.0"
[dev-dependencies]
log = "0.4.11"
diff --git a/nebula_settings/Cargo.toml b/nebula_settings/Cargo.toml
index 43cfcce..c7c29f3 100644
--- a/nebula_settings/Cargo.toml
+++ b/nebula_settings/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "nebula-settings"
-version = "1.7.0"
+version = "1.8.0"
license = "GPL-3.0-or-later"
description = "Shared reader for Nebula runtime user settings (nebula_settings.txt) and theme terminal-color tables"
publish = false
diff --git a/nebula_split/Cargo.toml b/nebula_split/Cargo.toml
index b1fa368..f57f9fe 100644
--- a/nebula_split/Cargo.toml
+++ b/nebula_split/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "nebula-split"
-version = "1.7.0"
+version = "1.8.0"
license = "GPL-3.0-or-later"
description = "Shared split-pane rules: layout tree, geometry, divider drag and directional focus"
publish = false
diff --git a/nebula_terminal/Cargo.toml b/nebula_terminal/Cargo.toml
index 8a40565..b712354 100644
--- a/nebula_terminal/Cargo.toml
+++ b/nebula_terminal/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "nebula_terminal"
-version = "1.7.0"
+version = "1.8.0"
license = "GPL-3.0-or-later"
description = "Nebula terminal emulation core"
readme = "../README.md"
diff --git a/scripts/build-installer.ps1 b/scripts/build-installer.ps1
index 2d3040c..55112b3 100644
--- a/scripts/build-installer.ps1
+++ b/scripts/build-installer.ps1
@@ -85,28 +85,7 @@ if (-not (Test-Path -LiteralPath $installerScript -PathType Leaf)) {
}
if (-not $SkipBuild) {
- Push-Location $repo
- $previousTargetDirectory = $env:CARGO_TARGET_DIR
- try {
- $env:CARGO_TARGET_DIR = $cargoTargetRoot
- $workspaceArgs = @('build', '--workspace', '--exclude', 'nebula', '--locked')
- $gpuiArgs = @('build', '-p', 'nebula', '--bin', 'pebrel', '--features', 'gpui-shell', '--locked')
- if ($Configuration -eq 'release') {
- $workspaceArgs += '--release'
- $gpuiArgs += '--release'
- }
- & cargo @workspaceArgs
- if ($LASTEXITCODE -ne 0) {
- throw "Cargo workspace build failed with exit code $LASTEXITCODE"
- }
- & cargo @gpuiArgs
- if ($LASTEXITCODE -ne 0) {
- throw "Cargo gpui-shell build failed with exit code $LASTEXITCODE"
- }
- } finally {
- $env:CARGO_TARGET_DIR = $previousTargetDirectory
- Pop-Location
- }
+ & (Join-Path $PSScriptRoot 'build-windows-product.ps1') -Configuration $Configuration -TargetDirectory $cargoTargetRoot
}
$missing = @($requiredFiles | Where-Object { -not (Test-Path -LiteralPath $_ -PathType Leaf) })
diff --git a/scripts/build-windows-product.ps1 b/scripts/build-windows-product.ps1
new file mode 100644
index 0000000..89367e2
--- /dev/null
+++ b/scripts/build-windows-product.ps1
@@ -0,0 +1,36 @@
+[CmdletBinding()]
+param(
+ [ValidateSet('debug', 'release')]
+ [string] $Configuration = 'release',
+ [string] $TargetDirectory
+)
+
+$ErrorActionPreference = 'Stop'
+Set-StrictMode -Version Latest
+$repo = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
+if ([string]::IsNullOrWhiteSpace($TargetDirectory)) {
+ $TargetDirectory = Join-Path $repo 'target'
+} elseif (-not [IO.Path]::IsPathRooted($TargetDirectory)) {
+ $TargetDirectory = Join-Path $repo $TargetDirectory
+}
+$previousTargetDirectory = $env:CARGO_TARGET_DIR
+Push-Location $repo
+try {
+ $env:CARGO_TARGET_DIR = [IO.Path]::GetFullPath($TargetDirectory)
+ # Keep the feature graph identical for the initial build, ZIP and installer.
+ # The acceptance lab is tested by CI but does not supply a packaged binary.
+ $arguments = @(
+ 'build', '--locked', '--timings',
+ '-p', 'nebula', '--bin', 'pebrel',
+ '-p', 'nebula_hook', '--bin', 'pebrel-hook',
+ '--features', 'nebula/gpui-shell'
+ )
+ if ($Configuration -eq 'release') { $arguments += '--release' }
+ & cargo @arguments
+ if ($LASTEXITCODE -ne 0) {
+ throw "Cargo Windows product build failed with exit code $LASTEXITCODE"
+ }
+} finally {
+ $env:CARGO_TARGET_DIR = $previousTargetDirectory
+ Pop-Location
+}
diff --git a/scripts/ci_native_tests.py b/scripts/ci_native_tests.py
new file mode 100644
index 0000000..8e5545b
--- /dev/null
+++ b/scripts/ci_native_tests.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+"""Run the complete native suite with one Rust workspace feature graph."""
+
+from __future__ import annotations
+
+import subprocess
+import sys
+
+
+def native_commands() -> list[list[str]]:
+ return [
+ [sys.executable, "-m", "unittest", "discover", "-s", "scripts/tests", "-v"],
+ [sys.executable, "-m", "unittest", "discover", "-s", "scripts/conformance/tests", "-v"],
+ [
+ "cargo", "test", "--locked", "--workspace",
+ "--features", "nebula/gpui-test-support", "--timings",
+ ],
+ ]
+
+
+def main() -> int:
+ for command in native_commands():
+ print("Running:", " ".join(command), flush=True)
+ subprocess.run(command, check=True)
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/scripts/installer.iss b/scripts/installer.iss
index f8a9fbb..6fc0299 100644
--- a/scripts/installer.iss
+++ b/scripts/installer.iss
@@ -1,9 +1,9 @@
-#ifndef AppVersion
- #define AppVersion "1.7.0"
+#ifndef AppVersion
+ #define AppVersion "1.8.0"
#endif
#ifndef NumericVersion
- #define NumericVersion "1.7.0.0"
+ #define NumericVersion "1.8.0.0"
#endif
#ifndef Configuration
diff --git a/scripts/package-release.ps1 b/scripts/package-release.ps1
index 400d7b8..671146d 100644
--- a/scripts/package-release.ps1
+++ b/scripts/package-release.ps1
@@ -144,33 +144,7 @@ function Assert-FreshBinaries {
}
if (-not $SkipBuild) {
- Push-Location $repo
- $previousTargetDirectory = $env:CARGO_TARGET_DIR
- try {
- $env:CARGO_TARGET_DIR = $cargoTargetRoot
- # Never build nebula without gpui-shell first: a workspace default
- # binary overwrites the product exe with the legacy winit shell.
- # Exclude nebula from the workspace build, then link GPUI last.
- if ($Configuration -eq 'release') {
- & cargo build --workspace --release --exclude nebula --locked
- if ($LASTEXITCODE -ne 0) {
- throw "Cargo workspace build failed with exit code $LASTEXITCODE"
- }
- & cargo build -p nebula --bin pebrel --release --features gpui-shell --locked
- } else {
- & cargo build --workspace --exclude nebula --locked
- if ($LASTEXITCODE -ne 0) {
- throw "Cargo workspace build failed with exit code $LASTEXITCODE"
- }
- & cargo build -p nebula --bin pebrel --features gpui-shell --locked
- }
- if ($LASTEXITCODE -ne 0) {
- throw "Cargo gpui-shell build failed with exit code $LASTEXITCODE"
- }
- } finally {
- $env:CARGO_TARGET_DIR = $previousTargetDirectory
- Pop-Location
- }
+ & (Join-Path $PSScriptRoot 'build-windows-product.ps1') -Configuration $Configuration -TargetDirectory $cargoTargetRoot
}
$missing = @($manifest.GetEnumerator() | Where-Object {
diff --git a/scripts/tests/build-windows-product.tests.ps1 b/scripts/tests/build-windows-product.tests.ps1
new file mode 100644
index 0000000..d236a97
--- /dev/null
+++ b/scripts/tests/build-windows-product.tests.ps1
@@ -0,0 +1,44 @@
+$ErrorActionPreference = 'Stop'
+Set-StrictMode -Version Latest
+$builder = Join-Path $PSScriptRoot '../build-windows-product.ps1'
+$originalTarget = $env:CARGO_TARGET_DIR
+$originalDirectory = (Get-Location).Path
+$global:ProductBuildCalls = @()
+$global:ProductBuildExit = 0
+function global:cargo {
+ $global:ProductBuildCalls += ,@($args)
+ $global:LASTEXITCODE = $global:ProductBuildExit
+}
+try {
+ $env:CARGO_TARGET_DIR = 'preserve-caller-target'
+ & $builder -Configuration release -TargetDirectory target
+ if ($global:ProductBuildCalls.Count -ne 1) { throw 'Expected one product build' }
+ $arguments = $global:ProductBuildCalls[0]
+ $packages = @(); $binaries = @()
+ for ($i = 0; $i -lt $arguments.Count - 1; $i++) {
+ if ($arguments[$i] -eq '-p') { $packages += $arguments[$i + 1] }
+ if ($arguments[$i] -eq '--bin') { $binaries += $arguments[$i + 1] }
+ }
+ if (($packages -join ',') -ne 'nebula,nebula_hook') { throw 'Unexpected package selection' }
+ if (($binaries -join ',') -ne 'pebrel,pebrel-hook') { throw 'Unexpected product binaries' }
+ foreach ($required in @('--locked', '--release', '--features', 'nebula/gpui-shell')) {
+ if ($required -notin $arguments) { throw "Missing product build argument: $required" }
+ }
+ if ('--workspace' -in $arguments) { throw 'Packaging must not build the acceptance lab' }
+ if ($env:CARGO_TARGET_DIR -ne 'preserve-caller-target') { throw 'Caller target changed' }
+ & $builder -Configuration debug -TargetDirectory target
+ if ('--release' -in $global:ProductBuildCalls[1]) { throw 'Debug build selected release' }
+ $global:ProductBuildExit = 27
+ $failed = $false
+ try { & $builder -Configuration release -TargetDirectory target } catch {
+ $failed = $_.Exception.Message -match 'exit code 27'
+ }
+ if (-not $failed) { throw 'Cargo failure must fail packaging' }
+ if ($env:CARGO_TARGET_DIR -ne 'preserve-caller-target') { throw 'Failure changed caller target' }
+ if ((Get-Location).Path -ne $originalDirectory) { throw 'Failure changed caller directory' }
+ Write-Output 'build-windows-product.tests.ps1: PASS'
+} finally {
+ $env:CARGO_TARGET_DIR = $originalTarget
+ Remove-Item Function:\cargo
+ Remove-Variable ProductBuildCalls,ProductBuildExit -Scope Global
+}
diff --git a/scripts/tests/package-release.tests.ps1 b/scripts/tests/package-release.tests.ps1
index 6226ccb..615aff3 100644
--- a/scripts/tests/package-release.tests.ps1
+++ b/scripts/tests/package-release.tests.ps1
@@ -38,15 +38,10 @@ try {
}
$scriptBody = Get-Content -LiteralPath $packageScript -Raw -Encoding UTF8
- if ($scriptBody -notmatch '--features gpui-shell') {
- throw 'Release packaging must rebuild Pebrel with --features gpui-shell so the zip ships the GPUI shell.'
- }
- if ($scriptBody -notmatch '--bin pebrel') {
- throw 'Release packaging must build the Pebrel product executable.'
- }
- if ($scriptBody -notmatch '--exclude nebula') {
- throw 'Release packaging must exclude nebula from the workspace build so the default-feature binary cannot overwrite the GPUI shell.'
+ if ($scriptBody -notmatch 'build-windows-product.ps1') {
+ throw 'Release packaging must use the shared explicit product build.'
}
+ & (Join-Path $PSScriptRoot 'build-windows-product.tests.ps1')
if ($scriptBody -notmatch 'Assert-FreshBinaries') {
throw 'Release packaging must refuse stale binaries (freshness guard missing).'
diff --git a/scripts/tests/test_ci_native_tests.py b/scripts/tests/test_ci_native_tests.py
new file mode 100644
index 0000000..4f25da8
--- /dev/null
+++ b/scripts/tests/test_ci_native_tests.py
@@ -0,0 +1,47 @@
+from __future__ import annotations
+
+import subprocess
+import unittest
+from unittest.mock import patch
+
+from scripts.ci_native_tests import main, native_commands
+
+
+class NativeSuiteTests(unittest.TestCase):
+ def test_full_workspace_and_interactions_share_one_unfiltered_invocation(self):
+ rust = [command for command in native_commands() if command[0] == "cargo"]
+ self.assertEqual(len(rust), 1)
+ command = rust[0]
+ self.assertEqual(command[1], "test")
+ self.assertIn("--locked", command)
+ self.assertIn("--workspace", command)
+ self.assertEqual(command[command.index("--features") + 1], "nebula/gpui-test-support")
+ self.assertNotIn("--exclude", command)
+ self.assertNotIn("--lib", command)
+ self.assertNotIn("--skip", command)
+ self.assertNotIn("--", command)
+
+ def test_both_python_test_roots_are_discovered(self):
+ suites = [command for command in native_commands() if "unittest" in command]
+ self.assertEqual(
+ {command[command.index("-s") + 1] for command in suites},
+ {"scripts/tests", "scripts/conformance/tests"},
+ )
+ self.assertTrue(all("discover" in command for command in suites))
+
+ def test_success_runs_every_command_and_checks_exit_codes(self):
+ with patch("scripts.ci_native_tests.subprocess.run") as run:
+ self.assertEqual(main(), 0)
+ self.assertEqual(run.call_count, len(native_commands()))
+ self.assertTrue(all(call.kwargs["check"] for call in run.call_args_list))
+
+ def test_failure_stops_the_suite_and_is_not_reported_as_success(self):
+ with patch("scripts.ci_native_tests.subprocess.run") as run:
+ run.side_effect = subprocess.CalledProcessError(7, "test")
+ with self.assertRaises(subprocess.CalledProcessError):
+ main()
+ self.assertEqual(run.call_count, 1)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/scripts/tests/test_stable_release.py b/scripts/tests/test_stable_release.py
index e73dd17..7dd1fd6 100644
--- a/scripts/tests/test_stable_release.py
+++ b/scripts/tests/test_stable_release.py
@@ -68,21 +68,17 @@ def notes(checksum_placeholder: bool = True) -> str:
class StableReleaseTests(unittest.TestCase):
- def test_stable_workflow_runs_gpui_interaction_tests_on_every_platform(self) -> None:
+ def test_stable_workflow_requires_full_native_tests_before_aggregation(self) -> None:
root = Path(__file__).resolve().parents[2]
workflow = (root / ".github/workflows/release.yml").read_text(encoding="utf-8")
- command = "cargo test --locked -p nebula --bin pebrel --features gpui-test-support gpui_shell::"
- self.assertEqual(workflow.count(command), 3)
- windows_step = workflow.split(" - name: Test workspace and native harness\n", 1)[1]
- windows_step = windows_step.split(" - name:", 1)[0]
- self.assertIn("shell: pwsh", windows_step)
- lines = [line.strip() for line in windows_step.splitlines()]
- commands = 0
- for index, line in enumerate(lines):
- if line.startswith(("cargo test ", "python -m unittest ")):
- commands += 1
- self.assertEqual(lines[index + 1], "if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }")
- self.assertEqual(commands, 5)
+ native = workflow.split(" native-tests:\n", 1)[1].split("\n linux:\n", 1)[0]
+ for platform in ("linux-x64", "windows-x64", "macos-arm64", "macos-x64"):
+ self.assertIn("platform: " + platform, native)
+ self.assertIn("run: python scripts/ci_native_tests.py", native)
+ self.assertNotIn("continue-on-error", native)
+ aggregate = workflow.split("\n aggregate:\n", 1)[1].split("\n publish:\n", 1)[0]
+ self.assertIn("needs: [prepare, native-tests, linux, macos, windows]", aggregate)
+ self.assertNotIn("always()", aggregate)
def test_native_packagers_expose_stable_channel_without_preview_id(self) -> None:
root = Path(__file__).resolve().parents[2]
diff --git a/tools/i18n-contract/Cargo.lock b/tools/i18n-contract/Cargo.lock
index fef745b..f055b79 100644
--- a/tools/i18n-contract/Cargo.lock
+++ b/tools/i18n-contract/Cargo.lock
@@ -16,7 +16,7 @@ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]]
name = "nebula-settings"
-version = "1.7.0"
+version = "1.8.0"
[[package]]
name = "pebrel-i18n-contract"