Files
Panama/docs/superpowers/specs/2026-08-24-applications-storage-snapshots-redesign.md

9.3 KiB
Raw Permalink Blame History

Applications, Storage & Snapshots redesign

Approved mock: home-mocks/applications.html (scratchpad, :8642). Spec wins over mock on conflict. Scope: the Applications tab (Gaming and Screen Intelligence untouched) plus the System category's Storage and Snapshots tabs, folded into this phase by decision.

Goals

  1. Applications becomes an app manager: searchable installed list (DesktopEntries + flatpak metadata), flatpak uninstall, honest system-package rows, permission summaries, autostart toggle per app, jump chips to the app's rules elsewhere.
  2. The panama apps catalog goes native: category chips → entries with installed state, installing through the same dnf/flatpak paths (polkit prompts). Same files as the CLI.
  3. Defaults modernized: role dropdowns replace the hand-rolled accordion; a single-file-type override ("One file type") for when a role's family is too broad.
  4. Storage: proportional breakdown bar with honest captions; folder bars share ONE scale; "Clean up, honestly" — itemized, sized, click-each, nothing pre-selected, nothing nags (the anti-racket rules are contract-pinned); the duplicate container affordances merge.
  5. Snapshots: retention becomes editable (wire the caller-less Snapshots.setRetention); the file browser becomes its own card that opens regardless of source-card state (fixes the collapsed-card bug); rollback stays absent (contract).

Non-goals: dnf package removal from Settings (honest refusal row instead), full flatpak permission editing (summary + Open Flatseal when installed), per-app storage classification beyond the flatpak sizes, portal-grant editing, snapshot space measurement (quotas honesty stays).

New helper: scripts/panama-applications (pinned verbs)

House discipline (validated inputs, JSON out, mutations return fresh state, bounded timeouts):

  • flatpaks[{ id, name, size, origin }] (from flatpak list machine-readable columns).
  • permissions <app-id>{ summary: [human strings], raw: {...} } from flatpak info --show-permissions — curated buckets: Camera, Microphone, Full file system access, Home folder, Network, Devices; unknown keys summarized honestly, never dropped silently.
  • uninstall <app-id>flatpak uninstall --noninteractive (app only; a second verb unused-runtimes lists what --unused would remove, and clean-unused removes them — the Storage cleanup row uses these).
  • catalog → categories + entries from setup/packages/extras/* (same parser rules as setup/lib/extras-catalog: flatpak:<id> | Label, bare dnf names, indented continuations), each entry { id, label, kind: flatpak|dnf, installed } (installed via flatpak info / rpm -q).
  • install <category> <entry-id> → flatpak: flatpak install --noninteractive flathub <id>; dnf: pkexec dnf install -y <pkg>. Refuses ids not present in the catalog files (no arbitrary package installation through this surface — contract-pinned).

Extended helpers

  • scripts/panama-default-apps: search-types <query> → matching MIME types with their current handler + candidate apps; set-type <mime> <desktop-id>xdg-mime default (validated against installed desktop entries). Role behavior untouched.
  • scripts/panama-disks: breakdown → segments { home, applications, caches, system, free } in bytes — home = the scan targets under ~ minus caches, applications = flatpak app+runtime sizes (user-readable sums), caches = /.cache, system = used the others ("System & everything else" caption — honest arithmetic remainder), free from the fs. cleanables[{ id, label, detail, bytes, privileged }] for: cache (/.cache), trash, flatpak-unused, dnf-cache (privileged). clean <id> executes exactly one, refusing unknown ids; trash via gio trash --empty; cache via a guarded rm of ~/.cache/* (never follows symlinks out).
  • scripts/panama-snapshots: retention already supported (set-retention); add set-retention argument validation for the three horizons if not already split (hourly/daily/weekly numbers 0-50).

Services (A)

  • services/AppLibrary.qml (new): merges DesktopEntries.applications with the flatpak metadata (id-matched via the entry's flatpak export), exposes apps: [{ entryId, name, icon, kind: flatpak|system, flatpakId, size }], permissionsFor(id) (cached), uninstall(flatpakId), catalog state (categories, entriesFor(cat), install(...)), busy/lastError, seam PANAMA_APPLICATIONS_HELPER.
  • services/DefaultApps.qml: searchTypes(query), setType(mime, desktopId) wrappers.
  • services/Disks.qml: breakdown, cleanables, clean(id) wrappers; cleanables refresh after any clean.
  • services/Snapshots.qml: nothing new needed beyond confirming setRetention's shape matches three-horizon editing; adjust if it takes a single string.

UI (B)

ApplicationsPage.qml rebuilt: Installed applications card (search field filters name + id; rows: letter/icon tile, name + source badge, subtitle id·size or "Installed by the system package manager"; expanded: Permissions row (+ Open Flatseal when installed), Start with the session (autostart toggle — creates/toggles the autostart entry for that app), "Elsewhere in Settings" jump chips (shown only where a rule exists: Notifs.appRule customized/present → notifications; app in AudioDevices applications → sound; PrivacyPage relevance is static — link when the app id appears in its rules if cheaply knowable, else omit), Uninstall (flatpak, two-stage danger) or the honest dnf refusal row with the exact command). Browse-the-catalog card (category chips, entry rows, Install with polkit caption for dnf entries, INSTALLED badge). Default applications card: role dropdowns via OptionPickerRow-style (candidates from the existing role matching; keep all 10 roles + family-count details), then the "One file type" row expanding to a search field over searchTypes with per-type app pickers. Autostart card: existing rows restyled with the standardized confirm; compositor autostart row kept read-only. The Search card stays but the hardcoded "Super+Space" is replaced by a live Keybinds lookup (launcher description match, literal fallback).

StoragePage.qml: breakdown stack bar + legend at top (honest captions; "System & everything else" for the remainder); Folders card bars share one scale (the disk, or the largest — pick the DISK so it's comparable to the free-space bar, with a note); "Clean up, honestly" card from cleanables (row per item: label, honest cost detail, size, Clear… with two-stage confirm; privileged rows carry the password caption; zero-byte rows render inert with "nothing to do"); the "Unused container images" kitty-terminal row is REMOVED (the Containers card below already routes properly — one affordance, not two). Drive/Filesystems/ Removable/Swap cards kept.

SnapshotsPage.qml: per-config Keep row becomes three dropdowns (hourly/daily/weekly → setRetention); the browser moves OUT of the volume card into its own card rendered whenever browsing state is set (opening from a collapsed card now works — this is the bug fix); timeline/preview/expander kept; Space card kept with its honesty.

Search & docs (C)

New entries: Installed applications, Uninstall an application, Application permissions, Install applications (catalog), Autostart, File associations → applications; Clean up storage, Application caches → storage; Snapshot retention → snapshots. Docs regen only if schema changes (none expected — verify).

Contracts (C — write, never run)

  • applications-settings-contract: reconcile with the rebuilt page (role labels, card titles, AutostartAppPicker, the bun matcher extraction).
  • NEW app-library-contract: fixture-driven (stub flatpak/rpm): catalog parser agreement with setup/lib/extras-catalog rules, install refuses off-catalog ids, uninstall argv shape, permissions summary buckets, dnf never invoked for removal anywhere in the helper.
  • disks-contract: extend — breakdown arithmetic honesty (segments sum ≤ used, remainder labeled), cleanup rules: every cleanable itemized with bytes, nothing auto-selected, no cleanable executes without its id being explicitly passed, cache rm is guarded, trash via gio. Pin the anti-racket copy stance (no urgency language).
  • snapshots-contract: extend — setRetention wired from the page, browser renders independent of the volume card's open state, rollback still absent.
  • default-apps-contract family rules untouched; new needles for set-type validation.
  • Backlog: Phase 10. README count line if count changes.

Agent ownership (parallel)

  • A: scripts/panama-applications (new), scripts/panama-default-apps, scripts/panama-disks, scripts/panama-snapshots (only if retention args need splitting), services/AppLibrary.qml (new), services/DefaultApps.qml, services/Disks.qml, services/Snapshots.qml.
  • B: modules/settings/ApplicationsPage.qml, StoragePage.qml, SnapshotsPage.qml, new components + qmldir.
  • C: services/SettingsSearch.qml, contracts above, backlog, README count line.

Hard rules for everyone: no live mutations (no flatpak install/uninstall, no dnf, no rm, no gio trash, no snapper writes, no xdg-mime writes) — read-only probes and stub fixtures only; no test runs; valid QML/Python at every save. B programs against the pinned APIs.