mirror of
https://github.com/github/spec-kit.git
synced 2026-07-06 22:32:13 +08:00
* Stage 6: Complete migration — remove legacy scaffold path (#1924) Remove the legacy GitHub download and offline scaffold code paths. All 26 agents now use the integration system exclusively. Code removal (~1073 lines from __init__.py): - download_template_from_github(), download_and_extract_template() - scaffold_from_core_pack(), _locate_release_script() - install_ai_skills(), _get_skills_dir (restored slim version for presets) - _has_bundled_skills(), _migrate_legacy_kimi_dotted_skills() - AGENT_SKILLS_MIGRATIONS, _handle_agent_skills_migration() - _parse_rate_limit_headers(), _format_rate_limit_error() - Three-way branch in init() collapsed to integration-only Config derivation (single source of truth): - AGENT_CONFIG derived from INTEGRATION_REGISTRY (replaced 180-line dict) - CommandRegistrar.AGENT_CONFIGS derived from INTEGRATION_REGISTRY (replaced 160-line dict) - Backward-compat constants kept for presets/extensions: SKILL_DESCRIPTIONS, NATIVE_SKILLS_AGENTS, DEFAULT_SKILLS_DIR Release pipeline cleanup: - Deleted create-release-packages.sh/.ps1 (948 lines of ZIP packaging) - Deleted create-github-release.sh, generate-release-notes.sh - Deleted simulate-release.sh, get-next-version.sh, update-version.sh - Removed .github/workflows/scripts/ directory entirely - release.yml is now self-contained: check, notes, release all inlined - Install instructions use uv tool install with version tag Test cleanup: - Deleted test_ai_skills.py (tested removed functions) - Deleted test_core_pack_scaffold.py (tested removed scaffold) - Cleaned test_agent_config_consistency.py (removed 19 release-script tests) - Fixed test_branch_numbering.py (removed dead monkeypatches) - Updated auto-promote tests (verify files created, not tip messages) 1089 tests pass, 0 failures, ruff clean. * fix: resolve merge conflicts with #2051 (claude as skills) - Fix circular import: move CommandRegistrar import in claude integration to inside method bodies (was at module level) - Lazy-populate AGENT_CONFIGS via _ensure_configs() to avoid circular import at class definition time - Set claude registrar_config to .claude/commands (extension/preset target) since the integration handles .claude/skills in setup() - Update tests from #2051 to match: registrar_config assertions, remove --integration tip assertions, remove install_ai_skills mocks 1086 tests pass. * fix: properly preserve claude skills migration from #2051 Restore ClaudeIntegration.registrar_config to .claude/skills (not .claude/commands) so extension/preset registrations write to the correct skills directory. Update tests that simulate claude setup to use .claude/skills and check for SKILL.md layout. Some tests still need updating for the full skills path — 10 remaining failures from the #2051 test expectations around the extension/preset skill registration flow. WIP: 1076/1086 pass. * fix: properly handle SKILL.md paths in extension update rollback and tests Fix extension update rollback using _compute_output_name() for SKILL.md agents (converts dots to hyphens in skill directory names). Previously the backup and cleanup code constructed paths with raw command names (e.g. speckit.test-ext.hello/SKILL.md) instead of the correct computed names (speckit-test-ext-hello/SKILL.md). Test fixes for claude skills migration: - Update claude tests to use .claude/skills paths and SKILL.md layout - Use qwen (not claude) for skills-guard tests since claude's agent dir IS the skills dir — creating it triggers command registration - Fix test_extension_command_registered_when_extension_present to check skills path format 1086 tests pass, 0 failures, ruff clean. * fix: address PR review — lazy init, assertions, deprecated flags - _ensure_configs(): catch ImportError (not Exception), don't set _configs_loaded on failure so retries work - Move _ensure_configs() before unregister loop (not inside it) - Module-level try/except catches ImportError specifically - Remove tautology assertion (or True) in test_extensions.py - Strengthen preset provenance assertion to check source: field - Mark --offline, --skip-tls, --debug, --github-token as hidden deprecated no-ops in init() 1086 tests pass. * fix: remove deleted release scripts from pyproject.toml force-include Removes force-include entries for create-release-packages.sh/.ps1 which were deleted but still referenced in [tool.hatch.build].
256 lines
11 KiB
Python
256 lines
11 KiB
Python
"""Consistency checks for agent configuration across runtime surfaces."""
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
from specify_cli import AGENT_CONFIG, AI_ASSISTANT_ALIASES, AI_ASSISTANT_HELP
|
|
from specify_cli.extensions import CommandRegistrar
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
class TestAgentConfigConsistency:
|
|
"""Ensure kiro-cli migration stays synchronized across key surfaces."""
|
|
|
|
def test_runtime_config_uses_kiro_cli_and_removes_q(self):
|
|
"""AGENT_CONFIG should include kiro-cli and exclude legacy q."""
|
|
assert "kiro-cli" in AGENT_CONFIG
|
|
assert AGENT_CONFIG["kiro-cli"]["folder"] == ".kiro/"
|
|
assert AGENT_CONFIG["kiro-cli"]["commands_subdir"] == "prompts"
|
|
assert "q" not in AGENT_CONFIG
|
|
|
|
def test_extension_registrar_uses_kiro_cli_and_removes_q(self):
|
|
"""Extension command registrar should target .kiro/prompts."""
|
|
cfg = CommandRegistrar.AGENT_CONFIGS
|
|
|
|
assert "kiro-cli" in cfg
|
|
assert cfg["kiro-cli"]["dir"] == ".kiro/prompts"
|
|
assert "q" not in cfg
|
|
|
|
def test_extension_registrar_includes_codex(self):
|
|
"""Extension command registrar should include codex targeting .agents/skills."""
|
|
cfg = CommandRegistrar.AGENT_CONFIGS
|
|
|
|
assert "codex" in cfg
|
|
assert cfg["codex"]["dir"] == ".agents/skills"
|
|
assert cfg["codex"]["extension"] == "/SKILL.md"
|
|
|
|
def test_runtime_codex_uses_native_skills(self):
|
|
"""Codex runtime config should point at .agents/skills."""
|
|
assert AGENT_CONFIG["codex"]["folder"] == ".agents/"
|
|
assert AGENT_CONFIG["codex"]["commands_subdir"] == "skills"
|
|
|
|
def test_init_ai_help_includes_roo_and_kiro_alias(self):
|
|
"""CLI help text for --ai should stay in sync with agent config and alias guidance."""
|
|
assert "roo" in AI_ASSISTANT_HELP
|
|
for alias, target in AI_ASSISTANT_ALIASES.items():
|
|
assert alias in AI_ASSISTANT_HELP
|
|
assert target in AI_ASSISTANT_HELP
|
|
|
|
def test_devcontainer_kiro_installer_uses_pinned_checksum(self):
|
|
"""Devcontainer installer should always verify Kiro installer via pinned SHA256."""
|
|
post_create_text = (REPO_ROOT / ".devcontainer" / "post-create.sh").read_text(encoding="utf-8")
|
|
|
|
assert 'KIRO_INSTALLER_SHA256="7487a65cf310b7fb59b357c4b5e6e3f3259d383f4394ecedb39acf70f307cffb"' in post_create_text
|
|
assert "sha256sum -c -" in post_create_text
|
|
assert "KIRO_SKIP_KIRO_INSTALLER_VERIFY" not in post_create_text
|
|
|
|
def test_agent_context_scripts_use_kiro_cli(self):
|
|
"""Agent context scripts should advertise kiro-cli and not legacy q agent key."""
|
|
bash_text = (REPO_ROOT / "scripts" / "bash" / "update-agent-context.sh").read_text(encoding="utf-8")
|
|
pwsh_text = (REPO_ROOT / "scripts" / "powershell" / "update-agent-context.ps1").read_text(encoding="utf-8")
|
|
|
|
assert "kiro-cli" in bash_text
|
|
assert "kiro-cli" in pwsh_text
|
|
assert "Amazon Q Developer CLI" not in bash_text
|
|
assert "Amazon Q Developer CLI" not in pwsh_text
|
|
|
|
# --- Tabnine CLI consistency checks ---
|
|
|
|
def test_runtime_config_includes_tabnine(self):
|
|
"""AGENT_CONFIG should include tabnine with correct folder and subdir."""
|
|
assert "tabnine" in AGENT_CONFIG
|
|
assert AGENT_CONFIG["tabnine"]["folder"] == ".tabnine/agent/"
|
|
assert AGENT_CONFIG["tabnine"]["commands_subdir"] == "commands"
|
|
assert AGENT_CONFIG["tabnine"]["requires_cli"] is True
|
|
assert AGENT_CONFIG["tabnine"]["install_url"] is not None
|
|
|
|
def test_extension_registrar_includes_tabnine(self):
|
|
"""CommandRegistrar.AGENT_CONFIGS should include tabnine with correct TOML config."""
|
|
from specify_cli.extensions import CommandRegistrar
|
|
|
|
assert "tabnine" in CommandRegistrar.AGENT_CONFIGS
|
|
cfg = CommandRegistrar.AGENT_CONFIGS["tabnine"]
|
|
assert cfg["dir"] == ".tabnine/agent/commands"
|
|
assert cfg["format"] == "toml"
|
|
assert cfg["args"] == "{{args}}"
|
|
assert cfg["extension"] == ".toml"
|
|
|
|
def test_agent_context_scripts_include_tabnine(self):
|
|
"""Agent context scripts should support tabnine agent type."""
|
|
bash_text = (REPO_ROOT / "scripts" / "bash" / "update-agent-context.sh").read_text(encoding="utf-8")
|
|
pwsh_text = (REPO_ROOT / "scripts" / "powershell" / "update-agent-context.ps1").read_text(encoding="utf-8")
|
|
|
|
assert "tabnine" in bash_text
|
|
assert "TABNINE_FILE" in bash_text
|
|
assert "tabnine" in pwsh_text
|
|
assert "TABNINE_FILE" in pwsh_text
|
|
|
|
def test_ai_help_includes_tabnine(self):
|
|
"""CLI help text for --ai should include tabnine."""
|
|
assert "tabnine" in AI_ASSISTANT_HELP
|
|
|
|
# --- Kimi Code CLI consistency checks ---
|
|
|
|
def test_kimi_in_agent_config(self):
|
|
"""AGENT_CONFIG should include kimi with correct folder and commands_subdir."""
|
|
assert "kimi" in AGENT_CONFIG
|
|
assert AGENT_CONFIG["kimi"]["folder"] == ".kimi/"
|
|
assert AGENT_CONFIG["kimi"]["commands_subdir"] == "skills"
|
|
assert AGENT_CONFIG["kimi"]["requires_cli"] is True
|
|
|
|
def test_kimi_in_extension_registrar(self):
|
|
"""Extension command registrar should include kimi using .kimi/skills and SKILL.md."""
|
|
cfg = CommandRegistrar.AGENT_CONFIGS
|
|
|
|
assert "kimi" in cfg
|
|
kimi_cfg = cfg["kimi"]
|
|
assert kimi_cfg["dir"] == ".kimi/skills"
|
|
assert kimi_cfg["extension"] == "/SKILL.md"
|
|
|
|
def test_kimi_in_powershell_validate_set(self):
|
|
"""PowerShell update-agent-context script should include 'kimi' in ValidateSet."""
|
|
ps_text = (REPO_ROOT / "scripts" / "powershell" / "update-agent-context.ps1").read_text(encoding="utf-8")
|
|
|
|
validate_set_match = re.search(r"\[ValidateSet\(([^)]*)\)\]", ps_text)
|
|
assert validate_set_match is not None
|
|
validate_set_values = re.findall(r"'([^']+)'", validate_set_match.group(1))
|
|
|
|
assert "kimi" in validate_set_values
|
|
|
|
def test_ai_help_includes_kimi(self):
|
|
"""CLI help text for --ai should include kimi."""
|
|
assert "kimi" in AI_ASSISTANT_HELP
|
|
|
|
# --- Trae IDE consistency checks ---
|
|
|
|
def test_trae_in_agent_config(self):
|
|
"""AGENT_CONFIG should include trae with correct folder and commands_subdir."""
|
|
assert "trae" in AGENT_CONFIG
|
|
assert AGENT_CONFIG["trae"]["folder"] == ".trae/"
|
|
assert AGENT_CONFIG["trae"]["commands_subdir"] == "rules"
|
|
assert AGENT_CONFIG["trae"]["requires_cli"] is False
|
|
assert AGENT_CONFIG["trae"]["install_url"] is None
|
|
|
|
def test_trae_in_extension_registrar(self):
|
|
"""Extension command registrar should include trae using .trae/rules and markdown, if present."""
|
|
cfg = CommandRegistrar.AGENT_CONFIGS
|
|
|
|
assert "trae" in cfg
|
|
trae_cfg = cfg["trae"]
|
|
assert trae_cfg["format"] == "markdown"
|
|
assert trae_cfg["args"] == "$ARGUMENTS"
|
|
assert trae_cfg["extension"] == ".md"
|
|
|
|
def test_trae_in_agent_context_scripts(self):
|
|
"""Agent context scripts should support trae agent type."""
|
|
bash_text = (REPO_ROOT / "scripts" / "bash" / "update-agent-context.sh").read_text(encoding="utf-8")
|
|
pwsh_text = (REPO_ROOT / "scripts" / "powershell" / "update-agent-context.ps1").read_text(encoding="utf-8")
|
|
|
|
assert "trae" in bash_text
|
|
assert "TRAE_FILE" in bash_text
|
|
assert "trae" in pwsh_text
|
|
assert "TRAE_FILE" in pwsh_text
|
|
|
|
def test_trae_in_powershell_validate_set(self):
|
|
"""PowerShell update-agent-context script should include 'trae' in ValidateSet."""
|
|
ps_text = (REPO_ROOT / "scripts" / "powershell" / "update-agent-context.ps1").read_text(encoding="utf-8")
|
|
|
|
validate_set_match = re.search(r"\[ValidateSet\(([^)]*)\)\]", ps_text)
|
|
assert validate_set_match is not None
|
|
validate_set_values = re.findall(r"'([^']+)'", validate_set_match.group(1))
|
|
|
|
assert "trae" in validate_set_values
|
|
|
|
def test_ai_help_includes_trae(self):
|
|
"""CLI help text for --ai should include trae."""
|
|
assert "trae" in AI_ASSISTANT_HELP
|
|
|
|
# --- Pi Coding Agent consistency checks ---
|
|
|
|
def test_pi_in_agent_config(self):
|
|
"""AGENT_CONFIG should include pi with correct folder and commands_subdir."""
|
|
assert "pi" in AGENT_CONFIG
|
|
assert AGENT_CONFIG["pi"]["folder"] == ".pi/"
|
|
assert AGENT_CONFIG["pi"]["commands_subdir"] == "prompts"
|
|
assert AGENT_CONFIG["pi"]["requires_cli"] is True
|
|
assert AGENT_CONFIG["pi"]["install_url"] is not None
|
|
|
|
def test_pi_in_extension_registrar(self):
|
|
"""Extension command registrar should include pi using .pi/prompts."""
|
|
cfg = CommandRegistrar.AGENT_CONFIGS
|
|
|
|
assert "pi" in cfg
|
|
pi_cfg = cfg["pi"]
|
|
assert pi_cfg["dir"] == ".pi/prompts"
|
|
assert pi_cfg["format"] == "markdown"
|
|
assert pi_cfg["args"] == "$ARGUMENTS"
|
|
assert pi_cfg["extension"] == ".md"
|
|
|
|
def test_pi_in_powershell_validate_set(self):
|
|
"""PowerShell update-agent-context script should include 'pi' in ValidateSet."""
|
|
ps_text = (REPO_ROOT / "scripts" / "powershell" / "update-agent-context.ps1").read_text(encoding="utf-8")
|
|
|
|
validate_set_match = re.search(r"\[ValidateSet\(([^)]*)\)\]", ps_text)
|
|
assert validate_set_match is not None
|
|
validate_set_values = re.findall(r"'([^']+)'", validate_set_match.group(1))
|
|
|
|
assert "pi" in validate_set_values
|
|
|
|
def test_agent_context_scripts_include_pi(self):
|
|
"""Agent context scripts should support pi agent type."""
|
|
bash_text = (REPO_ROOT / "scripts" / "bash" / "update-agent-context.sh").read_text(encoding="utf-8")
|
|
pwsh_text = (REPO_ROOT / "scripts" / "powershell" / "update-agent-context.ps1").read_text(encoding="utf-8")
|
|
|
|
assert "pi" in bash_text
|
|
assert "Pi Coding Agent" in bash_text
|
|
assert "pi" in pwsh_text
|
|
assert "Pi Coding Agent" in pwsh_text
|
|
|
|
def test_ai_help_includes_pi(self):
|
|
"""CLI help text for --ai should include pi."""
|
|
assert "pi" in AI_ASSISTANT_HELP
|
|
|
|
# --- iFlow CLI consistency checks ---
|
|
|
|
def test_iflow_in_agent_config(self):
|
|
"""AGENT_CONFIG should include iflow with correct folder and commands_subdir."""
|
|
assert "iflow" in AGENT_CONFIG
|
|
assert AGENT_CONFIG["iflow"]["folder"] == ".iflow/"
|
|
assert AGENT_CONFIG["iflow"]["commands_subdir"] == "commands"
|
|
assert AGENT_CONFIG["iflow"]["requires_cli"] is True
|
|
|
|
def test_iflow_in_extension_registrar(self):
|
|
"""Extension command registrar should include iflow targeting .iflow/commands."""
|
|
cfg = CommandRegistrar.AGENT_CONFIGS
|
|
|
|
assert "iflow" in cfg
|
|
assert cfg["iflow"]["dir"] == ".iflow/commands"
|
|
assert cfg["iflow"]["format"] == "markdown"
|
|
assert cfg["iflow"]["args"] == "$ARGUMENTS"
|
|
|
|
def test_iflow_in_agent_context_scripts(self):
|
|
"""Agent context scripts should support iflow agent type."""
|
|
bash_text = (REPO_ROOT / "scripts" / "bash" / "update-agent-context.sh").read_text(encoding="utf-8")
|
|
pwsh_text = (REPO_ROOT / "scripts" / "powershell" / "update-agent-context.ps1").read_text(encoding="utf-8")
|
|
|
|
assert "iflow" in bash_text
|
|
assert "IFLOW_FILE" in bash_text
|
|
assert "iflow" in pwsh_text
|
|
assert "IFLOW_FILE" in pwsh_text
|
|
|
|
def test_ai_help_includes_iflow(self):
|
|
"""CLI help text for --ai should include iflow."""
|
|
assert "iflow" in AI_ASSISTANT_HELP
|