SIGN IN SIGN UP
github / spec-kit UNCLAIMED

💫 Toolkit to help you get started with Spec-Driven Development

0 0 17 Python

Add `specify integration` subcommand for post-init integration management (#2083)

* Initial plan

* Add specify integration subcommand (list, install, uninstall, switch)

Implements the `specify integration` subcommand group for managing
integrations in existing projects after initial setup:

- `specify integration list` — shows available integrations and installed status
- `specify integration install <key>` — installs an integration into existing project
- `specify integration uninstall [key]` — hash-safe removal preserving modified files
- `specify integration switch <target>` — uninstalls current, installs target

Follows the established `specify <noun> <verb>` CLI pattern used by
extensions and presets. Shared infrastructure (scripts, templates) is
preserved during uninstall and switch operations.

Agent-Logs-Url: https://github.com/github/spec-kit/sessions/1cca6c84-3e12-465d-88b8-a646d3504f63

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>

* Address review feedback: extract helper, fix return type annotation

- Extract _update_init_options_for_integration() to deduplicate init-options
  update logic between install and switch commands
- Fix _parse_integration_options return type to dict[str, Any] | None

Agent-Logs-Url: https://github.com/github/spec-kit/sessions/1cca6c84-3e12-465d-88b8-a646d3504f63

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>

* Potential fix for pull request finding 'Unused import'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Address review feedback: validate script type, handle --flag=value, fix metadata cleanup

- Add _normalize_script_type() to validate script type against SCRIPT_TYPE_CHOICES
- Handle --name=value syntax in _parse_integration_options()
- Clear init-options.json keys in no-manifest uninstall early-return path
- Clear stale metadata between switch teardown and install phases
- Add 5 tests covering the new edge cases

* Block --force with different integration, persist script type in init-options

- --force on install now rejects overwriting a different integration; users must
  use 'specify integration switch' instead
- _update_init_options_for_integration() now accepts and persists script_type
- Fix misleading test docstring for switch metadata test
- Add test_force_blocked_with_different_integration

* Remove --force from integration install, ensure shared infra on install/switch

- Remove --force parameter entirely from integration install; users must
  uninstall before reinstalling to prevent orphaned files
- Auto-install shared infrastructure (.specify/scripts/, .specify/templates/)
  when missing during install or switch
- Add test for shared infra creation on bare project install

* Remove redundant installed_key != key check

The == key case already returns above, so the != key guard is always true
at this point. Simplify to just 'if installed_key:'.

* Run shared infra unconditionally, defer metadata removal in switch

- Call _install_shared_infra() unconditionally on install and switch since it
  merges without overwriting existing files
- Remove premature metadata cleanup between switch phases; metadata is now
  only updated after successful Phase 2 install

* Add install rollback, graceful manifest errors, clear switch metadata

- Attempt teardown rollback on install/switch failure to avoid orphaned files
- Catch ValueError/FileNotFoundError on IntegrationManifest.load() in uninstall
  with user-friendly recovery guidance
- Clear metadata immediately after switch teardown so failed Phase 2 doesn't
  leave stale references to the removed integration

* Log rollback failures instead of silently suppressing them

* Handle corrupt manifest in switch, distinguish unknown vs missing manifest

- Wrap IntegrationManifest.load() in switch with ValueError/FileNotFoundError
  handling, matching the pattern used in uninstall
- Split else branch to report 'unknown integration' vs 'no manifest' separately

* Clean up metadata on rollback, broaden init-options match in uninstall

- Remove integration.json in install/switch rollback paths so failed installs
  don't leave stale metadata
- Match on both 'integration' and 'ai' keys when clearing init-options.json
  during uninstall to handle partially-written metadata

* Fix recovery guidance for unreadable manifests, fix type annotations

- Recovery instructions now guide users through delete manifest → uninstall →
  reinstall workflow that actually works
- Type annotations for optional CLI parameters changed from str to str | None

* Allow manifest-only uninstall for unknown/removed integrations

- Uninstall no longer requires the integration to be in the registry; falls back
  to manifest.uninstall() directly when get_integration() returns None
- Switch Phase 1 similarly uses manifest-only uninstall for unknown integrations
  instead of skipping teardown, preventing orphaned files

* Fail fast on corrupt integration.json, validate integration options

- _read_integration_json() now exits with an actionable error when
  integration.json exists but is corrupt/unreadable
- _parse_integration_options() rejects unknown options, validates flag usage,
  and requires values for non-flag options

* Validate integration.json is a dict, fail fast on missing manifest in switch

- _read_integration_json() validates parsed JSON is a dict, not a list/string
- Switch fails fast with recovery guidance when manifest is missing instead
  of silently skipping teardown and risking co-existing integration files

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
C
Copilot committed
94ba857b78074024f095b08b45802e17d2bff653
Parent: e1ab4f0
Committed by GitHub <noreply@github.com> on 4/3/2026, 10:35:04 PM