Repository navigation
Conversation
Assisted-by: Claude Code (model: Claude Opus 5, autonomous)
`specify integration uninstall` tore down the integration files but left the extension and preset commands and skills registered for that agent, and when it promoted another integration to default it did not register the enabled extensions and presets for it, unlike `use` and `switch`. github#4862 added both steps for catalog-installed adapters in the `external_lifecycle` wrapper only. Do them in the uninstall command for every integration, including the no-manifest path, and drop the wrapper copy so external adapters do not run them twice. Assisted-by: Claude Code (model: Claude Opus 5, autonomous)
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
specify integration uninstall <agent>removes the integration's own files but leaves the extension and preset commands and skills registered for that agent. When the uninstalled integration was the default, it also promotes another integration without registering the enabled extensions and presets for it.useandswitchboth do these steps;uninstalldid not. Reproduction with the bundledgitextension:Presets go the same way: with the bundled
leanpreset installed, uninstalling claude leaves five of its override skills in.claude/skills/, and gemini keeps the core commands instead of the preset's.#4862 added these two steps for catalog-installed adapters only, inside the
external_lifecyclewrapper. That wrapper returns before its transaction when no external adapter is involved, so built-in integrations never reached them. This PR does them in the uninstall command itself, for every integration and also on the "no manifest" path, using the same helpers (the fallback messages are the wrapper's; the cleanup messages followswitch). It drops the wrapper's copy, which would otherwise run the steps a second time for external adapters. The integrations reference now describes the behaviour under Uninstall.Behaviour notes: the extensions and presets stay installed; only the files registered for the removed agent go. As with
switch, an extension command file the user edited is removed with its agent.Testing
test_uninstall_unregisters_extension_artifacts: the extension skill and its registry entry are gone after uninstall. Onmain:Extension skill should be removed with its agent.test_uninstall_default_registers_extensions_for_fallback, run with and without the integration manifest: the promoted default gets the extension skill. Onmain:Promoted default should receive enabled extensions(both cases).test_uninstall_non_default_preserves_default_extension_artifacts: uninstalling a non-default integration leaves the default's extension files and registry entry in place.test_command_uninstall.py: 14 passed.tests/specify_cli/integrations/withouttest_installed_adapters.py: 387 passed.tests/specify_cli/integrations/test_installed_adapters.py(external adapters, the path the wrapper steps were removed from): 668 passed.leanpreset, against this branch:.claude/holds no files afterwards,.gemini/commands/speckit.git.*.tomlexist, and gemini's commands come fromlean.Equivalent local checks: tests ran with
.venv/bin/python -m pytestand the CLI with the venv'sspecify, on macOS.AI Disclosure
AI disclosure: This contribution was produced by Claude Code running autonomously on behalf of @Chaoqi31. An audit agent (Claude Fable 5.1, max reasoning effort) found the bug and wrote a failing reproduction. A fix agent (Claude Opus 5, xhigh effort) wrote the fix, tests and docs sentence. A separate review agent (Claude Fable 5.1, max reasoning effort) checked the branch, and the orchestrating agent (Claude Opus 5) reran the CLI reproductions and wrote the commits and this description. AI generated the code, tests and text. No human reviewed the diff line by line before submission.