Stage 5: Skills, Generic & Option-Driven Integrations (#1924) (#2052)

* Stage 5: Skills, Generic & Option-Driven Integrations (#1924)

Add SkillsIntegration base class and migrate codex, kimi, agy, and
generic to the integration system.

Integrations:
- SkillsIntegration(IntegrationBase) in base.py — creates
  speckit-<name>/SKILL.md layout matching release ZIP output byte-for-byte
- CodexIntegration — .agents/skills/, --skills default=True
- KimiIntegration — .kimi/skills/, --skills + --migrate-legacy options,
  dotted→hyphenated skill directory migration
- AgyIntegration — .agent/skills/, skills-only (commands deprecated v1.20.5)
- GenericIntegration — user-specified --commands-dir, MarkdownIntegration
- All four have update-context.sh/.ps1 scripts
- All four registered in INTEGRATION_REGISTRY

CLI changes:
- --ai <agent> auto-promotes to integration path for all registered agents
- Interactive agent selection also auto-promotes (bug fix)
- --ai-skills and --ai-commands-dir show deprecation notices on integration path
- Next-steps display shows correct skill invocation syntax for skills integrations
- agy added to CommandRegistrar.AGENT_CONFIGS

Tests:
- test_integration_base_skills.py — reusable mixin with setup, frontmatter,
  directory structure, scripts, CLI auto-promote, and complete file inventory
  (sh+ps) tests
- Per-agent test files: test_integration_{codex,kimi,agy,generic}.py
- Kimi legacy migration tests, generic --commands-dir validation
- Registry updated with Stage 5 keys
- Removed 9 dead-mock tests, moved 4 integration tests to proper locations
- Fixed all bare project-name tests to use tmp_path
- Fixed 6 pre-existing ANSI escape code test failures in test_extensions.py
  and test_presets.py

1524 tests pass, 0 failures.

* fix: remove unused variable flagged by ruff (F841)

* fix: address PR review — integration-type-aware deprecation messages and early generic validation

- --ai-skills deprecation message now distinguishes SkillsIntegration
  ("skills are the default") from command-based integrations ("has no effect")
- --ai-commands-dir validation for generic runs even when auto-promoted,
  giving clear CLI error instead of late ValueError from setup()
- Resolves review comments from #2052

* fix: address PR review round 2

- Remove unused SKILL_DESCRIPTIONS dict from base.py (dead code after
  switching to template descriptions for ZIP parity)
- Narrow YAML parse catch from Exception to yaml.YAMLError
- Remove unused shutil import from test_integration_kimi.py
- Remove unused _REGISTRAR_EXEMPT class attr from test_registry.py
- Reword --ai-commands-dir deprecation to be actionable
- Update generic validation error to mention both --ai and --integration

* fix: address PR review round 3

- Clarify parsed_options forwarding is intentional (all options passed,
  integrations decide what to use)
- Extract _strip_ansi() helper in test_extensions.py and test_presets.py
- Remove unused pytest import (test_cli.py), unused locals (test_integration_base_skills.py)
- Reword --ai-commands-dir deprecation to be actionable without referencing
  the not-yet-implemented --integration-options

* fix: address PR review round 4

- Reorder kimi migration: run super().setup() first so hyphenated
  targets exist, then migrate dotted dirs (prevents user content loss)
- Move _strip_ansi() to shared tests/conftest.py, import from there
  in test_extensions.py, test_presets.py, test_ai_skills.py
- Remove now-unused re imports from all three test files

* fix: address PR review round 5

- Use write_bytes() for LF-only newlines (no CRLF on Windows)
- Add --integration-options CLI parameter — raw string passed through
  to the integration via opts['raw_options']; the integration owns
  parsing of its own options
- GenericIntegration.setup() reads --commands-dir from raw_options
  when not in parsed_options (supports --integration-options="...")
- Skip early --ai-commands-dir validation when --integration-options
  is provided (integration validates in its own setup())
- Remove parse_integration_options from core — integrations parse
  their own options

* fix: address PR review round 6

- GenericIntegration is now stateless: removed self._commands_dir
  instance state, overrides setup() directly to compute destination
  from parsed_options/raw_options on the stack
- commands_dest() raises by design (stateless singleton)
- _quote() in SkillsIntegration now escapes backslashes and double
  quotes to produce valid YAML even with special characters

* fix: address PR review round 7

- Support --commands-dir=value form in raw_options parsing (not just
  --commands-dir value with space separator)
- Normalize CRLF to LF in write_file_and_record() before encoding
- Persist ai_skills=True in init-options.json when using a
  SkillsIntegration, so extensions/presets emit SKILL.md overrides
  correctly even without explicit --ai-skills flag
This commit is contained in:
Manfred Riem
2026-04-02 08:00:12 -05:00
committed by GitHub
parent b44ffc0101
commit 4f9d966beb
28 changed files with 1777 additions and 414 deletions

View File

@@ -46,17 +46,21 @@ def _register_builtins() -> None:
users install and invoke.
"""
# -- Imports (alphabetical) -------------------------------------------
from .agy import AgyIntegration
from .amp import AmpIntegration
from .auggie import AuggieIntegration
from .bob import BobIntegration
from .claude import ClaudeIntegration
from .codex import CodexIntegration
from .codebuddy import CodebuddyIntegration
from .copilot import CopilotIntegration
from .cursor_agent import CursorAgentIntegration
from .gemini import GeminiIntegration
from .generic import GenericIntegration
from .iflow import IflowIntegration
from .junie import JunieIntegration
from .kilocode import KilocodeIntegration
from .kimi import KimiIntegration
from .kiro_cli import KiroCliIntegration
from .opencode import OpencodeIntegration
from .pi import PiIntegration
@@ -70,17 +74,21 @@ def _register_builtins() -> None:
from .windsurf import WindsurfIntegration
# -- Registration (alphabetical) --------------------------------------
_register(AgyIntegration())
_register(AmpIntegration())
_register(AuggieIntegration())
_register(BobIntegration())
_register(ClaudeIntegration())
_register(CodexIntegration())
_register(CodebuddyIntegration())
_register(CopilotIntegration())
_register(CursorAgentIntegration())
_register(GeminiIntegration())
_register(GenericIntegration())
_register(IflowIntegration())
_register(JunieIntegration())
_register(KilocodeIntegration())
_register(KimiIntegration())
_register(KiroCliIntegration())
_register(OpencodeIntegration())
_register(PiIntegration())