Skip to content

Commit d601a0c

Browse files
fix: classify dotted override-only artifacts as commands
Co-authored-by: nicolehaugen <10600161+nicolehaugen@users.noreply.github.com>
1 parent 04535be commit d601a0c

2 files changed

Lines changed: 23 additions & 1 deletion

File tree

‎src/specify_cli/artifacts/__init__.py‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,12 @@ def _iter_project_override_artifacts(
882882
reported as a command when some other layer already provides that
883883
command and as a template otherwise. That keeps a command override
884884
from also appearing as a second, spurious ``template:`` row.
885+
886+
A dotted name (``speckit.local``) is a command name under the
887+
resolver's own grammar (see ``_COMMAND_NAME_RE``) regardless of
888+
whether any lower, non-project layer backs it, so it is classified
889+
as a command even when the override is the only layer — matching
890+
the exact ID ``preset resolve``/``artifact info`` accepts for it.
885891
"""
886892
overrides_dir = resolver.overrides_dir
887893
if not overrides_dir.is_dir():
@@ -897,7 +903,8 @@ def _iter_project_override_artifacts(
897903
)
898904
for layer in command_layers
899905
)
900-
yield ("command" if backed_by_command else "template"), name, ""
906+
is_command = backed_by_command or bool(_COMMAND_NAME_RE.fullmatch(name))
907+
yield ("command" if is_command else "template"), name, ""
901908
scripts_dir = overrides_dir / "scripts"
902909
if not scripts_dir.is_dir():
903910
return

‎tests/test_artifact_command.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,21 @@ def test_project_override_only_artifact_is_listed(self, spec_kit_project: Path):
716716
info = catalog.get_artifact_info("local-template")
717717
assert info["stack"][0]["layer"] == "project"
718718

719+
def test_dotted_override_only_artifact_is_a_command(self, spec_kit_project: Path):
720+
overrides = spec_kit_project / ".specify" / "templates" / "overrides"
721+
overrides.mkdir(parents=True)
722+
(overrides / "speckit.local.md").write_text("body", encoding="utf-8")
723+
724+
catalog = ArtifactCatalog(spec_kit_project)
725+
ids = {row.id for row in catalog.list_artifacts()}
726+
assert "command:speckit.local" in ids
727+
assert "template:speckit.local" not in ids
728+
with pytest.raises(ArtifactNotFoundError):
729+
catalog.get_artifact_info("template:speckit.local")
730+
info = catalog.get_artifact_info("command:speckit.local")
731+
assert info["kind"] == "command"
732+
assert info["stack"][0]["layer"] == "project"
733+
719734
def test_unregistered_preset_template_without_manifest(self, spec_kit_project: Path):
720735
pack_dir = _install_preset(spec_kit_project, "legacy-preset", provides={"templates": []})
721736
preset_templates_dir = pack_dir / "templates"

0 commit comments

Comments
 (0)