feat: add contextual actions and recoverable application uninstall

This commit is contained in:
2026-10-12 15:01:15 +02:00
parent 8d8e2278ab
commit 2598f6f1dd
10 changed files with 2361 additions and 12 deletions
+18 -3
View File
@@ -33,6 +33,7 @@ Open `Package.swift` in Xcode to edit the project. Use the bundled app above to
- Type to filter applications; the first match is selected automatically.
- Up/Down or Control-K/Control-J changes the selection without leaving search or modifying its text.
- Return, keypad Enter, the Open Application button, or a double-click opens the selection.
- Command-K or the bottom-right Actions button opens a searchable selector for the selected application. Return chooses **Uninstall application**; Escape closes the selector and returns focus to search.
- Escape or Command-W dismisses the launcher and restores the previously active application. Switching focus away dismisses it without stealing focus back.
- Reopen from Finder to show it again with an empty search. Dismissal leaves the process running; Command-Q quits it.
- Every activation brings the launcher to the currently active macOS Space, including full-screen Spaces, without switching desktops.
@@ -74,6 +75,20 @@ Background discovery preserves the selected application even if its row changes.
Applications with identical display names show a muted containing-folder hint beside the name. Copies sharing the same folder show their full application bundle paths instead. Home paths abbreviate to `~`, and long hints truncate in the middle. Unique names have no hint; locations are recalculated whenever discovery refreshes.
## Application actions and uninstall
Select an application and open **Actions ⌘K**. The red **Uninstall application** action opens a review sheet with file checkboxes, paths, sizes, and a selected-item count. Filtering by name or path does not change selections. Up/Down highlights rows; Space toggles the highlighted eligible item when the file list has focus. Back or Escape returns to the launcher. Return or the uninstall button opens a final confirmation; nothing is moved merely by choosing the action.
Discovery includes the application bundle and exact bundle-ID paths in your Library: Preferences, Caches, Application Support, Logs, Saved Application State, Application Scripts, and Containers. Embedded extension identifiers are included. App-group entitlements are read from validated native code signatures; related shared Group Containers and Application Scripts remain unchecked because other applications may use them. Conjure does not guess name-based leftovers or include package receipts. This is conservative discovery, not a guarantee that every associated file is found.
System-managed applications, Conjure itself, invalid bundles, symbolic-link paths, locked items, and files owned by another user are not removable. Locked candidates show a reason. A locked application bundle can still have eligible user-owned associated data; removing that data does not remove the locked application itself. No administrator authorization is requested. Running instances of the selected application and its embedded applications are asked to quit gracefully; refusal or timeout stops the operation before moving files.
Uninstall freezes the selected paths and records filesystem identities, then stages items by exclusive same-volume moves into private quarantine directories. A durable journal records each intended move before it happens. Staging failure attempts reverse-order restoration without overwriting recreated original paths. Only after every item is staged is the operation committed and finalized into Trash. A finalization failure retains committed quarantine data rather than trying to undo an already committed uninstall.
Interrupted operations are recovered on startup: uncommitted operations restore their originals; committed operations finish moving items to Trash. Unresolved operations block new uninstalls. Failure feedback offers **Retry recovery** and identifies retained journal/quarantine paths. Startup recovery feedback and retry remain available in Settings without taking focus during a login launch. Authenticated journals live under `~/Library/Application Support/Conjure/UninstallTransactions`; completed journals retain original-to-Trash mappings in `Completed`.
Files are never permanently deleted by uninstall. Trash moves preserve file metadata, but Finder's **Put Back** metadata is not created; restore completed items manually using the retained original-path mappings. Rollback is best-effort, not atomic: inaccessible or disconnected volumes and recreated paths can require manual recovery. Same-user malicious code with access to the journal key is outside the journal-authentication guarantee. Unsupported filesystem semantics fail closed.
## Native UI
The launcher keeps its Raycast-inspired 750 × 474-point, titlebar-free rounded panel, large borderless search field, compact icon rows, right-aligned application labels, and bottom-right launch pill. Its Sunset palette uses a dark brown background, soft amber and rust glows, warm cream text, and orange accents on the caret, selection, and action outline.
@@ -86,8 +101,8 @@ The brown tint is 35% opaque over an active, behind-window `NSVisualEffectView`
AppKit still provides text editing, table navigation, scrolling, application icons, controls, menus, fonts, and visual-effect materials. The background uses cached native radial gradients that fade to transparent: static soft blobs, without animations, timers, image assets, blur filters, or third-party UI dependencies. Decorative drawing does not intercept clicks. Increased-contrast settings strengthen the selection outline, and text colors are tuned for readability across the glows and selection.
- `Sources/Conjure`: application lifecycle, launcher and Settings windows, and application launching.
- `Sources/ConjureKit`: filesystem discovery, search ranking, launch history, global shortcut registration, and launcher alignment geometry.
- `Tests/ConjureKitTests`: deterministic discovery, ranking, history, shortcut validation, alignment boundaries, and installation safety checks.
- `Sources/Conjure`: application lifecycle, launcher, Settings, contextual actions and uninstall review windows, and application launching.
- `Sources/ConjureKit`: filesystem discovery, search ranking, launch history, global shortcut registration, launcher alignment geometry, associated-file discovery, and journaled uninstall/recovery.
- `Tests/ConjureKitTests`: deterministic discovery, ranking, history, shortcut validation, alignment boundaries, installation safety, and uninstall failure/recovery checks.
The launcher uses Apple's [visual-effect materials](https://developer.apple.com/documentation/appkit/nsvisualeffectview), [table row selection drawing](https://developer.apple.com/documentation/appkit/nstablerowview/drawselection(in:)), [application launching](https://developer.apple.com/documentation/appkit/nsworkspace/openapplication(at:configuration:completionhandler:)), and [reopen lifecycle](https://developer.apple.com/documentation/appkit/nsapplicationdelegate/applicationshouldhandlereopen(_:hasvisiblewindows:)).