Stage 3: Standard markdown integrations — 19 agents migrated to plugin architecture (#2038)

* Stage 3: Standard markdown integrations — 19 agents migrated to plugin architecture

Migrate all standard markdown integrations to self-contained subpackages
under integrations/. Each subclasses MarkdownIntegration with config-only
overrides (~10 lines per __init__.py).

Integrations migrated (19):
claude, qwen, opencode, junie, kilocode, auggie, roo, codebuddy,
qodercli, amp, shai, bob, trae, pi, iflow, kiro-cli, windsurf,
vibe, cursor-agent

Changes:
- Create integrations/<key>/ subpackage with __init__.py and scripts/
  (update-context.sh, update-context.ps1) for each integration
- Register all 19 in INTEGRATION_REGISTRY (20 total with copilot)
- MarkdownIntegration.setup() processes templates (replaces {SCRIPT},
  {ARGS}, __AGENT__; strips frontmatter blocks; rewrites paths)
- Extract install_scripts() to IntegrationBase; refactor copilot to use it
- Generalize --ai auto-promote from copilot-only to registry-driven:
  any integration registered in INTEGRATION_REGISTRY auto-promotes.
  Unregistered agents (gemini, tabnine, codex, kimi, agy, generic)
  continue through the legacy --ai path unchanged.
- Fix cursor/cursor-agent key mismatch in CommandRegistrar.AGENT_CONFIGS
- Add missing vibe entry to CommandRegistrar.AGENT_CONFIGS
- Update kiro alias test to reflect auto-promote behavior

Testing:
- Per-agent test files (test_integration_<agent>.py) with shared mixin
- 1316 tests passing, 0 failures
- Complete file inventory tests for both sh and ps variants
- Byte-for-byte validated against v0.4.3 release packages (684 files)

* Address PR review: fix repo root detection and no-op test

- Fix repo root fallback in all 20 update-context.sh scripts: walk up
  from script location to find .specify/ instead of falling back to pwd
- Fix repo root fallback in all 20 update-context.ps1 scripts: walk up
  from script location to find .specify/ instead of falling back to $PWD
- Add assertions to test_setup_writes_to_correct_directory: verify
  expected_dir exists and all command files reside under it

* Fix REPO_ROOT priority: prefer .specify walk-up over git root

In monorepos the git toplevel may differ from the project root that
contains .specify/. The previous fix still preferred git rev-parse
over the walk-up result.

Bash scripts (20): prefer the discovered _root when it contains
.specify/; only accept git root if it also contains .specify/.

PowerShell scripts (20): validate git root contains .specify/ before
using it; fall back to walking up from script directory otherwise.

* Guard git call with try/catch in PowerShell scripts

With $ErrorActionPreference = 'Stop', an unguarded git rev-parse
throws a terminating CommandNotFoundException when git is not
installed, preventing the .specify walk-up fallback from running.

Wrap the git call in try/catch across all 20 update-context.ps1
scripts so the fallback works reliably without git.

* Rename hyphenated package dirs to valid Python identifiers

Rename kiro-cli → kiro_cli and cursor-agent → cursor_agent so the
packages can be imported with normal Python syntax instead of
importlib.  The user-facing integration key (IntegrationBase.key)
stays hyphenated to match the actual CLI tool / binary name.

Also reorganize _register_builtins(): imports and registrations
are now grouped alphabetically with clear section comments.

* Reuse CommandRegistrar path rewriting in process_template()

Replace the duplicated regex-based path rewriting in
MarkdownIntegration.process_template() with a call to the shared
CommandRegistrar._rewrite_project_relative_paths() implementation.

This ensures extension-local paths are preserved and boundary rules
stay consistent across the codebase.

* Promote _rewrite_project_relative_paths to public API

Rename CommandRegistrar._rewrite_project_relative_paths() to
rewrite_project_relative_paths() (drop leading underscore) so
integrations can call it without reaching into a private method
across subsystem boundaries.

Addresses PR review feedback:
https://github.com/github/spec-kit/pull/2038#discussion_r3022105627

* Broaden TestRegistrarKeyAlignment to cover all integration keys

Parametrize across ALL_INTEGRATION_KEYS instead of only checking
cursor-agent and vibe.  Keeps a separate negative test for the
stale 'cursor' shorthand.

Addresses PR review feedback:
https://github.com/github/spec-kit/pull/2038#discussion_r3022269032
This commit is contained in:
Manfred Riem
2026-04-01 09:17:21 -05:00
committed by GitHub
parent 3113b72d6f
commit 255371d367
88 changed files with 2113 additions and 61 deletions

View File

@@ -37,10 +37,57 @@ def get_integration(key: str) -> IntegrationBase | None:
# -- Register built-in integrations --------------------------------------
def _register_builtins() -> None:
"""Register all built-in integrations."""
from .copilot import CopilotIntegration
"""Register all built-in integrations.
Package directories use Python-safe identifiers (e.g. ``kiro_cli``,
``cursor_agent``). The user-facing integration key stored in
``IntegrationBase.key`` stays hyphenated (``"kiro-cli"``,
``"cursor-agent"``) to match the actual CLI tool / binary name that
users install and invoke.
"""
# -- Imports (alphabetical) -------------------------------------------
from .amp import AmpIntegration
from .auggie import AuggieIntegration
from .bob import BobIntegration
from .claude import ClaudeIntegration
from .codebuddy import CodebuddyIntegration
from .copilot import CopilotIntegration
from .cursor_agent import CursorAgentIntegration
from .iflow import IflowIntegration
from .junie import JunieIntegration
from .kilocode import KilocodeIntegration
from .kiro_cli import KiroCliIntegration
from .opencode import OpencodeIntegration
from .pi import PiIntegration
from .qodercli import QodercliIntegration
from .qwen import QwenIntegration
from .roo import RooIntegration
from .shai import ShaiIntegration
from .trae import TraeIntegration
from .vibe import VibeIntegration
from .windsurf import WindsurfIntegration
# -- Registration (alphabetical) --------------------------------------
_register(AmpIntegration())
_register(AuggieIntegration())
_register(BobIntegration())
_register(ClaudeIntegration())
_register(CodebuddyIntegration())
_register(CopilotIntegration())
_register(CursorAgentIntegration())
_register(IflowIntegration())
_register(JunieIntegration())
_register(KilocodeIntegration())
_register(KiroCliIntegration())
_register(OpencodeIntegration())
_register(PiIntegration())
_register(QodercliIntegration())
_register(QwenIntegration())
_register(RooIntegration())
_register(ShaiIntegration())
_register(TraeIntegration())
_register(VibeIntegration())
_register(WindsurfIntegration())
_register_builtins()