Files
spec-kit/src/specify_cli/_agent_config.py
T
e9ffc9d8e7 feat: allow overriding default init integration via SPECKIT_INTEGRATION_DEFAULT (#3952)
* feat: allow overriding default init integration via SPECKIT_INTEGRATION_DEFAULT

Resolve the non-interactive/init default integration from the
SPECKIT_INTEGRATION_DEFAULT environment variable, fitting the existing
SPECKIT_INTEGRATION_* namespace. Falls back to the hardcoded "copilot"
default when unset, and warns to stderr (rather than silently falling
back) when the value is not a registered integration key.

Wires the resolver into specify init (interactive prompt default and
non-interactive fallback), the init workflow step, and the bundle init
default. Adds unit and CLI tests and documents the variable.

Closes #3939

Assisted-by: GitHub Copilot (model: claude-opus-4.8, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: eecda55f-fa13-42f7-99bf-bfb0bb8565a0

* test: cover env-var default wiring for picker, workflow step, and bundle

Address PR review: add regression tests so each SPECKIT_INTEGRATION_DEFAULT
wiring site cannot silently revert to the hardcoded constant.

- init.py: interactive picker receives the resolved key as default_key.
- workflow init step: no step/workflow default + env var drives output
  integration and argv.
- bundle _resolve_init_integration: env-var default applies when unspecified,
  while explicit override and manifest-declared integration still win.

Assisted-by: GitHub Copilot (model: claude-opus-4.8, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: eecda55f-fa13-42f7-99bf-bfb0bb8565a0

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: eecda55f-fa13-42f7-99bf-bfb0bb8565a0
2026-08-03 12:20:49 -05:00

57 lines
2.0 KiB
Python

"""Agent configuration constants derived from the integration registry."""
from __future__ import annotations
import os
import sys
from typing import Any
def _build_agent_config() -> dict[str, dict[str, Any]]:
from .integrations import INTEGRATION_REGISTRY
config: dict[str, dict[str, Any]] = {}
for key, integration in INTEGRATION_REGISTRY.items():
if integration.config:
config[key] = dict(integration.config)
return config
AGENT_CONFIG: dict[str, dict[str, Any]] = _build_agent_config()
DEFAULT_INIT_INTEGRATION = "copilot"
#: Environment variable used to override the fallback integration that
#: ``specify init`` selects in non-interactive sessions. Follows the existing
#: ``SPECKIT_INTEGRATION_*`` namespace (see ``SPECKIT_INTEGRATION_<KEY>_EXECUTABLE``
#: and ``SPECKIT_INTEGRATION_CATALOG_URL``).
DEFAULT_INIT_INTEGRATION_ENV_VAR = "SPECKIT_INTEGRATION_DEFAULT"
def resolve_default_init_integration() -> str:
"""Return the default init integration, honoring an env-var override.
Reads :data:`DEFAULT_INIT_INTEGRATION_ENV_VAR`
(``SPECKIT_INTEGRATION_DEFAULT``). When it names a registered integration
key, that key is returned; otherwise the hardcoded
:data:`DEFAULT_INIT_INTEGRATION` (``"copilot"``) is used. An invalid value
emits a warning to stderr rather than silently falling back, so operators
can tell a typo from an intentional default.
"""
override = (os.environ.get(DEFAULT_INIT_INTEGRATION_ENV_VAR) or "").strip()
if not override:
return DEFAULT_INIT_INTEGRATION
if override in AGENT_CONFIG:
return override
print(
f"Warning: {DEFAULT_INIT_INTEGRATION_ENV_VAR}='{override}' is not a "
f"recognized integration; falling back to '{DEFAULT_INIT_INTEGRATION}'. "
f"Choose from: {', '.join(sorted(AGENT_CONFIG.keys()))}.",
file=sys.stderr,
)
return DEFAULT_INIT_INTEGRATION
SCRIPT_TYPE_CHOICES: dict[str, str] = {
"sh": "POSIX Shell (bash/zsh)",
"ps": "PowerShell",
"py": "Python",
}