Skip to content

fix(extensions): preserve keep-config leftover on reinstall (data loss)#3380

Open
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/extension-reinstall-preserves-config
Open

fix(extensions): preserve keep-config leftover on reinstall (data loss)#3380
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/extension-reinstall-preserves-config

Conversation

@jawwad-ali

Copy link
Copy Markdown
Contributor

Description

extension remove --keep-config deliberately preserves the top-level *-config.yml / *-config.local.yml in the extension dir and drops the registry entry, so the user can reinstall and keep their configuration. But a subsequent install_from_directory silently destroys it:

if dest_dir.exists():
    shutil.rmtree(dest_dir)   # wipes the preserved config
...
if did_remove:                # only runs on the --force path
    ...restore from .backup...

After a keep-config remove the registry reports not installed, so the reinstall is not a --force removal → did_remove is False → the restore block never runs → the config is gone. Reproduced on main @ 92b7cf7: a user config (api_key: MY-CUSTOMIZED-VALUE) survives remove(keep_config=True) but is wiped by the next reinstall — the file doesn't even exist afterward. This is data loss that directly contradicts the feature's promise.

Fix

Before the rmtree, capture any top-level *-config.yml / *-config.local.yml from the existing dest_dir (in-memory), and write them back after the fresh copytree — using the same *-config filter and symlink guard the --force restore path already applies. The --force .backup restore still takes precedence for that path; this only covers the in-place keep-config leftover.

Testing

New test_reinstall_preserves_keep_config_leftover: install → write custom config → remove(keep_config=True) → reinstall (no force) → assert the custom config survives. Fails before (config file gone after reinstall — verified by source-stash), passes after. Full tests/test_extensions.py: 327 passed, 3 skipped (no regressions; keep_config=False/.backup path unaffected). uvx ruff check clean.

AI Disclosure

  • I did use AI assistance (describe below)

Found and fixed with Claude Code (Claude Fable 5) under my direction. AI traced the keep-config leftover through the reinstall path and found the restore only fires on --force; I reproduced the data loss, verified fail-before/pass-after and the full suite, and reviewed the diff.

remove(keep_config=True) intentionally leaves the top-level *-config.yml /
*-config.local.yml in place and drops the registry entry. A subsequent
install_from_directory is not a --force removal (did_remove is False), so
the unconditional 'if dest_dir.exists(): shutil.rmtree(dest_dir)' wiped
the preserved config and the backup-restore path never ran — silently
destroying user configuration the feature promised to keep. Capture the
top-level *-config.yml/*-config.local.yml from an existing dest_dir before
the rmtree and write them back after the fresh copytree, mirroring the
*-config filter the --force restore path already uses.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jawwad-ali jawwad-ali requested a review from mnriem as a code owner July 6, 2026 20:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant