feat: add version feature reporting (#2548)

This commit is contained in:
Pascal THUET
2026-05-14 19:52:14 +02:00
committed by GitHub
parent c1a1653aca
commit e6afba9429
3 changed files with 102 additions and 4 deletions

View File

@@ -77,6 +77,16 @@ specify version
Displays the Spec Kit CLI version, Python version, platform, and architecture. Displays the Spec Kit CLI version, Python version, platform, and architecture.
To inspect local CLI capabilities without checking the network:
```bash
specify version --features
specify version --features --json
```
The JSON form is intended for scripts and coding agents that need to choose a
workflow based on the installed CLI's supported features.
A quick version check is also available via: A quick version check is also available via:
```bash ```bash

View File

@@ -1155,15 +1155,59 @@ def check():
if not any(agent_results.values()): if not any(agent_results.values()):
console.print("[dim]Tip: Install a coding agent for the best experience[/dim]") console.print("[dim]Tip: Install a coding agent for the best experience[/dim]")
def _feature_capabilities() -> dict[str, bool]:
"""Return stable local CLI capability flags for humans and agents."""
return {
"controlled_multi_install_integrations": True,
"integration_use_command": True,
"multi_install_safe_registry_metadata": True,
"integration_upgrade_command": True,
"self_check_command": True,
"workflow_catalog": True,
"bundled_templates": True,
}
@app.command() @app.command()
def version(): def version(
features: bool = typer.Option(
False,
"--features",
help="Show local CLI feature capabilities.",
),
json_output: bool = typer.Option(
False,
"--json",
help="Emit feature capabilities as JSON. Requires --features.",
),
):
"""Display version and system information.""" """Display version and system information."""
import platform import platform
show_banner()
cli_version = get_speckit_version() cli_version = get_speckit_version()
if json_output and not features:
console.print("[red]Error:[/red] --json requires --features.")
raise typer.Exit(1)
if features:
capabilities = _feature_capabilities()
if json_output:
payload = {"version": cli_version, "features": capabilities}
console.print(json.dumps(payload, indent=2))
return
console.print(f"Spec Kit CLI: {cli_version}")
console.print()
console.print("Features:")
for key, enabled in capabilities.items():
label = key.replace("_", " ")
console.print(f"- {label}: {'yes' if enabled else 'no'}")
return
show_banner()
info_table = Table(show_header=False, box=None, padding=(0, 2)) info_table = Table(show_header=False, box=None, padding=(0, 2))
info_table.add_column("Key", style="cyan", justify="right") info_table.add_column("Key", style="cyan", justify="right")
info_table.add_column("Value", style="white") info_table.add_column("Value", style="white")

View File

@@ -1,5 +1,6 @@
"""Tests for the --version CLI flag.""" """Tests for CLI version reporting."""
import json
from unittest.mock import patch from unittest.mock import patch
from typer.testing import CliRunner from typer.testing import CliRunner
@@ -33,3 +34,46 @@ class TestVersionFlag:
result = runner.invoke(app, ["--version", "init"]) result = runner.invoke(app, ["--version", "init"])
assert result.exit_code == 0 assert result.exit_code == 0
assert "specify 0.7.2" in result.output assert "specify 0.7.2" in result.output
class TestVersionCommand:
"""Test the `specify version` subcommand."""
def test_version_features_text(self):
"""specify version --features prints local capability flags."""
with patch("specify_cli.get_speckit_version", return_value="1.2.3"):
result = runner.invoke(app, ["version", "--features"])
assert result.exit_code == 0
assert "Spec Kit CLI: 1.2.3" in result.output
assert "Features:" in result.output
assert "- controlled multi install integrations: yes" in result.output
assert "- integration use command: yes" in result.output
assert "- self check command: yes" in result.output
def test_version_features_json(self):
"""specify version --features --json prints machine-readable capabilities."""
with patch("specify_cli.get_speckit_version", return_value="1.2.3"):
result = runner.invoke(app, ["version", "--features", "--json"])
assert result.exit_code == 0
payload = json.loads(result.output)
assert payload == {
"version": "1.2.3",
"features": {
"controlled_multi_install_integrations": True,
"integration_use_command": True,
"multi_install_safe_registry_metadata": True,
"integration_upgrade_command": True,
"self_check_command": True,
"workflow_catalog": True,
"bundled_templates": True,
},
}
def test_version_json_requires_features(self):
"""specify version --json is rejected until a JSON surface exists."""
result = runner.invoke(app, ["version", "--json"])
assert result.exit_code != 0
assert "--json requires --features" in result.output