specify init does not copy templates/commands/ to .specify/templates/commands/ — wrap composition strategy fails
- Langage dominant
- Python
- Étoiles
- 137k
- Forks
- 12.3k
- Merge moyen
- 2 j 12 h
- PR mergées (30 j)
- 159
Description
## `specify init` does not copy `templates/commands/` to `.specify/templates/commands/`
### Problem
During `specify init`, the `install_shared_infra` function in `shared_infra.py` copies template files from the bundled `templates/` directory to `.specify/templates/`. However, it only processes **files** at the top level (`src.is_file()` check), skipping subdirectories — specifically `templates/commands/`.
This means the core command templates (e.g., `implement.md`, `specify.md`, `plan.md`, etc.) are installed directly to the agent directory (e.g., `.opencode/commands/speckit.implement.md`) via the integration system, but they are **not** kept in `.specify/templates/commands/` for the preset resolver to find.
### Impact
Preset authors who use the `wrap` composition strategy for command overrides (e.g., wrapping `speckit.implement` with a preamble) cannot resolve the core command as a base layer. The `PresetResolver.collect_all_layers()` method looks for core commands at:
```python
c = self.templates_dir / "commands" / f"{template_name}.md" # or stem fallback
```
Since `.specify/templates/commands/` doesn't exist after `specify init`, the resolver finds no base layer, composition fails, and the command is silently not registered (`registered_commands` stays empty `{}`).
### Reproduction
```bash
specify init --here --integration opencode --script sh --ignore-agent-tools
# .specify/templates/commands/ does NOT exist
# .opencode/commands/speckit.implement.md exists (installed by integration)
# Create a preset with a wrap strategy for speckit.implement
specify preset add --dev /path/to/my-preset
# registered_commands is {} — the wrap composition failed silently
```
### Workaround
Manually copy command templates after init:
```bash
mkdir -p .specify/templates/commands
cp /templates/commands/*.md .specify/templates/commands/
```
### Suggested fix
In `shared_infra.py`, the `install_shared_infra` function should also copy the `templates/commands/` subdirectory (with the same overwrite/manifest logic). Something like:
```python
# After the top-level template files loop:
commands_src = templates_src / "commands"
if commands_src.is_dir():
dest_commands = dest_templates / "commands"
if _ensure_or_bucket_dir(dest_commands):
for src_path in commands_src.iterdir():
if not src_path.is_file() or src_path.name.startswith("."):
continue
dst = dest_commands / src_path.name
rel = dst.relative_to(project_path).as_posix()
# ... same overwrite/manifest logic as above ...
```
Alternatively, the `PresetResolver` could fall back to reading core commands from the agent directory (e.g., `.opencode/commands/speckit.implement.md`) when `.specify/templates/commands/` doesn't have them.
### Environment
- Spec Kit v0.11.3
- macOS Darwin arm64
- Integration: opencode
Guide de contribution
Ouvrir le guide de contribution
Piste de recherche
Start in shared_infra.py at install_shared_infra and inspect how top-level templates are copied, then compare that with PresetResolver.collect_all_layers() and its templates/commands lookup. Reproduce with the provided specify init and preset commands; done means command templates are available under .specify/templates/commands/ and a wrap preset registers its composed command.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- python
- Domaine
- cli, tooling
- Type d'issue
- Bug
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Activité
- Active
- Clarté
- Clairement spécifiée
- Accessibilité débutants
- 74/100