Skip to content

Commit 5d5b02f

Browse files
iamaeroplaneclaude
andcommitted
fix(extensions): drop alias pattern enforcement from _validate()
Aliases are intentionally free-form to preserve community extension compatibility (e.g. 'speckit.verify' short aliases used by spec-kit-verify and other existing extensions). This aligns _validate() with the intent of upstream commit 4deb90f (fix: restore alias compatibility, #2110/#2125). Only type and None-normalization checks remain for aliases. Pattern enforcement continues for primary command names only. Updated tests to verify free-form aliases pass through unchanged with no warnings instead of being auto-corrected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b82e39e commit 5d5b02f

2 files changed

Lines changed: 13 additions & 29 deletions

File tree

src/specify_cli/extensions.py

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -239,34 +239,22 @@ def _validate(self):
239239
"must follow pattern 'speckit.{extension}.{command}'"
240240
)
241241

242-
# Validate and auto-correct alias name formats
242+
# Validate alias types; no pattern enforcement on aliases — they are
243+
# intentionally free-form to preserve community extension compatibility
244+
# (e.g. 'speckit.verify' short aliases used by existing extensions).
243245
aliases = cmd.get("aliases")
244246
if aliases is None:
247+
cmd["aliases"] = []
245248
aliases = []
246249
if not isinstance(aliases, list):
247250
raise ValidationError(
248251
f"Aliases for command '{cmd['name']}' must be a list"
249252
)
250-
for i, alias in enumerate(aliases):
253+
for alias in aliases:
251254
if not isinstance(alias, str):
252255
raise ValidationError(
253256
f"Aliases for command '{cmd['name']}' must be strings"
254257
)
255-
if not EXTENSION_COMMAND_NAME_PATTERN.match(alias):
256-
corrected = self._try_correct_command_name(alias, ext["id"])
257-
if corrected:
258-
self.warnings.append(
259-
f"Alias '{alias}' does not follow the required pattern "
260-
f"'speckit.{{extension}}.{{command}}'. Registering as '{corrected}'. "
261-
f"The extension author should update the manifest to use this name."
262-
)
263-
rename_map[alias] = corrected
264-
aliases[i] = corrected
265-
else:
266-
raise ValidationError(
267-
f"Invalid alias '{alias}': "
268-
"must follow pattern 'speckit.{extension}.{command}'"
269-
)
270258

271259
# Rewrite any hook command references that pointed at a renamed command or
272260
# an alias-form ref (ext.cmd → speckit.ext.cmd). Always emit a warning when

tests/test_extensions.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,8 @@ def test_command_name_mismatched_namespace_not_corrected(self, temp_dir, valid_m
305305
with pytest.raises(ValidationError, match="Invalid command name"):
306306
ExtensionManifest(manifest_path)
307307

308-
def test_alias_autocorrect_speckit_prefix(self, temp_dir, valid_manifest_data):
309-
"""Test that a legacy 'speckit.command' alias is auto-corrected."""
308+
def test_alias_free_form_accepted(self, temp_dir, valid_manifest_data):
309+
"""Aliases are free-form — a 'speckit.command' alias must be accepted unchanged."""
310310
import yaml
311311

312312
valid_manifest_data["provides"]["commands"][0]["aliases"] = ["speckit.hello"]
@@ -317,10 +317,8 @@ def test_alias_autocorrect_speckit_prefix(self, temp_dir, valid_manifest_data):
317317

318318
manifest = ExtensionManifest(manifest_path)
319319

320-
assert manifest.commands[0]["aliases"] == ["speckit.test-ext.hello"]
321-
assert len(manifest.warnings) == 1
322-
assert "speckit.hello" in manifest.warnings[0]
323-
assert "speckit.test-ext.hello" in manifest.warnings[0]
320+
assert manifest.commands[0]["aliases"] == ["speckit.hello"]
321+
assert manifest.warnings == []
324322

325323
def test_valid_command_name_has_no_warnings(self, temp_dir, valid_manifest_data):
326324
"""Test that a correctly-named command produces no warnings."""
@@ -778,8 +776,8 @@ def test_install_rejects_extension_id_in_core_namespace(self, temp_dir, project_
778776
with pytest.raises(ValidationError, match="conflicts with core command namespace"):
779777
manager.install_from_directory(ext_dir, "0.1.0", register_commands=False)
780778

781-
def test_install_autocorrects_alias_without_extension_namespace(self, temp_dir, project_dir):
782-
"""Legacy short aliases are auto-corrected to 'speckit.{ext_id}.{cmd}' with a warning."""
779+
def test_install_accepts_free_form_alias(self, temp_dir, project_dir):
780+
"""Aliases are free-form — a short 'speckit.shortcut' alias must be preserved unchanged."""
783781
import yaml
784782

785783
ext_dir = temp_dir / "alias-shortcut"
@@ -812,10 +810,8 @@ def test_install_autocorrects_alias_without_extension_namespace(self, temp_dir,
812810
manager = ExtensionManager(project_dir)
813811
manifest = manager.install_from_directory(ext_dir, "0.1.0", register_commands=False)
814812

815-
assert manifest.commands[0]["aliases"] == ["speckit.alias-shortcut.shortcut"]
816-
assert len(manifest.warnings) == 1
817-
assert "speckit.shortcut" in manifest.warnings[0]
818-
assert "speckit.alias-shortcut.shortcut" in manifest.warnings[0]
813+
assert manifest.commands[0]["aliases"] == ["speckit.shortcut"]
814+
assert manifest.warnings == []
819815

820816
def test_install_rejects_namespace_squatting(self, temp_dir, project_dir):
821817
"""Install should reject commands and aliases outside the extension namespace."""

0 commit comments

Comments
 (0)