Skip to content

Commit e6afba9

Browse files
authored
feat: add version feature reporting (#2548)
1 parent c1a1653 commit e6afba9

3 files changed

Lines changed: 102 additions & 4 deletions

File tree

docs/reference/core.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,16 @@ specify version
7777

7878
Displays the Spec Kit CLI version, Python version, platform, and architecture.
7979

80+
To inspect local CLI capabilities without checking the network:
81+
82+
```bash
83+
specify version --features
84+
specify version --features --json
85+
```
86+
87+
The JSON form is intended for scripts and coding agents that need to choose a
88+
workflow based on the installed CLI's supported features.
89+
8090
A quick version check is also available via:
8191

8292
```bash

src/specify_cli/__init__.py

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,15 +1155,59 @@ def check():
11551155
if not any(agent_results.values()):
11561156
console.print("[dim]Tip: Install a coding agent for the best experience[/dim]")
11571157

1158+
1159+
def _feature_capabilities() -> dict[str, bool]:
1160+
"""Return stable local CLI capability flags for humans and agents."""
1161+
return {
1162+
"controlled_multi_install_integrations": True,
1163+
"integration_use_command": True,
1164+
"multi_install_safe_registry_metadata": True,
1165+
"integration_upgrade_command": True,
1166+
"self_check_command": True,
1167+
"workflow_catalog": True,
1168+
"bundled_templates": True,
1169+
}
1170+
1171+
11581172
@app.command()
1159-
def version():
1173+
def version(
1174+
features: bool = typer.Option(
1175+
False,
1176+
"--features",
1177+
help="Show local CLI feature capabilities.",
1178+
),
1179+
json_output: bool = typer.Option(
1180+
False,
1181+
"--json",
1182+
help="Emit feature capabilities as JSON. Requires --features.",
1183+
),
1184+
):
11601185
"""Display version and system information."""
11611186
import platform
11621187

1163-
show_banner()
1164-
11651188
cli_version = get_speckit_version()
11661189

1190+
if json_output and not features:
1191+
console.print("[red]Error:[/red] --json requires --features.")
1192+
raise typer.Exit(1)
1193+
1194+
if features:
1195+
capabilities = _feature_capabilities()
1196+
if json_output:
1197+
payload = {"version": cli_version, "features": capabilities}
1198+
console.print(json.dumps(payload, indent=2))
1199+
return
1200+
1201+
console.print(f"Spec Kit CLI: {cli_version}")
1202+
console.print()
1203+
console.print("Features:")
1204+
for key, enabled in capabilities.items():
1205+
label = key.replace("_", " ")
1206+
console.print(f"- {label}: {'yes' if enabled else 'no'}")
1207+
return
1208+
1209+
show_banner()
1210+
11671211
info_table = Table(show_header=False, box=None, padding=(0, 2))
11681212
info_table.add_column("Key", style="cyan", justify="right")
11691213
info_table.add_column("Value", style="white")

tests/test_cli_version.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
"""Tests for the --version CLI flag."""
1+
"""Tests for CLI version reporting."""
22

3+
import json
34
from unittest.mock import patch
45

56
from typer.testing import CliRunner
@@ -33,3 +34,46 @@ def test_version_flag_takes_precedence_over_subcommand(self):
3334
result = runner.invoke(app, ["--version", "init"])
3435
assert result.exit_code == 0
3536
assert "specify 0.7.2" in result.output
37+
38+
39+
class TestVersionCommand:
40+
"""Test the `specify version` subcommand."""
41+
42+
def test_version_features_text(self):
43+
"""specify version --features prints local capability flags."""
44+
with patch("specify_cli.get_speckit_version", return_value="1.2.3"):
45+
result = runner.invoke(app, ["version", "--features"])
46+
47+
assert result.exit_code == 0
48+
assert "Spec Kit CLI: 1.2.3" in result.output
49+
assert "Features:" in result.output
50+
assert "- controlled multi install integrations: yes" in result.output
51+
assert "- integration use command: yes" in result.output
52+
assert "- self check command: yes" in result.output
53+
54+
def test_version_features_json(self):
55+
"""specify version --features --json prints machine-readable capabilities."""
56+
with patch("specify_cli.get_speckit_version", return_value="1.2.3"):
57+
result = runner.invoke(app, ["version", "--features", "--json"])
58+
59+
assert result.exit_code == 0
60+
payload = json.loads(result.output)
61+
assert payload == {
62+
"version": "1.2.3",
63+
"features": {
64+
"controlled_multi_install_integrations": True,
65+
"integration_use_command": True,
66+
"multi_install_safe_registry_metadata": True,
67+
"integration_upgrade_command": True,
68+
"self_check_command": True,
69+
"workflow_catalog": True,
70+
"bundled_templates": True,
71+
},
72+
}
73+
74+
def test_version_json_requires_features(self):
75+
"""specify version --json is rejected until a JSON surface exists."""
76+
result = runner.invoke(app, ["version", "--json"])
77+
78+
assert result.exit_code != 0
79+
assert "--json requires --features" in result.output

0 commit comments

Comments
 (0)