Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/reference/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ specify version

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:

```bash
Expand Down
50 changes: 47 additions & 3 deletions src/specify_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1155,15 +1155,59 @@ def check():
if not any(agent_results.values()):
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()
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."""
import platform

show_banner()

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.add_column("Key", style="cyan", justify="right")
info_table.add_column("Value", style="white")
Expand Down
46 changes: 45 additions & 1 deletion tests/test_cli_version.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Tests for the --version CLI flag."""
"""Tests for CLI version reporting."""

import json
from unittest.mock import patch

from typer.testing import CliRunner
Expand Down Expand Up @@ -33,3 +34,46 @@ def test_version_flag_takes_precedence_over_subcommand(self):
result = runner.invoke(app, ["--version", "init"])
assert result.exit_code == 0
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
Loading