From 1699e324ae1fba4f2be758f0da449407a00a5f4b Mon Sep 17 00:00:00 2001 From: Hamed Rabah <26891088+hamedrabah@users.noreply.github.com> Date: Thu, 27 Aug 2026 17:43:38 -0700 Subject: [PATCH 1/2] fix: read feature.json as UTF-8 in PowerShell Assisted-by: Codex (model: GPT-5, autonomous) --- scripts/powershell/common.ps1 | 4 +-- tests/test_check_prerequisites_paths_only.py | 34 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/scripts/powershell/common.ps1 b/scripts/powershell/common.ps1 index 585e884702..bb61f623bb 100644 --- a/scripts/powershell/common.ps1 +++ b/scripts/powershell/common.ps1 @@ -135,7 +135,7 @@ function Save-FeatureJson { # Read current value and skip write when unchanged if (Test-Path -LiteralPath $fjPath -PathType Leaf) { try { - $raw = Get-Content -LiteralPath $fjPath -Raw + $raw = [System.IO.File]::ReadAllText($fjPath, [System.Text.Encoding]::UTF8) $cfg = $raw | ConvertFrom-Json if ($cfg.feature_directory -eq $FeatureDirectory) { return @@ -187,7 +187,7 @@ function Get-FeaturePathsEnv { Save-FeatureJson -RepoRoot $repoRoot -FeatureDirectory $env:SPECIFY_FEATURE_DIRECTORY } } elseif (Test-Path $featureJson) { - $featureJsonRaw = Get-Content -LiteralPath $featureJson -Raw + $featureJsonRaw = [System.IO.File]::ReadAllText($featureJson, [System.Text.Encoding]::UTF8) try { $featureConfig = $featureJsonRaw | ConvertFrom-Json } catch { diff --git a/tests/test_check_prerequisites_paths_only.py b/tests/test_check_prerequisites_paths_only.py index 3331cf92e4..abe12b6fd8 100644 --- a/tests/test_check_prerequisites_paths_only.py +++ b/tests/test_check_prerequisites_paths_only.py @@ -288,6 +288,40 @@ def test_ps_paths_only_succeeds_on_non_spec_branch(prereq_repo: Path) -> None: assert "FEATURE_DIR" in data +@pytest.mark.skipif( + not _WINDOWS_POWERSHELL, reason="Windows PowerShell 5.1 not available" +) +def test_windows_powershell_reads_bomless_utf8_feature_json( + prereq_repo: Path, +) -> None: + """Windows PowerShell must decode non-ASCII feature paths as UTF-8 (#4333).""" + feature_directory = "specs/001-后台信息架构" + feature_path = prereq_repo / feature_directory + feature_path.mkdir(parents=True) + _write_feature_json(prereq_repo, feature_directory) + + resolved_path = prereq_repo / "resolved-feature-path.txt" + common_ps = prereq_repo / ".specify" / "scripts" / "powershell" / "common.ps1" + ps_command = ( + f". '{common_ps}'; " + "$resolved = Get-FeaturePathsEnv -NoPersist; " + "$utf8NoBom = New-Object System.Text.UTF8Encoding($false); " + f"[System.IO.File]::WriteAllText('{resolved_path}', " + "[string]$resolved.FEATURE_DIR, $utf8NoBom)" + ) + result = subprocess.run( + [_WINDOWS_POWERSHELL, "-NoProfile", "-Command", ps_command], + cwd=prereq_repo, + capture_output=True, + text=True, + check=False, + env=_clean_env(), + ) + + assert result.returncode == 0, result.stderr + assert resolved_path.read_text(encoding="utf-8") == str(feature_path) + + @pytest.mark.skipif(not (HAS_PWSH or _WINDOWS_POWERSHELL), reason="no PowerShell available") @pytest.mark.parametrize( ("use_env_var", "specify_feature", "expected_branch"), From dc98fe5ef83028b8df05bd897e07bcb7fb778997 Mon Sep 17 00:00:00 2001 From: Hamed Rabah <26891088+hamedrabah@users.noreply.github.com> Date: Thu, 27 Aug 2026 17:54:27 -0700 Subject: [PATCH 2/2] test: write Unicode feature path as UTF-8 Assisted-by: Codex (model: GPT-5, autonomous) --- tests/test_check_prerequisites_paths_only.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_check_prerequisites_paths_only.py b/tests/test_check_prerequisites_paths_only.py index abe12b6fd8..dc2ee23f8f 100644 --- a/tests/test_check_prerequisites_paths_only.py +++ b/tests/test_check_prerequisites_paths_only.py @@ -38,7 +38,7 @@ def _write_feature_json( repo: Path, feature_directory: str = "specs/001-my-feature" ) -> None: (repo / ".specify" / "feature.json").write_text( - json.dumps({"feature_directory": feature_directory}), + json.dumps({"feature_directory": feature_directory}, ensure_ascii=False), encoding="utf-8", )