github / github/spec-kit

[Feature]: Add --json output to preset info and extension info with fully-expanded per-contribution detail (per-pack detail view; complements list --json summary counts)

Aperta
#4,213 11 commenti 0 reazioni 0 assegnatari Vedi su GitHub
enhancement feature-assess feature-go
Lingua principale
Python
Stelle
137k
Fork
12.3k
Merge medio
2g 12h
PR unite (30g)
159

Descrizione

### Problem Statement

Today `specify preset info ` and `specify extension info ` emit only text. `speckit-wizard-canvas` reads the raw `preset.yml` / `extension.yml` files with `js-yaml` and re-normalizes the shape itself in `composition/collect.mjs::parseProvidesEntries` and `::parseHookDeclarations` — including strategy inference from shorthand keys (`replaces` vs. `wraps` vs. `prepends` vs. `appends`), hook-phase normalization (`phase` vs. `trigger`, `command` vs. `targetCommand`), and script-runtime inference by globbing `scripts/{bash,powershell,python}/*.{sh,ps1,py}`. All of this is server-side data being reconstructed on the client.

Downstream consumers need the structured shape returned by the CLI itself so they can stop reconstructing it.

**How this differs from the companion `preset list --json` / `extension list --json` issue.** The `list` variant operates on **the collection of installed packs** and returns a **JSON array**, one row per pack, where `provides` is **just integer counts** (`{ commands: 4, templates: 2, scripts: 1, hooks: 3 }`) — a summary/catalog view suitable for "here's every preset the project has". `info` operates on **one pack, addressed by id**, and returns a **single JSON object** where `provides` is **fully expanded** — every command, template, script, and hook enumerated with its full per-contribution schema (`id`, `name`, `description`, `artifact`, `optional`, `handoffs`, `strategy`, `sourcePath`, `runtimes`, etc.). A wizard rendering "here's what `speckit.git` contributes to my project" needs the `info` detail; `list`'s counts are not enough. Both surfaces are required; neither is a subset of the other.

### Proposed Solution

Add `--json` to both `info` commands. Output shape:

```json
{
"id": "…", "name": "…", "description": "…", "version": "…",
"author": "…", "priority": 100, "enabled": true, "source": { "…": "…" },
"commands": [
{ "id": "…", "name": "speckit.plan", "description": "…",
"artifact": "specs/{feature}/plan.md", "optional": false,
"handoffs": [ { "to": "speckit.tasks", "when": "…", "message": "…" } ],
"strategy": "wrap",
"source": { "layer": "preset", "presetId": "…" },
"sourcePath": "commands/speckit.plan.md" }
],
"templates": [
{ "id": "…", "name": "…", "description": "…",
"strategy": "replace",
"source": { "…": "…" }, "sourcePath": "templates/…" }
],
"scripts": [
{ "id": "…", "name": "…", "description": "…",
"strategy": "replace",
"source": { "…": "…" }, "sourcePath": "scripts/bash/…",
"runtimes": ["bash", "powershell", "python"] }
],
"hooks": [
{ "id": "…", "name": "…", "description": "…",
"trigger": "before_speckit.plan", "targetCommand": "speckit.git.checklist",
"sourcePath": "commands/speckit.git.checklist.md",
"optional": false, "priority": 10 }
]
}
```

Notes:

- Preset objects omit `hooks`.
- Extension `commands`/`templates`/`scripts` entries omit `strategy` (they are always `replace`, per the replace-only rule enforced at `extensions/__init__.py:622-626`).
- `id` values use the stable-id scheme from the companion "stable id / lookupId" issue; the `id` on a per-contribution entry is what the companion `specify artifact info --json` stack's `lookupId` points at.
- `artifact`, `optional`, `handoffs` on commands come from the companion "artifact/optional/handoffs" issue.
- `runtimes` on scripts comes directly from the manifest (extensions post-#4010; add the same field to preset script entries for parity).
- All shorthand-key normalization (`replaces`/`wraps`/`prepends`/`appends` → `strategy: "replace"|"wrap"|"prepend"|"append"`) is done server-side.

### Alternatives Considered

- Fold everything into the companion `specify artifact info --json` command. Rejected — `artifact info` is per-artifact (walks one composition stack across all installed packs); `info --json` is per-source (walks one preset/extension across all its contributions). Both are needed and neither is a subset of the other.
- Fold everything into the companion `preset list --json` / `extension list --json`. Rejected — that surface is per-collection with summary counts; `info` is per-pack with full expansion. Different shape, different call pattern, different use cases (see Problem Statement).
- Emit YAML. Rejected — the whole point is to let the wizard drop `js-yaml`.
- Leave hook-phase / strategy shorthand un-normalized. Rejected — every consumer would reproduce the client-side logic from `composition/collect.mjs` and drift over time.

### Component

Specify CLI (initialization, commands)

### AI Agent (if applicable)

Not applicable

### Use Cases

1. `speckit-wizard-canvas` deletes `composition/collect.mjs::parseProvidesEntries` and `::parseHookDeclarations`, replacing them with `JSON.parse(execFileSync("specify", ["preset", "info", "", "--json"]))` / `specify extension info --json`. This is the change that removes the `js-yaml` dependency.
2. An IDE plugin renders hover-cards on command names by looking up the `commands[]` entry (description, `artifact`, `handoffs`).
3. A pre-commit check walks `extension info --json`'s `hooks[]` to warn when two extensions register the same `trigger` at the same `priority`.

### Acceptance Criteria

- [ ] `specify preset info --json` and `specify extension info --json` emit a single JSON object with top-level fields matching the companion `list --json` issue (`id`, `name`, `description`, `version`, `author`, `priority`, `enabled`, `source`) **plus** fully-expanded `commands`, `templates`, `scripts` arrays (and `hooks` for extensions) — not integer counts.
- [ ] Command entries include `artifact`, `optional`, `handoffs` (from the companion command-fields issue).
- [ ] Script entries include `runtimes` for both presets and extensions.
- [ ] Preset command/template/script entries include `strategy`; extension entries omit it (or set to `"replace"` for informational purposes).
- [ ] Shorthand keys (`replaces`/`wraps`/`prepends`/`appends`) are normalized server-side into `strategy`.
- [ ] Hook entries include `trigger`, `targetCommand`, `sourcePath`, `optional`, `priority` — `phase`/`command` shorthand normalized.
- [ ] All `id` values follow the stable-id scheme and are stable across reinstalls, matching the `lookupId` values emitted by `specify artifact info --json`.
- [ ] Unknown id → non-zero exit + stderr JSON error.
- [ ] Tests: schema round-trip, strategy normalization (all four shorthand forms), hook shorthand normalization, extension replace-only enforcement, handoffs frontmatter-merge, and `id` cross-reference with `specify artifact info --json` output.
- [ ] Docs: `preset info` / `extension info` sections in the CLI reference show the `--json` shape and normalization rules, plus a note contrasting `info --json` (per-pack, full expansion) with `list --json` (per-collection, count summary).

### Additional Context

Direct replacement for `plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/composition/collect.mjs::parseProvidesEntries` and `::parseHookDeclarations` in `github/spec-kit-copilot`. Depends on the companion "artifact/optional/handoffs" and "stable id / lookupId" issues; benefits from the companion "structured source provenance" issue.

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

Start with the `preset info --json` and `extension info --json` CLI entry points, then trace the existing normalization in `composition/collect.mjs::parseProvidesEntries` and `::parseHookDeclarations`; review `extensions/__init__.py:622-626` for replace-only behavior. Compare the output with the companion `list --json` and `artifact info --json` contracts. Done means the specified expanded schemas, stable IDs, normalization, errors, tests, and CLI reference documentation are complete.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
javascript, python
Ambito
cli, documentation, testing
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Attiva
Chiarezza
Abbastanza chiara
Idoneità per principianti
45/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.