Files
spec-kit/tests
e79fa25f3f Fix: scaffold self-contained namespaced preset commands (#4076) (#4082)
* Fix: scaffold self-contained namespaced preset commands (#4076)

Preset command templates named `speckit.<ns>.<cmd>` were silently dropped
whenever `.specify/extensions/<ns>/` was absent, while `speckit.<cmd>`
always scaffolded. The `_extension_installed_for_command` guard filtered
purely on name shape, conflating "override of an installed extension's
command" with "a preset shipping its own namespaced command." Because a
`type: command` template always ships its own body, such a command is
self-contained and must scaffold like any short-named command.

Remove the name-shape guard at all four call sites (registration, both
reconciliation passes, and skills). The reconciliation loop already skips
names that resolve to no layers (`if not layers: continue`), and the
composed-None branch still cleans up commands whose base layer disappeared.
Convert the command-mode "no base layer to compose onto" hard error into a
warn + skip, matching the existing behavior in _reconcile_composed_commands
so command-mode install and reconciliation stay consistent.

Update the two tests that encoded the old drop behavior to assert the new
consistent-scaffold contract, and add coverage proving 2-part and 3-part
preset commands scaffold identically with no extension installed.

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cfc4f1ce-6acb-465a-aa7b-999f2e4197fb

* Skip uncomposable commands in skills mode too (PR #4082 review)

When _register_commands skips an uncomposable composition command (a
wrap/prepend/append with no base layer to compose onto — e.g. the command
it wraps comes from an uninstalled extension), install still passed the
full manifest to _register_skills. For a command-backed integration in
skills mode, _register_skills created the missing skill and fell back to
the raw preset body because no `.composed` file existed, materializing a
broken SKILL.md — a literal `{CORE_TEMPLATE}` for wrap, or just the
preset's own fragment for prepend/append. Previously the raise in
_register_commands aborted before skills ran, so this never surfaced.

Make _register_skills apply the same skip: for a composition-strategy
command with no `.composed` file, resolve the stack and skip when no base
exists (resolve_content is None). The skip is silent because
_register_commands already warned for the same command in the same pass.

Add a regression test proving an uncomposable wrap command renders no skill
and never leaks a literal {CORE_TEMPLATE} in skills mode.

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cfc4f1ce-6acb-465a-aa7b-999f2e4197fb

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cfc4f1ce-6acb-465a-aa7b-999f2e4197fb
2026-08-13 09:04:39 -05:00
..