# Remove Uninstall Metadata Design ## Goal Make `aim remove` uninstall `aim`-managed app artifacts rather than only unregistering apps, while preserving backward compatibility for existing registry entries and keeping uninstall logic in `aim-core`. ## Agreed Product Shape ### Remove behavior - `aim remove ` should delete the tracked app from the registry - It should also remove `aim`-managed installed artifacts for that app - Missing artifact files should not make removal fail - Desktop refresh helper failures should surface as warnings rather than block removal ### Metadata model - Persist install metadata on successful install - Persist exact installed paths for payload, desktop entry, and icon - Persist the effective install scope - Keep install metadata optional so old registry entries still deserialize cleanly ### Compatibility posture - New installs should uninstall using persisted exact paths - Existing registry entries without install metadata should fall back to derived `aim`-managed paths - Uninstall should only target paths that belong to `aim` management, not arbitrary external files ## Recommended Approach Use a hybrid uninstall model. This combines exact persisted install metadata for newly installed apps with a conservative derived-path fallback for legacy registry entries. It avoids breaking older registries while making future uninstall behavior precise and resilient to layout changes. The model is: - successful install persists `InstallMetadata` into `AppRecord` - remove resolves uninstall targets from metadata when present - remove falls back to `aim`-managed path derivation when metadata is absent - uninstall deletes payload, desktop entry, and icon, then refreshes desktop caches best-effort ## Data Model ### `InstallMetadata` Persist this on each installed app record: - `scope` - `payload_path` - `desktop_entry_path` - `icon_path` Store these as optional path strings under an optional `install` field on `AppRecord`. ### Backward compatibility - `AppRecord.install` is optional - legacy records continue to load unchanged - remove derives fallback targets from `stable_id` and inferred scope when `install` is absent ## Remove Execution Model ### 1. Resolve the app - Match the registered app by stable id or display name - Preserve existing ambiguity behavior ### 2. Resolve uninstall targets Prefer persisted metadata: - exact payload path - exact desktop entry path - exact icon path - persisted scope Fallback for legacy records: - payload path from `managed_appimage_path(...)` - desktop entry path from `desktop_entry_path(...)` - icon path from `icon_path(...)` - scope inferred conservatively, defaulting to user-managed locations when exact scope is unknown ### 3. Delete managed artifacts Delete only `aim`-managed artifacts: - AppImage payload - generated `.desktop` file - generated icon Rules: - treat missing files as already removed - collect deleted paths for reporting - do not attempt to delete non-`aim` unmanaged locations ### 4. Refresh desktop integration best-effort - probe helpers using the same capability model used by install - run `update-desktop-database` and `gtk-update-icon-cache` when relevant - return warnings instead of failing removal if refresh helpers are missing or fail ### 5. Persist registry last - only save the registry after uninstall execution completes - successful uninstall with warnings still removes the registry entry ## Safety Model ### Managed-only deletion Uninstall must only delete files that are known `aim` outputs: - persisted metadata generated by `aim` - derived managed paths under `aim`-controlled naming conventions ### Idempotency Repeated remove attempts should be safe: - missing files are ignored - warnings can still be emitted for helper refresh failures - registry result remains correct even if artifacts were already manually deleted ### Failure handling - file deletion failures should stop removal and keep the app registered - refresh failures should not block removal - no rollback is needed for already-deleted files ## Verification Strategy ### Unit tests - install metadata round-trips through the registry model - remove plan resolves exact persisted paths - remove plan falls back to derived managed paths for legacy records ### Integration tests - add then remove deletes payload, desktop entry, and icon - remove tolerates already-missing artifacts - remove emits warnings when refresh helpers are unavailable or fail - legacy registry entries without install metadata still uninstall derived user-managed files ## Architecture Slice ### Core changes - extend `domain::app::AppRecord` with optional `InstallMetadata` - populate `InstallMetadata` in the add/install path from `InstalledApp` - extend `app::remove` with uninstall planning and execution - reuse `integration::refresh` helper execution after deletion ### CLI changes - keep CLI thin - `aim-cli` should continue delegating uninstall behavior to `aim-core` - render warnings from uninstall results if present ## Non-Goals - deleting arbitrary external files not managed by `aim` - adding a separate garbage collection command in this change - refactoring install path layout beyond the metadata needed for uninstall