From ab9c70262d7426af03dd32e1b05f731148938d78 Mon Sep 17 00:00:00 2001 From: Quratulain-bilal Date: Wed, 29 Apr 2026 20:12:04 +0500 Subject: [PATCH] fix: include --from git+... in upgrade hint to avoid PyPI squat package (#2411) The compatibility-error messages in extensions.py and presets.py, plus the extension troubleshooting guide, told users to upgrade with: uv tool install specify-cli --force Without `--from git+https://github.com/github/spec-kit.git`, uv resolves `specify-cli` from PyPI, where an unrelated package with the same name (no author, no project URLs) ships a stub CLI that lacks `extension`, `preset`, and most spec-kit commands. Users following the upgrade hint land on the squat package and report "extension command removed" (see #1982). Reuse the existing `REINSTALL_COMMAND` constant in extensions.py and import it from presets.py so all three call sites point at the GitHub source. The doc fix also adds a one-line note explaining the PyPI collision so the same advice doesn't get re-stripped later. Refs #1982 --- extensions/EXTENSION-DEVELOPMENT-GUIDE.md | 2 +- src/specify_cli/extensions.py | 2 +- src/specify_cli/presets.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/EXTENSION-DEVELOPMENT-GUIDE.md b/extensions/EXTENSION-DEVELOPMENT-GUIDE.md index dfc112522..42ce2d71d 100644 --- a/extensions/EXTENSION-DEVELOPMENT-GUIDE.md +++ b/extensions/EXTENSION-DEVELOPMENT-GUIDE.md @@ -669,7 +669,7 @@ hooks: **Error**: `Extension requires spec-kit >=0.2.0` -- **Fix**: Update spec-kit with `uv tool install specify-cli --force` +- **Fix**: Update spec-kit with `uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git`. The bare `specify-cli` package on PyPI is a different, unrelated project — installing it without `--from git+...` will give you a stub CLI that does not include `extension`, `preset`, or other spec-kit commands. **Error**: `Command file not found` diff --git a/src/specify_cli/extensions.py b/src/specify_cli/extensions.py index a419ebf1d..761b7f31e 100644 --- a/src/specify_cli/extensions.py +++ b/src/specify_cli/extensions.py @@ -1108,7 +1108,7 @@ class ExtensionManager: raise CompatibilityError( f"Extension requires spec-kit {required}, " f"but {speckit_version} is installed.\n" - f"Upgrade spec-kit with: uv tool install specify-cli --force" + f"Upgrade spec-kit with: {REINSTALL_COMMAND}" ) except InvalidSpecifier: raise CompatibilityError(f"Invalid version specifier: {required}") diff --git a/src/specify_cli/presets.py b/src/specify_cli/presets.py index 27054a77f..690d1c51f 100644 --- a/src/specify_cli/presets.py +++ b/src/specify_cli/presets.py @@ -27,7 +27,7 @@ import yaml from packaging import version as pkg_version from packaging.specifiers import SpecifierSet, InvalidSpecifier -from .extensions import ExtensionRegistry, normalize_priority +from .extensions import REINSTALL_COMMAND, ExtensionRegistry, normalize_priority def _substitute_core_template( @@ -576,7 +576,7 @@ class PresetManager: raise PresetCompatibilityError( f"Preset requires spec-kit {required}, " f"but {speckit_version} is installed.\n" - f"Upgrade spec-kit with: uv tool install specify-cli --force" + f"Upgrade spec-kit with: {REINSTALL_COMMAND}" ) except InvalidSpecifier: raise PresetCompatibilityError(