Skip to content

fix(powershell): treat bracketed project paths literally in create-new-feature - #5399

Merged
mnriem merged 2 commits into
github:mainfrom
adityajai119:fix/5398-powershell-bracketed-repo-path
Nov 12, 2026
Merged

mnriem merged 2 commits into
github:mainfrom
adityajai119:fix/5398-powershell-bracketed-repo-path

Conversation

@adityajai119

@adityajai119 adityajai119 commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Description

Fixes #5398.

In a project whose path contains [ or ] (for example app [v2]), scripts/powershell/create-new-feature.ps1 reads the brackets as wildcards because it passes the project path to Set-Location, Test-Path and Get-ChildItem without -LiteralPath:

  • Set-Location $repoRoot fails with "Cannot find path ... because it does not exist", so the script exits 1 before creating anything. The Python helper creates the feature in the same project.
  • Get-HighestNumberFromSpecs (Test-Path $SpecsDir, Get-ChildItem -Path $SpecsDir) sees no existing feature directories, so a new feature is numbered 001 again next to an existing 001-*.
  • $needsSpec = -not (Test-Path -PathType Leaf $specFile) reports an existing spec.md as missing, so -AllowExistingBranch on an existing feature rewrites its spec.md.

This PR switches those four calls to -LiteralPath. New-Item -Path already treats its path literally, so it is unchanged. #4956 and #4970 fixed bracketed feature directories and #5396 covers the template lookup in common.ps1; neither changes this script, and the two PRs do not overlap. With only this PR, a bracketed project gets a correctly numbered feature, but spec.md starts empty with the existing "Spec template not found" warning until #5396 lands. With both applied, spec.md gets the template.

Testing

  • Tested locally with .\.venv\Scripts\specify.exe --help
  • Ran relevant existing tests with .\.venv\Scripts\python.exe -m pytest tests -q, using the affected test paths: tests/test_create_new_feature_python_parity.py and tests/test_timestamp_branches.py give 54 passed, 191 skipped (the skips are the bash cases, which skip on this Windows machine)
  • Tested with a sample project (if applicable)

New test test_powershell_handles_bracketed_repo_path in tests/test_create_new_feature_python_parity.py runs the PowerShell and Python helpers in projects named ps [v2] and py [v2] that already contain specs/001-login-page/spec.md. It checks that both helpers exit 0 and name the new feature 002-payment-export, and that -AllowExistingBranch -Number 1 -ShortName login-page keeps the existing spec.md byte for byte (the test writes it with CRLF line endings and compares raw bytes). It runs on Windows PowerShell 5.1.26100 here (POWERSHELL_EXE resolves to powershell.exe, since pwsh is not installed):

  • on main: fails at the PowerShell exit code (Set-Location : Cannot find path ...);
  • with only the numbering lines reverted: fails with '001-payment-export' == '002-payment-export';
  • with only the $needsSpec line reverted: fails with b'' == b'# My spec\r\n\r\nKeep this.\r\n' (the existing spec.md is emptied);
  • with this PR: passes.

Sample project (Windows PowerShell 5.1): specify init 'app [v2]' --integration codex --script ps --ignore-agent-tools --non-interactive from v1.4.0, plus specs\001-login-page. Running .\.specify\scripts\powershell\create-new-feature.ps1 -Json 'Add payment export' fails at Set-Location with the shipped script, and prints 002-payment-export with exit 0 with this change.

Also ran uvx ruff@0.15.0 check src tests (all checks passed) and git diff --check (clean), and parsed the changed script with the Windows PowerShell 5.1 parser (no errors).

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (fill in the disclosure below)

AI disclosure: OpenCode with Claude Opus 5.5 (max reasoning effort, autonomous agent mode), acting on behalf of @adityajai119, found and reproduced the bug, wrote the fix and the test, ran the checks above, and drafted this description. Both commits carry an Assisted-by: OpenCode (model: Claude Opus 5.5, autonomous) trailer.

…w-feature

create-new-feature.ps1 passed the project path to Set-Location, Test-Path
and Get-ChildItem without -LiteralPath, so brackets in that path were read
as wildcards: the script stopped at Set-Location, numbered a new feature
001 again, and treated an existing spec.md as missing under
-AllowExistingBranch.

Fixes github#5398

Assisted-by: OpenCode (model: Claude Opus 5.5, autonomous)
@adityajai119
adityajai119 requested a review from mnriem as a code owner November 12, 2026 07:24
Copilot AI dynamic review requested due to automatic review settings November 12, 2026 07:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The regression test does not verify byte-for-byte preservation because read_text() normalizes line endings, leaving an active test-coverage issue.

1 open issue
What changed in this PR

This pull request fixes PowerShell feature creation when project paths contain square brackets by treating those paths literally during navigation, numbering, and specification detection.

Changes:

  • Uses -LiteralPath for project navigation, specs enumeration, and existing spec.md checks.
  • Adds PowerShell/Python parity coverage for bracketed project paths, feature numbering, and existing-spec preservation.
  • The preservation assertion currently compares decoded text rather than raw bytes.
File Description
tests/​test_create_new_feature_python_parity.py Adds regression coverage for bracketed repository paths, feature numbering, and preservation of an existing specification.
scripts/​powershell/​create-new-feature.ps1 Uses literal path handling for repository navigation, feature discovery, and existing specification checks.

Review effort: Lite (auto)

read_text() translates line endings, so the check could not tell a
preserved spec.md from one rewritten with different newlines. Write
the existing spec with CRLF line endings and compare raw bytes.

Assisted-by: OpenCode (model: Claude Opus 5.5, autonomous)
Copilot AI dynamic review requested due to automatic review settings November 12, 2026 08:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active issues were identified, and the change includes targeted regression coverage for bracketed paths, sequential numbering, and preservation of existing specifications.

No open issues 🎉

1 resolved since last review

Review effort: Lite (auto)

@mnriem mnriem added the triage-can-wait Verdict: valid and in-scope but deprioritized; held behind the evidence gate label Nov 12, 2026
@mnriem
mnriem requested a dynamic review from Copilot November 12, 2026 16:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active issues were identified, and the changes include literal-path handling plus regression coverage for bracketed project paths, feature numbering, and specification preservation.

No open issues 🎉

Review effort: Lite (auto)

@mnriem
mnriem merged commit 2ee2b1e into github:main Nov 12, 2026
14 checks passed
@mnriem

mnriem commented Nov 12, 2026

Copy link
Copy Markdown
Collaborator

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage-can-wait Verdict: valid and in-scope but deprioritized; held behind the evidence gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: create-new-feature.ps1 fails in a project whose path contains square brackets

3 participants