5.2 KiB
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 <QUERY>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
aimmanagement, 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
InstallMetadataintoAppRecord - 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:
scopepayload_pathdesktop_entry_pathicon_path
Store these as optional path strings under an optional install field on AppRecord.
Backward compatibility
AppRecord.installis optional- legacy records continue to load unchanged
- remove derives fallback targets from
stable_idand inferred scope wheninstallis 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
.desktopfile - generated icon
Rules:
- treat missing files as already removed
- collect deleted paths for reporting
- do not attempt to delete non-
aimunmanaged locations
4. Refresh desktop integration best-effort
- probe helpers using the same capability model used by install
- run
update-desktop-databaseandgtk-update-icon-cachewhen 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::AppRecordwith optionalInstallMetadata - populate
InstallMetadatain the add/install path fromInstalledApp - extend
app::removewith uninstall planning and execution - reuse
integration::refreshhelper execution after deletion
CLI changes
- keep CLI thin
aim-clishould continue delegating uninstall behavior toaim-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