← pag

Commit 5ce8105

7
plików
+691
dodanych
-2
usuniętych
@@ -0,0 +1,3 @@
1 +__pycache__/
2 +*.pyc
3 +archive/
@@ -27,6 +27,7 @@ pag --help # same as above
27 27 - [Trust chain](#trust-chain)
28 28 - [Immutable system](#immutable-system)
29 29 - [Rollback](#rollback)
30 + - [Rolling – base baked into the ISO](#rolling--base-baked-into-the-iso)
30 31 - [Commands](#commands)
31 32 - [Environment variables](#environment-variables)
32 33 - [Paths and files](#paths-and-files)
@@ -55,6 +56,10 @@ sudo pag update
55 56 # …or the whole system: packages + kernel / initramfs / GRUB
56 57 sudo pag upgrade
57 58
59 +# Base baked into the ISO vs. the repository (full rolling)
60 +pag base # what comes from the image, what pag manages
61 +sudo pag base adopt # adopt the base from the repo (--dry-run = preview)
62 +
58 63 # Verify the integrity of all files
59 64 sudo pag verify --deep
60 65 ```
@@ -170,6 +175,33 @@ graph TD
170 175
171 176 ---
172 177
178 +### Rolling – base baked into the ISO
179 +
180 +The PaganOS image is built **from sources** (glibc, gcc, GTK, XFCE, kernel…).
181 +`pag` did not install them, so they are not in its database
182 +(`/var/lib/pag/installed.json`) – and since it does not know them,
183 +`pag upgrade` will **not** update them. The image files are not untouchable
184 +though: `pag install <name>` overwrites them (a backup is kept for
185 +`pag rollback`).
186 +
187 +To make the system fully rolling, tell pag what the image base is:
188 +
189 +```bash
190 +pag base # report: how many image packages pag manages, how many can
191 + # be adopted from the repo, which stay at the image version
192 +sudo pag base adopt # adopt the base from the repo (--dry-run = preview only)
193 +```
194 +
195 +After `pag base adopt` the image packages become ordinary repo packages, so
196 +the next `sudo pag upgrade` updates the **whole** system. The list of base
197 +packages comes from a manifest baked into the image:
198 +`/usr/share/pag/base.json` (name + version; the builder appends an entry for
199 +every package it builds). Builder names are mapped onto repo names (e.g.
200 +`gtk` → `gtk3`, `libX11` → `xorg-libx11`); names with no repo counterpart are
201 +reported as staying at the image version.
202 +
203 +---
204 +
173 205 ## Commands
174 206
175 207 ### BASICS
@@ -224,6 +256,14 @@ Flathub and suggests names – e.g. `pag firefox` will find the package.
224 256 | `pag sbom export [spdx\|cyclonedx]` | Export an SBOM manifest of all installed components |
225 257 | `pag self-update` | Update the `pag` client itself (GPG signature + SHA256 + syntax, atomically) |
226 258
259 +### ROLLING (BASE FROM THE IMAGE)
260 +
261 +| Command | Description |
262 +|---|---|
263 +| `pag base` | Report: image packages – managed by pag / adoptable from repo / no counterpart |
264 +| `pag base adopt` | Adopts the base packages from the repo (replaces image files, backup for `pag rollback`); `--dry-run` = preview |
265 +| `pag base adopt <pkg>...` | Adopts only the given base packages |
266 +
227 267 ### FLATPAK
228 268
229 269 | Command | Description |
@@ -27,6 +27,7 @@ pag --help # to samo co wyżej
27 27 - [Łańcuch zaufania](#łańcuch-zaufania)
28 28 - [System immutable](#system-immutable)
29 29 - [Rollback](#rollback)
30 + - [Rolling – baza z obrazu ISO](#rolling--baza-z-obrazu-iso)
30 31 - [Komendy](#komendy)
31 32 - [Zmienne środowiskowe](#zmienne-środowiskowe)
32 33 - [Ścieżki i pliki](#ścieżki-i-pliki)
@@ -55,6 +56,10 @@ sudo pag update
55 56 # …albo cały system: pakiety + kernel / initramfs / GRUB
56 57 sudo pag upgrade
57 58
59 +# Baza zbudowana w obrazie ISO a repozytorium (pełny rolling)
60 +pag base # co jest z obrazu, a czym pag już zarządza
61 +sudo pag base adopt # dograj bazę z repo (--dry-run = podgląd)
62 +
58 63 # Sprawdź integralność wszystkich plików
59 64 sudo pag verify --deep
60 65 ```
@@ -171,6 +176,32 @@ graph TD
171 176
172 177 ---
173 178
179 +### Rolling – baza z obrazu ISO
180 +
181 +Obraz PaganOS jest zbudowany **ze źródeł** (glibc, gcc, GTK, XFCE, jądro…).
182 +`pag` ich nie instalował, więc nie ma ich w swojej bazie
183 +(`/var/lib/pag/installed.json`) – a skoro ich nie zna, to `pag upgrade`
184 +ich **nie zaktualizuje**. Pliki z obrazu nie są jednak nietykalne:
185 +`pag install <nazwa>` je nadpisze (z kopią zapasową dla `pag rollback`).
186 +
187 +Żeby system był w pełni rolling, trzeba powiedzieć pagowi, co jest bazą obrazu:
188 +
189 +```bash
190 +pag base # raport: ile pakietów z obrazu pag zarządza, ile da się
191 + # zaadoptować z repo i co zostaje w wersji z obrazu
192 +sudo pag base adopt # dograj bazę z repo (--dry-run = podgląd, nic nie instaluje)
193 +```
194 +
195 +Po `pag base adopt` pakiety z obrazu stają się zwykłymi pakietami z repo,
196 +więc kolejne `sudo pag upgrade` aktualizuje **cały** system. Spis pakietów
197 +bazy pochodzi z manifestu wypalanego w obrazie: `/usr/share/pag/base.json`
198 +(nazwa + wersja; builder dopisuje wpis przy każdym budowanym pakiecie).
199 +Nazwy z buildera są mapowane na nazwy z repo (np. `gtk` → `gtk3`,
200 +`libX11` → `xorg-libx11`); te bez odpowiednika w repo raport zostawia
201 +w wersji z obrazu i mówi o tym wprost.
202 +
203 +---
204 +
174 205 ## Komendy
175 206
176 207 ### PODSTAWY
@@ -225,6 +256,14 @@ i Flathub oraz podpowiada nazwy – np. `pag firefox` znajdzie pakiet.
225 256 | `pag sbom export [spdx\|cyclonedx]` | Eksportuje manifest SBOM wszystkich zainstalowanych komponentów |
226 257 | `pag self-update` | Aktualizuje samego klienta `pag` (podpis GPG + SHA256 + składnia, atomowo) |
227 258
259 +### ROLLING (BAZA Z OBRAZU)
260 +
261 +| Komenda | Opis |
262 +|---|---|
263 +| `pag base` | Raport: pakiety z obrazu ISO – zarządzane przez pag / do adoptowania z repo / bez odpowiednika |
264 +| `pag base adopt` | Dogrywa pakiety bazy z repo (zastępuje pliki z obrazu, kopie dla `pag rollback`); `--dry-run` = podgląd |
265 +| `pag base adopt <pkg>...` | Adoptuje tylko wskazane pakiety bazy |
266 +
228 267 ### FLATPAK
229 268
230 269 | Komenda | Opis |
231 270 new file mode 100644
@@ -0,0 +1,84 @@
1 +#!/usr/bin/env python3
2 +"""extract-pag-lang.py – wyciąga wbudowane tłumaczenia z klienta `pag/pag`
3 +do plików `pag/pag-lang/{pl,en}.json` (klucz "usage" = tekst --help).
4 +
5 +Użycie:
6 + python3 pag/extract-pag-lang.py # odśwież pag-lang/*.json
7 + python3 pag/extract-pag-lang.py --check # tylko pokaż liczby kluczy
8 +
9 +Katalog projektu pag (odpowiada 1:1 repo git.paganlinux.eu/git/pag):
10 + pag/ – klient (PAG_VERSION)
11 + pag/pag-lang/ – tłumaczenia (generowane tym skryptem)
12 + pag/README.md, README-EN.md
13 + pag/archive/ – stare szkice klienta (build ich nie używa)
14 +
15 +Potem builder instaluje je do /usr/share/pag/lang (install_pag + respin-iso.sh),
16 +a `pag` czyta je w kolejności: PAG_LANG_DIR → /etc/pag/lang →
17 +/usr/share/pag/lang → ./pag-lang (dev).
18 +"""
19 +from __future__ import annotations
20 +
21 +import importlib.util
22 +import json
23 +import os
24 +import sys
25 +from importlib.machinery import SourceFileLoader
26 +
27 +HERE = os.path.dirname(os.path.abspath(__file__))
28 +PAG = os.path.join(HERE, "pag")
29 +OUT = os.path.join(HERE, "pag-lang")
30 +LANGS = ("pl", "en")
31 +
32 +
33 +def load_pag():
34 + # Eksportujemy CZYSTE wbudowane słowniki (bez nadpisań ze starych plików)
35 + os.environ["PAG_LANG_NO_FILES"] = "1"
36 + # Plik nie ma rozszerzenia .py → trzeba podać loader jawnie
37 + loader = SourceFileLoader("pagsrc", PAG)
38 + spec = importlib.util.spec_from_loader("pagsrc", loader)
39 + mod = importlib.util.module_from_spec(spec)
40 + sys.modules["pagsrc"] = mod
41 + # __name__ != "__main__" → main() z paga się NIE uruchomi
42 + loader.exec_module(mod)
43 + return mod
44 +
45 +
46 +def main() -> int:
47 + check = "--check" in sys.argv
48 + if not os.path.isfile(PAG):
49 + print(f"Brak pliku: {PAG}", file=sys.stderr)
50 + return 1
51 + mod = load_pag()
52 + tables = getattr(mod, "T", {})
53 + # Kontrola spójności PL/EN (pomijamy klucze „*_pl” – to celowe warianty PL)
54 + _pk = {k for k in tables.get("pl", {}) if not k.endswith("_pl")}
55 + _ek = {k for k in tables.get("en", {}) if not k.endswith("_pl")}
56 + _miss_en = sorted(_pk - _ek)
57 + _miss_pl = sorted(_ek - _pk)
58 + if _miss_en:
59 + print(f" ! en: brakuje {len(_miss_en)} kluczy: {', '.join(_miss_en[:10])}"
60 + + (" …" if len(_miss_en) > 10 else ""))
61 + if _miss_pl:
62 + print(f" ! pl: brakuje {len(_miss_pl)} kluczy: {', '.join(_miss_pl[:10])}"
63 + + (" …" if len(_miss_pl) > 10 else ""))
64 + os.makedirs(OUT, exist_ok=True)
65 + for code in LANGS:
66 + data = dict(tables.get(code, {}))
67 + usage = getattr(mod, f"USAGE_{code.upper()}", "")
68 + if usage:
69 + data["usage"] = usage
70 + n = len(data)
71 + if check:
72 + print(f" [{code}] {n} kluczy")
73 + continue
74 + path = os.path.join(OUT, f"{code}.json")
75 + with open(path, "w", encoding="utf-8") as fh:
76 + json.dump(data, fh, ensure_ascii=False, indent=2, sort_keys=True)
77 + print(f"✓ {path} ({n} kluczy)")
78 + if not check:
79 + print("Gotowe. Edytuj JSON-y, a builder/ISO wezmą je automatycznie.")
80 + return 0
81 +
82 +
83 +if __name__ == "__main__":
84 + sys.exit(main())
@@ -55,7 +55,7 @@ import threading, itertools
55 55 import uuid # serialNumber SBOM (CycloneDX)
56 56
57 57 # Wersja klienta – do porównania z repo.json["pag_version"] (self-update)
58 -PAG_VERSION = "3.3.23"
58 +PAG_VERSION = "3.4.0"
59 59 from urllib.error import URLError, HTTPError
60 60
61 61 # =============================================================================
@@ -392,6 +392,26 @@ T = {
392 392 "conf_pacsave": "Modified config kept as {path}",
393 393 # Zależności wirtualne (provides)
394 394 "provides_conflict": "Multiple providers for '{name}' ({providers}) – using '{chosen}'",
395 +
396 + # Base baked into the ISO image (pag base / base adopt)
397 + "base_title": "Base from the ISO image",
398 + "base_no_manifest": "This system carries no base manifest (/usr/share/pag/base.json) – nothing to adopt.",
399 + "base_iso_version": "Image version",
400 + "base_total": "Base packages (from image)",
401 + "base_tracked": "Managed by pag",
402 + "base_adoptable": "Adoptable from repo",
403 + "base_unmatched": "No counterpart in repo",
404 + "base_adopt_hint": "Adopt them (image files get replaced by repo packages): sudo pag base adopt",
405 + "base_unmatched_hint": "These stay at the image version (no such package in repo):",
406 + "base_more": "more",
407 + "base_nothing_selected": "None of the given names is on the adopt list.",
408 + "base_all_managed": "Every base package is already managed by pag.",
409 + "base_adopt_plan": "Adopting {} base packages from the repo (~{:.0f} MB):",
410 + "base_dry_run": "Dry run – nothing was installed.",
411 + "base_unmanaged_hint": "{} packages from the ISO image are not managed by pag yet – 'sudo pag base adopt' replaces them with repo packages (only then does 'pag upgrade' update them).",
412 + "base_overwrite": "{} comes from the ISO image – its files will be replaced (backup kept for 'pag rollback').",
413 + "base_reboot_hint": "Base adopted from the repo – reboot before using the new libraries/toolchain.",
414 + "stats_base": "Base (image) managed",
395 415 },
396 416 "pl": {
397 417 "root_required": "pag wymaga uprawnień root (sudo).",
@@ -502,6 +522,26 @@ T = {
502 522 "conf_pacnew": "Zmieniony plik konfiguracyjny zachowany; nowa wersja: {path}",
503 523 "conf_pacsave": "Zmieniony plik konfiguracyjny zachowany jako {path}",
504 524 "provides_conflict": "Wielu dostawców dla '{name}' ({providers}) – używam '{chosen}'",
525 +
526 + # Baza wypalona w obrazie ISO (pag base / base adopt)
527 + "base_title": "Baza z obrazu ISO",
528 + "base_no_manifest": "Ten system nie ma manifestu bazy (/usr/share/pag/base.json) – nie ma czego adoptować.",
529 + "base_iso_version": "Wersja obrazu",
530 + "base_total": "Pakiety bazy (z obrazu)",
531 + "base_tracked": "Zarządzane przez pag",
532 + "base_adoptable": "Do adoptowania z repo",
533 + "base_unmatched": "Bez odpowiednika w repo",
534 + "base_adopt_hint": "Adoptuj (pliki z obrazu zostaną zastąpione pakietami z repo): sudo pag base adopt",
535 + "base_unmatched_hint": "Te zostaną w wersji z obrazu (brak takiego pakietu w repo):",
536 + "base_more": "więcej",
537 + "base_nothing_selected": "Żadna z podanych nazw nie jest na liście do adoptowania.",
538 + "base_all_managed": "Wszystkie pakiety bazy są już zarządzane przez pag.",
539 + "base_adopt_plan": "Adoptowanie {} pakietów bazy z repo (~{:.0f} MB):",
540 + "base_dry_run": "Próba na sucho – nic nie zainstalowano.",
541 + "base_unmanaged_hint": "{} pakietów z obrazu ISO nie jest jeszcze zarządzanych przez pag – 'sudo pag base adopt' zamieni je na pakiety z repo (dopiero wtedy 'pag upgrade' je aktualizuje).",
542 + "base_overwrite": "{} pochodzi z obrazu ISO – pliki zostaną zastąpione (kopia zapasowa dla 'pag rollback').",
543 + "base_reboot_hint": "Baza zaadoptowana z repo – zrestartuj system, zanim zaczniesz używać nowych bibliotek/narzędzi.",
544 + "stats_base": "Baza (obraz) zarządzana",
505 545 },
506 546 }
507 547
@@ -599,6 +639,7 @@ STAGING_DIR = "/.pag_staging" # na tej samej partycji co / (unikamy E
599 639 PKG_EXT = ".pag"
600 640 REPO_CACHE_TTL = 3600
601 641 MAX_PKG_SIZE = 2 * 1024 * 1024 * 1024 # 2 GB – maksymalny rozmiar paczki
642 +BASE_MANIFEST = "/usr/share/pag/base.json" # baza z obrazu ISO (pag base/adopt)
602 643
603 644 # ── UPRZYWILEJOWANE PLIKI ────────────────────────────────────────────────────
604 645 # Domyślnie pag zdejmuje bit SUID i wymusza właściciela root:root. Niektóre
@@ -2748,6 +2789,10 @@ def cmd_install(package_names, as_dep=False, upgrade=False):
2748 2789 marker = f" [{_('new')}]"
2749 2790 print(f" {name}-{p.version}{marker}")
2750 2791
2792 + # Pakiet z bazy obrazu ISO (nie w installed.json) → ostrzeż, że pliki z ISO
2793 + # zostaną zastąpione pakietem z repo (kopia do `pag rollback`).
2794 + _base_warn_overwrite(to_install)
2795 +
2751 2796 if not as_dep and not upgrade:
2752 2797 if not _ask_confirm():
2753 2798 print(_("cancelled")); return 0
@@ -3348,6 +3393,209 @@ def _pending_updates() -> List[str]:
3348 3393 return [n for n, i in installed.items()
3349 3394 if n not in pinned and (rp := repo.get(n)) and _candidate_newer(rp, i)]
3350 3395
3396 +# =============================================================================
3397 +# BAZA Z OBRAZU ISO → REPO (`pag base`) – pełny rolling
3398 +# =============================================================================
3399 +# ISO jest zbudowane ZE ŹRÓDEŁ (glibc, gcc, gtk, XFCE, …) – pag tych pakietów
3400 +# nie instalował, więc nie ma ich w installed.json/files.db. Skutki:
3401 +# • `pag upgrade` ich NIE dotyka (nie ma o nich pojęcia),
3402 +# • mimo to `pag install <nazwa>` je NADPISZE – pag robi kopię plików spoza
3403 +# swojej bazy (patrz _new_transaction_backup_root), więc nie są nietykalne.
3404 +#
3405 +# /usr/share/pag/base.json (wypalany przez build-pagan.sh) mówi, co jest w bazie
3406 +# obrazu i w jakiej wersji. `pag base` pokazuje stan, a `pag base adopt` dogrywa
3407 +# te pakiety z repo – po tym zabiegu pag zarządza nimi normalnie, więc
3408 +# `pag upgrade` aktualizuje CAŁY system (rolling), a nie tylko to, co sam
3409 +# wcześniej zainstalował.
3410 +#
3411 +# Nazwy z buildera różnią się od nazw pakietów w repo (builder buduje „libX11”,
3412 +# repo ma pakiet „xorg-libx11”), stąd aliasy poniżej. Nazwy bez odpowiednika
3413 +# w repo zostają w wersji z obrazu – raport mówi o tym wprost, zamiast udawać,
3414 +# że są aktualne.
3415 +BASE_NAME_ALIASES = {
3416 + "atk": "at-spi2-core",
3417 + "dejavu-fonts": "dejavu-ttf",
3418 + "fontconfig": "xorg-fontconfig",
3419 + "gtk": "gtk3",
3420 + "iceauth": "xorg-iceauth",
3421 + "libX11": "xorg-libx11",
3422 + "libXau": "xorg-libxau",
3423 + "libXdmcp": "xorg-libxdmcp",
3424 + "libXext": "xorg-libxext",
3425 + "libXft": "xorg-libxft",
3426 + "libdrm": "xorg-libdrm",
3427 + "libnspr": "nspr",
3428 + "libxkbfile": "xorg-libxkbfile",
3429 + "libxklavier": "xorg-libxklavier",
3430 + "linux-pam": "pam",
3431 + "pixman": "xorg-pixman",
3432 + "sdl2": "sdl",
3433 + "setxkbmap": "xorg-setxkbmap",
3434 + "xauth": "xorg-xauth",
3435 + "xf86-input-libinput": "xorg-xf86-input-libinput",
3436 + "xf86-video-fbdev": "xorg-xf86-video-fbdev",
3437 + "xinit": "xorg-xinit",
3438 + "xkbcomp": "xorg-xkbcomp",
3439 + "xkeyboard-config": "xorg-xkeyboard-config",
3440 +}
3441 +
3442 +
3443 +def _base_manifest() -> dict:
3444 + """Manifest bazy z obrazu ({} gdy obraz go nie dostarcza)."""
3445 + _d = load_json(os.path.join(PAG_ROOT, BASE_MANIFEST.lstrip("/")))
3446 + return _d if isinstance(_d, dict) else {}
3447 +
3448 +
3449 +def _base_entries() -> list:
3450 + """[(nazwa_z_buildera, wersja_z_obrazu), ...] z manifestu."""
3451 + _out = []
3452 + for _e in (_base_manifest().get("packages") or []):
3453 + if isinstance(_e, str):
3454 + if _e:
3455 + _out.append((_e, "?"))
3456 + elif isinstance(_e, dict) and _e.get("name"):
3457 + _out.append((str(_e["name"]), str(_e.get("version") or "?")))
3458 + return _out
3459 +
3460 +
3461 +def _base_repo_name(name: str, repo: dict, installed: dict) -> str:
3462 + """Nazwa pakietu w repo dla nazwy z buildera (alias → provides → brak)."""
3463 + if name in repo:
3464 + return name
3465 + _alias = BASE_NAME_ALIASES.get(name)
3466 + if _alias and _alias in repo:
3467 + return _alias
3468 + _real = _resolve_provides(name, repo, installed)
3469 + return _real if _real in repo else ""
3470 +
3471 +
3472 +def _base_summary(repo: Optional[dict] = None) -> dict:
3473 + """Klasyfikacja pakietów bazy z obrazu wobec repo.
3474 +
3475 + repo=None → pobiera indeks repo (potrzebny do listy „do adoptowania”).
3476 + repo={} → bez sieci: rozpoznaje tylko to, czym pag już zarządza.
3477 + """
3478 + _entries = _base_entries()
3479 + if not _entries:
3480 + return {"total": 0, "tracked": 0, "adoptable": [], "unmatched": []}
3481 + if repo is None:
3482 + repo = fetch_all_packages()
3483 + installed = load_json(INSTALLED_DB)
3484 + tracked, adoptable, unmatched = 0, [], []
3485 + for _n, _v in _entries:
3486 + _real = _base_repo_name(_n, repo, installed)
3487 + if _n in installed or (_real and _real in installed):
3488 + tracked += 1
3489 + elif _real:
3490 + adoptable.append((_n, _real, _v))
3491 + else:
3492 + unmatched.append(_n)
3493 + return {"total": len(_entries), "tracked": tracked,
3494 + "adoptable": adoptable, "unmatched": unmatched}
3495 +
3496 +
3497 +def _base_hint_unmanaged() -> None:
3498 + """Jednozdaniowa informacja dla `pag sync/update/upgrade`."""
3499 + try:
3500 + _s = _base_summary()
3501 + except Exception:
3502 + return
3503 + if _s["adoptable"]:
3504 + print(f"\n ℹ {_('base_unmanaged_hint', len(_s['adoptable']))}")
3505 +
3506 +
3507 +def _base_warn_overwrite(names) -> None:
3508 + """Ostrzeżenie w `pag install`, gdy pakiet pochodzi z bazy obrazu ISO."""
3509 + _entries = _base_entries()
3510 + if not _entries:
3511 + return
3512 + _known = set()
3513 + for _n, _v in _entries:
3514 + _known.add(_n)
3515 + _al = BASE_NAME_ALIASES.get(_n)
3516 + if _al:
3517 + _known.add(_al)
3518 + _hit = [n for n in names if n in _known]
3519 + if _hit:
3520 + _listed = ", ".join(_hit[:5]) + (" …" if len(_hit) > 5 else "")
3521 + print(f" ℹ {_('base_overwrite', _listed)}")
3522 +
3523 +
3524 +def cmd_base_status():
3525 + """`pag base` / `pag base status` – co w systemie pochodzi z obrazu,
3526 + czym pag już zarządza i co da się zaadoptować z repo."""
3527 + _man = _base_manifest()
3528 + if not _man:
3529 + print(f" ℹ {_('base_no_manifest')}")
3530 + return 0
3531 + _s = _base_summary()
3532 + print(f"\n {_c('bold', _('base_title'))}")
3533 + print(f" {'─' * 46}")
3534 + _de = _man.get("de") or ""
3535 + print(f" {_('base_iso_version'):<34} {_man.get('iso_version', '?')}" + (f" ({_de})" if _de else ""))
3536 + print(f" {_('base_total'):<34} {_s['total']}")
3537 + print(f" {_('base_tracked'):<34} {_s['tracked']}")
3538 + print(f" {_('base_adoptable'):<34} {len(_s['adoptable'])}")
3539 + print(f" {_('base_unmatched'):<34} {len(_s['unmatched'])}")
3540 + if _s["adoptable"]:
3541 + print(f"\n {_('base_adopt_hint')}")
3542 + for _iso_n, _real, _v in _s["adoptable"][:10]:
3543 + _m = "" if _iso_n == _real else f" ({_iso_n})"
3544 + print(f" {_real}-{_v}{_m}")
3545 + if len(_s["adoptable"]) > 10:
3546 + print(f" … {len(_s['adoptable']) - 10} {_('base_more')}")
3547 + if _s["unmatched"]:
3548 + print(f"\n {_('base_unmatched_hint')}")
3549 + print(" " + ", ".join(_s["unmatched"][:12])
3550 + + (f" … +{len(_s['unmatched']) - 12}" if len(_s["unmatched"]) > 12 else ""))
3551 + return 0
3552 +
3553 +
3554 +def cmd_base_adopt(args):
3555 + """`pag base adopt [pkg...] [--dry-run]` – dograj bazę z obrazu z repo.
3556 +
3557 + Pakiety bazy nie ma w installed.json, więc pag traktuje je jak NOWĄ
3558 + instalację: pliki z obrazu trafiają do kopii transakcji (działa
3559 + `pag rollback`), a po sukcesie pag zarządza nimi jak każdym innym pakietem.
3560 + """
3561 + if not _base_manifest():
3562 + print(f" ℹ {_('base_no_manifest')}")
3563 + return 1
3564 + repo = fetch_all_packages()
3565 + if not repo:
3566 + print(f"❌ {_('no_index')}")
3567 + return 1
3568 + _want = [a for a in args if not a.startswith("-") and a != "adopt"]
3569 + _s = _base_summary(repo)
3570 + plan = _s["adoptable"]
3571 + if _want:
3572 + _sel = set(_want)
3573 + plan = [p for p in plan if p[0] in _sel or p[1] in _sel]
3574 + if not plan:
3575 + print(f" ℹ {_('base_nothing_selected')}")
3576 + return 0
3577 + if not plan:
3578 + print(f"✅ {_('base_all_managed')}")
3579 + return 0
3580 + _size = sum(repo[r].size_bytes for _i, r, _v in plan if r in repo)
3581 + print(f"\n {_('base_adopt_plan', len(plan), _size / 1048576)}")
3582 + for _iso_n, _real, _v in plan[:20]:
3583 + _rv = repo[_real].version if _real in repo else "?"
3584 + _m = "" if _iso_n == _real else f" ({_iso_n} → {_real})"
3585 + print(f" {_real}: {_v} → {_rv}{_m}")
3586 + if len(plan) > 20:
3587 + print(f" … {len(plan) - 20} {_('base_more')}")
3588 + if "-n" in args or "--dry-run" in args:
3589 + print(f" {_('base_dry_run')}")
3590 + return 0
3591 + _rc = cmd_install([r for _i, r, _v in plan])
3592 + if _rc == 0:
3593 + # Wymienione biblioteki/narzędzia (glibc, gcc, GTK…) są już nowe na dysku,
3594 + # ale działające procesy wciąż mają stare w pamięci – restart domyka.
3595 + print(f"\n ℹ {_('base_reboot_hint')}")
3596 + return _rc
3597 +
3598 +
3351 3599 def cmd_update(do_upgrade: bool = False):
3352 3600 """`pag sync` / `pag update` – odświeżenie indeksów + raport aktualizacji.
3353 3601
@@ -3382,6 +3630,7 @@ def cmd_update(do_upgrade: bool = False):
3382 3630 pending = _pending_updates()
3383 3631 if not pending:
3384 3632 print(f"✅ {_('all_up_to_date')}")
3633 + _base_hint_unmanaged()
3385 3634 return 0
3386 3635 print(f"{_('updates_available', len(pending))}")
3387 3636 installed = load_json(INSTALLED_DB)
@@ -3389,10 +3638,13 @@ def cmd_update(do_upgrade: bool = False):
3389 3638 for n in pending:
3390 3639 print(f" {n}: {installed.get(n, {}).get('version', '?')} → {repo[n].version}")
3391 3640 if not do_upgrade:
3641 + _base_hint_unmanaged()
3392 3642 return 0 # sync: tylko informacja
3393 3643 if not _ask_confirm():
3394 3644 return 0
3395 - return cmd_install(pending, upgrade=True)
3645 + _rc = cmd_install(pending, upgrade=True)
3646 + _base_hint_unmanaged()
3647 + return _rc
3396 3648
3397 3649 def _initramfs_stale() -> bool:
3398 3650 """Czy initramfs jest starszy niż najnowsze jądro (wymaga przebudowy)."""
@@ -3977,6 +4229,12 @@ def cmd_stats():
3977 4229 print(f" {_('stats_cache'):<30} {cache_size/1048576:.1f} MB")
3978 4230 print(f" {_('stats_history'):<30} {len(history)}")
3979 4231 print(f" {_('stats_last_update'):<30} {last_update}")
4232 + _bs = _base_summary(repo={}) # bez sieci – tylko stan zarządzania bazą
4233 + if _bs["total"]:
4234 + _bt = f"{_bs['tracked']}/{_bs['total']}"
4235 + if _bs["tracked"] < _bs["total"]:
4236 + _bt += " (sudo pag base adopt)"
4237 + print(f" {_('stats_base'):<30} {_bt}")
3980 4238 by_size = sorted(installed.items(), key=lambda x: x[1].get("size_bytes", 0), reverse=True)[:5]
3981 4239 if by_size:
3982 4240 print(f"\n {_c('dim', 'Top 5:')}")
@@ -5410,6 +5668,10 @@ BASIC:
5410 5668 pag stats System statistics
5411 5669 pag download <pkg>... Download packages to cache (offline prep)
5412 5670
5671 +ROLLING (base baked into the image):
5672 + pag base [status] Image packages vs. repo (what pag manages)
5673 + pag base adopt [pkg...] Adopt base packages from the repo (--dry-run = preview)
5674 +
5413 5675 SECURITY:
5414 5676 pag key-add <url|file> Import GPG key
5415 5677 pag key-list List trusted keys
@@ -5465,6 +5727,10 @@ PODSTAWOWE:
5465 5727 pag stats Statystyki systemu
5466 5728 pag download <pkg>... Pobierz do cache (offline)
5467 5729
5730 +ROLLING (baza wypalona w obrazie):
5731 + pag base [status] Pakiety z obrazu vs repo (czym pag zarządza)
5732 + pag base adopt [pkg...] Adoptuj pakiety bazy z repo (--dry-run = podgląd)
5733 +
5468 5734 BEZPIECZEŃSTWO:
5469 5735 pag key-add <url|file> Importuj klucz GPG
5470 5736 pag key-list Lista zaufanych kluczy
@@ -5577,6 +5843,12 @@ def main():
5577 5843 if cmd in READ_ONLY:
5578 5844 sys.exit(READ_ONLY[cmd]() or 0)
5579 5845
5846 + # --- `pag base` / `pag base status`: tylko odczyt (bez roota i bez locka) ---
5847 + # `pag base adopt` NIE wpada tutaj – idzie ścieżką komend zapisu (roota + lock
5848 + # pilnuje wspólna obsługa niżej), żeby transakcja była bezpieczna.
5849 + if cmd in ("base", "base-status") and not (args and args[0] == "adopt"):
5850 + sys.exit(cmd_base_status() or 0)
5851 +
5580 5852 # --- Smart search: `pag <nazwa-pakietu>` → repo + Flathub + sugestie ---
5581 5853 WRITE_CMDS = {
5582 5854 "install", "remove", "update", "sync", "upgrade", "clean", "download",
@@ -5585,6 +5857,7 @@ def main():
5585 5857 "self-update",
5586 5858 "flatpak", "flatpak-install", "flatpak-remove", "flatpak-update",
5587 5859 "deploy-rollback", "deploy-cleanup", "initramfs-update", "grub-update",
5860 + "base", "base-adopt",
5588 5861 }
5589 5862 if cmd not in WRITE_CMDS:
5590 5863 # Literówka komendy? (np. `pag instal steam` zamiast `pag install`) –
@@ -5643,6 +5916,8 @@ def main():
5643 5916 "deploy-cleanup": lambda: cmd_deploy_cleanup(int(args[0]) if args else 3),
5644 5917 "initramfs-update": cmd_initramfs_update,
5645 5918 "grub-update": cmd_grub_update,
5919 + "base": lambda: cmd_base_adopt(args),
5920 + "base-adopt": lambda: cmd_base_adopt(args),
5646 5921 }
5647 5922
5648 5923 fn = WRITE_COMMANDS.get(cmd)
5649 5924 new file mode 100644
@@ -0,0 +1,120 @@
1 +{
2 + "active_deployment": "ACTIVE",
3 + "all_installed": "All packages are already installed.",
4 + "all_up_to_date": "All packages are up to date.",
5 + "autoremove_none": "No orphaned packages.",
6 + "autoremove_ok": "Removed {} orphaned packages.",
7 + "base_adopt_hint": "Adopt them (image files get replaced by repo packages): sudo pag base adopt",
8 + "base_adopt_plan": "Adopting {} base packages from the repo (~{:.0f} MB):",
9 + "base_adoptable": "Adoptable from repo",
10 + "base_all_managed": "Every base package is already managed by pag.",
11 + "base_dry_run": "Dry run – nothing was installed.",
12 + "base_iso_version": "Image version",
13 + "base_more": "more",
14 + "base_no_manifest": "This system carries no base manifest (/usr/share/pag/base.json) – nothing to adopt.",
15 + "base_nothing_selected": "None of the given names is on the adopt list.",
16 + "base_overwrite": "{} comes from the ISO image – its files will be replaced (backup kept for 'pag rollback').",
17 + "base_reboot_hint": "Base adopted from the repo – reboot before using the new libraries/toolchain.",
18 + "base_title": "Base from the ISO image",
19 + "base_total": "Base packages (from image)",
20 + "base_tracked": "Managed by pag",
21 + "base_unmanaged_hint": "{} packages from the ISO image are not managed by pag yet – 'sudo pag base adopt' replaces them with repo packages (only then does 'pag upgrade' update them).",
22 + "base_unmatched": "No counterpart in repo",
23 + "base_unmatched_hint": "These stay at the image version (no such package in repo):",
24 + "cache_cleared": "{} files ({:.2f} MB) cleared from cache.",
25 + "cache_ro": "Repo cache is read-only ({cache}) – using local index (may be outdated).\n Refresh as root: sudo pag sync",
26 + "cancelled": "Cancelled.",
27 + "conf_pacnew": "Modified config kept; new version saved as {path}",
28 + "conf_pacsave": "Modified config kept as {path}",
29 + "continue_q": "Continue? [Y/n] ",
30 + "db_lock_hint": "If no other pag process is running, wait a moment and retry.",
31 + "db_locked": "Another pag instance is running.",
32 + "deploy_cleanup_none": "No deployments to clean (minimum {}).",
33 + "deploy_cleanup_ok": "Removed {} old deployments.",
34 + "deploy_rollback_fail": "No previous deployment.",
35 + "deploy_rollback_ok": "Switched to deployment: {}",
36 + "deployments_list": "Deployments ({}):",
37 + "download_fail": "download failed",
38 + "downloaded": "Downloaded {} to cache ({:.2f} MB).",
39 + "downloading": "Downloading",
40 + "flatpak_adding": "Adding Flathub remote...",
41 + "flatpak_found": "Found {} results:",
42 + "flatpak_info_branch": "Branch",
43 + "flatpak_info_desc": "Description",
44 + "flatpak_info_id": "ID",
45 + "flatpak_info_origin": "Origin",
46 + "flatpak_info_size": "Installed size",
47 + "flatpak_info_version": "Version",
48 + "flatpak_install_prompt": "Install {}? [Y/n] ",
49 + "flatpak_installed": "Flatpak {} installed.",
50 + "flatpak_installing": "Installing {}...",
51 + "flatpak_menu_fix": "Add /var/lib/flatpak/exports/share to XDG_DATA_DIRS (and .../exports/bin to PATH) in your session, then re-login – PaganDE does this in session/pagande-session.",
52 + "flatpak_menu_hint": "Installed and verified, but this session may not show it in the menu: Flatpak exports are missing from XDG_DATA_DIRS.",
53 + "flatpak_missing": "Flatpak is not installed.",
54 + "flatpak_not_found": "not found on Flathub",
55 + "flatpak_not_installed": "Flatpak {} is not installed.",
56 + "flatpak_removed": "Flatpak {} removed.",
57 + "flatpak_scope": "Installation",
58 + "flatpak_searching": "Searching Flathub for '{}'...",
59 + "flatpak_updated": "Flatpaks updated.",
60 + "flatpak_usage": "Usage: pag flatpak <search|install|remove|list|update|info> [args]",
61 + "gpg_fail": "GPG verification failed",
62 + "gpg_missing": "GNUPG MISSING – install gnupg and retry",
63 + "indexes_refreshed": "Indexes refreshed.",
64 + "install_failed": "installation failed",
65 + "installed": "Installed {} packages.",
66 + "key_add_failed": "Key import failed (gpg error) – key was NOT added.",
67 + "key_imported": "Key imported successfully.",
68 + "key_removed": "Key removed: {}",
69 + "new": "NEW",
70 + "no_deployments": "No deployments.",
71 + "no_history": "No transaction history.",
72 + "no_index": "Cannot fetch repository indexes. Run 'pag update'.",
73 + "no_keys": "No trusted GPG keys.",
74 + "no_pinned": "No pinned packages.",
75 + "no_tty": "No TTY / stdin closed (EOF) – cancelling.",
76 + "not_found": "not found in repos",
77 + "not_found_hint": "Check the spelling or run 'pag search <query>'.",
78 + "not_pinned": "was not pinned.",
79 + "orphans_found": "Orphaned dependencies ({}): {}",
80 + "pinned_list": "Pinned packages ({}):",
81 + "pinned_to": "pinned to",
82 + "pkg_not_found": "Package not found: {} (not in any repo)",
83 + "provides_conflict": "Multiple providers for '{name}' ({providers}) – using '{chosen}'",
84 + "provides_mapped": "{} → {} (provides)",
85 + "removing": "Removing",
86 + "repo_added": "Added repository: {}",
87 + "repo_exists": "Repository already exists: {}",
88 + "rollback_files": "Rolled back {} files.",
89 + "rollback_restored": "Restored previous state from snapshot.",
90 + "root_required": "pag requires root privileges (sudo).",
91 + "sec_audit": "{pkg} installed by {user}",
92 + "sec_badname": "Invalid package name: {name}",
93 + "sec_conflict": "File conflict: {path} owned by {owner}",
94 + "sec_downgrade": "Downgrade blocked: {pkg} {new} < {old}",
95 + "sec_https": "HTTPS required for repos",
96 + "sec_locked": "Another pag process is running",
97 + "sec_suid": "SUID stripped from {path}",
98 + "sec_toobig": "Package too large: {size_mb}MB > {max_mb}MB",
99 + "sha256_mismatch": "SHA256 mismatch",
100 + "ssl_broken": "Python has no working ssl module (HTTPS impossible) – fix the python/openssl packages (e.g. sudo pag install -f python).",
101 + "stats_base": "Base (image) managed",
102 + "stats_cache": "Cache size",
103 + "stats_files": "Tracked files",
104 + "stats_history": "Transactions",
105 + "stats_last_update": "Last update",
106 + "stats_packages": "Installed packages",
107 + "stats_size": "Total size",
108 + "stats_title": "PAG Statistics",
109 + "to_install": "To install: {} packages ({:.2f} MB)",
110 + "unpinned": "unpinned.",
111 + "updated_done": "Index refresh complete. {} packages cached.",
112 + "updates_available": "⚠ {} packages have updates – run: pag update",
113 + "upgrading": "Upgrading: {} packages",
114 + "usage": "pag v3 – Pagan Linux Package Manager\n\nBASIC:\n pag install <pkg>... Install packages\n pag remove <pkg>... Remove packages\n pag update Update PACKAGES (refreshes indexes first)\n pag sync Refresh indexes + show pending package updates\n pag upgrade Update SYSTEM (packages + kernel/initramfs/GRUB)\n pag list [--installed] List available / installed\n pag search <query> Search packages\n pag info <pkg> Package details\n pag files <pkg> List package files\n pag verify [--deep] Verify integrity (--deep = SHA256 per file)\n pag clean Clear download cache\n pag stats System statistics\n pag download <pkg>... Download packages to cache (offline prep)\n\nROLLING (base baked into the image):\n pag base [status] Image packages vs. repo (what pag manages)\n pag base adopt [pkg...] Adopt base packages from the repo (--dry-run = preview)\n\nSECURITY:\n pag key-add <url|file> Import GPG key\n pag key-list List trusted keys\n pag key-remove <id> Remove key\n pag key-trust <repo> Pin repo signing key fingerprint (no TOFU)\n pag key-untrust <repo> Forget repo fingerprint (back to TOFU)\n pag key-trusted List pinned repo fingerprints\n\nADVANCED:\n pag why <pkg> Show why a package is installed\n pag autoremove Auto-remove orphaned dependencies\n pag pin <pkg> [ver] Pin package version\n pag unpin <pkg> Unpin\n pag pinned List pinned\n pag history Transaction history\n pag rollback Rollback last transaction\n pag remove-orphans Remove orphaned deps\n pag repo-add <url> [name] Add repository (drop-in /etc/pag/repos/)\n pag repo-list List repositories\n pag sbom export [fmt] SBOM manifest (spdx|cyclonedx)\n\nFLATPAK:\n pag flatpak [<query>] Search & install (smart)\n pag flatpak search <q> Search Flathub\n pag flatpak install <id> Install flatpak\n pag flatpak remove <id> Remove flatpak\n pag flatpak list List installed flatpaks\n pag flatpak update Update all flatpaks\n pag flatpak info <id> Show flatpak details\n\nIMMUTABLE OS (PAG_IMMUTABLE=1):\n pag deploy-list List all deployments\n pag deploy-rollback Switch to previous deployment\n pag deploy-cleanup [N] Remove old deployments (keep last N, default 3)\n pag initramfs-update Rebuild initramfs for current kernel/deployment\n pag grub-update Regenerate GRUB entries for all deployments\n",
115 + "verify_errors": "{} problems found:",
116 + "verify_ok": "All {} files intact.",
117 + "why_dependency": "dependency of",
118 + "why_explicit": "explicitly installed",
119 + "why_not_installed": "not installed"
120 +}
0 121 new file mode 100644
@@ -0,0 +1,128 @@
1 +{
2 + "active_deployment": "AKTYWNY",
3 + "all_installed": "Wszystkie pakiety są już zainstalowane.",
4 + "all_up_to_date": "Wszystkie pakiety są aktualne.",
5 + "autoremove_none": "Brak osieroconych pakietów.",
6 + "autoremove_ok": "Usunięto {} osieroconych pakietów.",
7 + "base_adopt_hint": "Adoptuj (pliki z obrazu zostaną zastąpione pakietami z repo): sudo pag base adopt",
8 + "base_adopt_plan": "Adoptowanie {} pakietów bazy z repo (~{:.0f} MB):",
9 + "base_adoptable": "Do adoptowania z repo",
10 + "base_all_managed": "Wszystkie pakiety bazy są już zarządzane przez pag.",
11 + "base_dry_run": "Próba na sucho – nic nie zainstalowano.",
12 + "base_iso_version": "Wersja obrazu",
13 + "base_more": "więcej",
14 + "base_no_manifest": "Ten system nie ma manifestu bazy (/usr/share/pag/base.json) – nie ma czego adoptować.",
15 + "base_nothing_selected": "Żadna z podanych nazw nie jest na liście do adoptowania.",
16 + "base_overwrite": "{} pochodzi z obrazu ISO – pliki zostaną zastąpione (kopia zapasowa dla 'pag rollback').",
17 + "base_reboot_hint": "Baza zaadoptowana z repo – zrestartuj system, zanim zaczniesz używać nowych bibliotek/narzędzi.",
18 + "base_title": "Baza z obrazu ISO",
19 + "base_total": "Pakiety bazy (z obrazu)",
20 + "base_tracked": "Zarządzane przez pag",
21 + "base_unmanaged_hint": "{} pakietów z obrazu ISO nie jest jeszcze zarządzanych przez pag – 'sudo pag base adopt' zamieni je na pakiety z repo (dopiero wtedy 'pag upgrade' je aktualizuje).",
22 + "base_unmatched": "Bez odpowiednika w repo",
23 + "base_unmatched_hint": "Te zostaną w wersji z obrazu (brak takiego pakietu w repo):",
24 + "cache_cleared": "{} plików ({:.2f} MB) usuniętych z cache.",
25 + "cache_ro": "Cache repozytoriów jest tylko-do-odczytu ({cache}) – używam lokalnego indeksu (może być nieaktualny).\n Odśwież jako root: sudo pag sync",
26 + "cancelled": "Anulowano.",
27 + "conf_pacnew": "Zmieniony plik konfiguracyjny zachowany; nowa wersja: {path}",
28 + "conf_pacsave": "Zmieniony plik konfiguracyjny zachowany jako {path}",
29 + "continue_q": "Kontynuować? [T/n] ",
30 + "db_lock_hint": "Jeśli żaden inny proces pag nie działa, poczekaj chwilę i spróbuj ponownie.",
31 + "db_locked": "Inna instancja pag jest uruchomiona.",
32 + "deploy_cleanup_none": "Nie ma deploymentów do wyczyszczenia (minimum {}).",
33 + "deploy_cleanup_ok": "Usunięto {} starych deploymentów.",
34 + "deploy_rollback_fail": "Brak poprzedniego deploymentu.",
35 + "deploy_rollback_ok": "Przełączono na deployment: {}",
36 + "deployments_list": "Deploymenty ({}):",
37 + "download_fail": "błąd pobierania",
38 + "downloaded": "Pobrano {} do cache ({:.2f} MB).",
39 + "downloading": "Pobieranie",
40 + "flatpak_adding": "Dodaję zdalne repozytorium Flathub...",
41 + "flatpak_found": "Znaleziono {} wyników:",
42 + "flatpak_info_branch": "Gałąź",
43 + "flatpak_info_desc": "Opis",
44 + "flatpak_info_id": "ID",
45 + "flatpak_info_origin": "Źródło",
46 + "flatpak_info_size": "Rozmiar",
47 + "flatpak_info_version": "Wersja",
48 + "flatpak_install_prompt": "Zainstalować {}? [T/n] ",
49 + "flatpak_installed": "Flatpak {} zainstalowany.",
50 + "flatpak_installing": "Instalowanie {}...",
51 + "flatpak_menu_fix": "Dodaj /var/lib/flatpak/exports/share do XDG_DATA_DIRS (a .../exports/bin do PATH) w sesji i zaloguj się ponownie – PaganDE robi to w session/pagande-session.",
52 + "flatpak_menu_hint": "Zainstalowano i zweryfikowano, ale sesja może jej nie pokazać w menu: brak eksportów Flatpaka w XDG_DATA_DIRS.",
53 + "flatpak_missing": "Flatpak nie jest zainstalowany.",
54 + "flatpak_not_found": "nie znaleziono we Flathub",
55 + "flatpak_not_installed": "Flatpak {} nie jest zainstalowany.",
56 + "flatpak_removed": "Flatpak {} usunięty.",
57 + "flatpak_scope": "Instalacja",
58 + "flatpak_searching": "Szukam '{}' we Flathub...",
59 + "flatpak_updated": "Flapaki zaktualizowane.",
60 + "flatpak_usage": "Użycie: pag flatpak <search|install|remove|list|update|info> [args]",
61 + "gpg_fail": "błąd weryfikacji GPG",
62 + "gpg_missing": "BRAK GNUPG – zainstaluj gnupg i spróbuj ponownie",
63 + "indexes_refreshed": "Indeksy odświeżone.",
64 + "install_failed": "błąd instalacji",
65 + "installed": "Zainstalowano {} pakietów.",
66 + "key_add_failed": "Import klucza nie powiódł się (błąd gpg) – klucz NIE został dodany.",
67 + "key_imported": "Klucz zaimportowany pomyślnie.",
68 + "key_removed": "Klucz usunięty: {}",
69 + "new": "NOWY",
70 + "no_deployments": "Brak deploymentów.",
71 + "no_history": "Brak historii transakcji.",
72 + "no_index": "Nie można pobrać indeksów repozytoriów. Uruchom 'pag update'.",
73 + "no_keys": "Brak zaufanych kluczy GPG.",
74 + "no_pinned": "Brak przypiętych pakietów.",
75 + "no_tty": "Brak terminala (EOF) – anuluję.",
76 + "not_found": "brak w repozytoriach",
77 + "not_found_hint": "Sprawdź pisownię lub uruchom 'pag search <fraza>'.",
78 + "not_pinned": "nie był przypięty.",
79 + "orphans_found": "Osierocone zależności ({}): {}",
80 + "pinned_list": "Przypięte pakiety ({}):",
81 + "pinned_to": "przypięty do",
82 + "pkg_not_found": "Nie znaleziono pakietu: {} (brak w repozytoriach)",
83 + "provides_conflict": "Wielu dostawców dla '{name}' ({providers}) – używam '{chosen}'",
84 + "provides_mapped": "{} → {} (provides)",
85 + "removing": "Usuwanie",
86 + "repo_added": "Dodano repozytorium: {}",
87 + "repo_exists": "Repozytorium już istnieje: {}",
88 + "rollback_files": "Wycofano {} plików.",
89 + "rollback_restored": "Przywrócono poprzedni stan z migawki.",
90 + "root_required": "pag wymaga uprawnień root (sudo).",
91 + "sec_audit": "{pkg} installed by {user}",
92 + "sec_audit_pl": "{pkg} zainstalowany przez {user}",
93 + "sec_badname": "Invalid package name: {name}",
94 + "sec_badname_pl": "Nieprawidlowa nazwa pakietu: {name}",
95 + "sec_conflict": "File conflict: {path} owned by {owner}",
96 + "sec_conflict_pl": "Konflikt plikow: {path} nalezy do {owner}",
97 + "sec_downgrade": "Downgrade blocked: {pkg} {new} < {old}",
98 + "sec_downgrade_pl": "Blokada downgrade: {pkg} {new} < {old}",
99 + "sec_https": "HTTPS required for repos",
100 + "sec_https_pl": "Repozytorium wymaga HTTPS",
101 + "sec_locked": "Another pag process is running",
102 + "sec_locked_pl": "Inny proces pag juz dziala",
103 + "sec_suid": "SUID stripped from {path}",
104 + "sec_suid_pl": "SUID usuniety z {path}",
105 + "sec_toobig": "Package too large: {size_mb}MB > {max_mb}MB",
106 + "sec_toobig_pl": "Paczka za duza: {size_mb}MB > {max_mb}MB",
107 + "sha256_mismatch": "niezgodność SHA256",
108 + "ssl_broken": "Python bez działającego modułu ssl (HTTPS niemożliwe) – napraw pakiety python/openssl (np. sudo pag install -f python).",
109 + "stats_base": "Baza (obraz) zarządzana",
110 + "stats_cache": "Rozmiar cache",
111 + "stats_files": "Śledzone pliki",
112 + "stats_history": "Transakcje",
113 + "stats_last_update": "Ostatnia aktualizacja",
114 + "stats_packages": "Zainstalowane pakiety",
115 + "stats_size": "Całkowity rozmiar",
116 + "stats_title": "Statystyki PAG",
117 + "to_install": "Do zainstalowania: {} pakietów ({:.2f} MB)",
118 + "unpinned": "odpięty.",
119 + "updated_done": "Odświeżanie zakończone. {} pakietów w cache.",
120 + "updates_available": "⚠ jest {} pakietów do zaktualizowania – wpisz: pag update",
121 + "upgrading": "Aktualizacje: {} pakietów",
122 + "usage": "pag v3 – Pagan Linux Package Manager\n\nPODSTAWOWE:\n pag install <pkg>... Instalacja pakietów\n pag remove <pkg>... Usuwanie pakietów\n pag update Aktualizacja PAKIETÓW (odświeża indeksy)\n pag sync Odśwież indeksy + info o aktualizacjach\n pag upgrade Aktualizacja SYSTEMU (pakiety + kernel/initramfs/GRUB)\n pag list [--installed] Lista dostępnych / zainstalowanych\n pag search <query> Szukaj pakietów\n pag info <pkg> Szczegóły pakietu\n pag files <pkg> Lista plików pakietu\n pag verify [--deep] Weryfikacja integralności\n pag clean Wyczyść cache pobierania\n pag stats Statystyki systemu\n pag download <pkg>... Pobierz do cache (offline)\n\nROLLING (baza wypalona w obrazie):\n pag base [status] Pakiety z obrazu vs repo (czym pag zarządza)\n pag base adopt [pkg...] Adoptuj pakiety bazy z repo (--dry-run = podgląd)\n\nBEZPIECZEŃSTWO:\n pag key-add <url|file> Importuj klucz GPG\n pag key-list Lista zaufanych kluczy\n pag key-remove <id> Usuń klucz\n pag key-trust <repo> Przypnij fingerprint klucza repo (bez TOFU)\n pag key-untrust <repo> Zapomnij fingerprint repo (powrót do TOFU)\n pag key-trusted Lista przypiętych fingerprintów repo\n\nZAAWANSOWANE:\n pag why <pkg> Dlaczego pakiet jest zainstalowany\n pag autoremove Usuń osierocone zależności\n pag pin <pkg> [ver] Przypnij wersję pakietu\n pag unpin <pkg> Odepnij\n pag pinned Lista przypiętych\n pag history Historia transakcji\n pag rollback Cofnij ostatnią transakcję\n pag remove-orphans Usuń osierocone zależności\n pag repo-add <url> [nazwa] Dodaj repozytorium (drop-in w /etc/pag/repos/)\n pag repo-list Lista repozytoriów\n pag sbom export [fmt] Manifest SBOM (spdx|cyclonedx)\n\nFLATPAK:\n pag flatpak [<query>] Szukaj i instaluj\n pag flatpak search <q> Szukaj na Flathub\n pag flatpak install <id> Zainstaluj flatpak\n pag flatpak remove <id> Usuń flatpak\n pag flatpak list Lista zainstalowanych\n pag flatpak update Aktualizuj wszystkie\n pag flatpak info <id> Szczegóły flatpaka\n\nIMMUTABLE OS (PAG_IMMUTABLE=1):\n pag deploy-list Lista wdrożeń\n pag deploy-rollback Przełącz na poprzednie wdrożenie\n pag deploy-cleanup [N] Usuń stare wdrożenia (zachowaj N, domyślnie 3)\n pag initramfs-update Przebuduj initramfs\n pag grub-update Regeneruj wpisy GRUB",
123 + "verify_errors": "Znaleziono {} problemów:",
124 + "verify_ok": "Wszystkie {} plików sprawne.",
125 + "why_dependency": "zależność od",
126 + "why_explicit": "zainstalowany jawnie",
127 + "why_not_installed": "niezainstalowany"
128 +}