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

142 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.