fixos 2.2.39__tar.gz → 2.2.41__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fixos-2.2.39 → fixos-2.2.41}/CHANGELOG.md +68 -0
- {fixos-2.2.39 → fixos-2.2.41}/PKG-INFO +24 -11
- {fixos-2.2.39 → fixos-2.2.41}/README.md +23 -10
- {fixos-2.2.39 → fixos-2.2.41}/fixos/__init__.py +1 -1
- fixos-2.2.41/fixos/__main__.py +7 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/cleanup_cmd.py +209 -35
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/quick_snapshot.py +5 -1
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/service_cleanup.py +117 -38
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/service_scanner.py +19 -7
- {fixos-2.2.39 → fixos-2.2.41}/fixos.egg-info/PKG-INFO +24 -11
- {fixos-2.2.39 → fixos-2.2.41}/fixos.egg-info/SOURCES.txt +2 -0
- {fixos-2.2.39 → fixos-2.2.41}/pyproject.toml +1 -1
- {fixos-2.2.39 → fixos-2.2.41}/setup.py +1 -1
- fixos-2.2.41/tests/unit/test_cleanup_cmd.py +194 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_service_cleanup.py +157 -6
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_service_scanner.py +25 -0
- {fixos-2.2.39 → fixos-2.2.41}/.env.example +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/LICENSE +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/MANIFEST.in +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/README.md +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/TEST_RESULTS.md +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/TEST_RESULTS_V2.md +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/alpine/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/arch/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/base/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/broken-audio/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/broken-full/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/broken-network/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/broken-thumbnails/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/debian/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/docker-compose.multi-system.yml +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/docker-compose.yml +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/fedora/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/test-multi-system.sh +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/test-scenarios.sh +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/ubuntu/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docker/validate-scenario.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docs/examples/advanced_usage.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/docs/examples/quickstart.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/agent/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/agent/autonomous.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/agent/autonomous_session.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/agent/hitl.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/agent/hitl_session.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/agent/session_core.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/agent/session_handlers.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/agent/session_io.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/anonymizer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/_cleanup_flatpak.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/_cleanup_home.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/_cleanup_snap.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/_cleanup_system.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/_cleanup_utils.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/ask_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/config_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/features_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/fix_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/history_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/main.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/orchestrate_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/output_formatter.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/profile_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/projects_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/provider_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/quick_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/quickfix_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/report_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/rollback_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/scan_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/shared.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/token_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli/watch_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/cli.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/config.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/config_interactive.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/constants.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/_flatpak_analysis_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/_flatpak_execution_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/_flatpak_recommendations_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/_storage_container_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/_storage_system_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/_storage_user_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/cache_discovery.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/checks/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/checks/_shared.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/checks/audio.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/checks/file_analysis.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/checks/hardware.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/checks/packages.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/checks/resources.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/checks/security.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/checks/storage_optimization.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/checks/system_core.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/checks/thumbnails.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/dev_project_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/disk_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/flatpak_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/project_scanner.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/service_details.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/storage_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/system_checks.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/diagnostics/utils.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/features/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/features/auditor.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/features/catalog.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/features/installer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/features/profiles.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/features/renderer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/fixes/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/interactive/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/interactive/cleanup_planner.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/llm_shell.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/orchestrator/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/orchestrator/executor.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/orchestrator/graph.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/orchestrator/orchestrator.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/orchestrator/rollback.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/platform_utils.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/plugins/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/plugins/base.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/plugins/builtin/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/plugins/builtin/audio.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/plugins/builtin/disk.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/plugins/builtin/hardware.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/plugins/builtin/resources.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/plugins/builtin/security.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/plugins/builtin/thumbnails.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/plugins/registry.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/profiles/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/providers/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/providers/llm.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/providers/llm_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/providers/schemas.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/system_checks.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/utils/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/utils/anonymizer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/utils/terminal.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/utils/timeout.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/utils/web_search.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos/watch.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos.egg-info/dependency_links.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos.egg-info/entry_points.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos.egg-info/requires.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/fixos.egg-info/top_level.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/pytest.ini +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/requirements-dev.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/requirements.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/scripts/pyqual-calibrate.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/setup.cfg +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/conftest.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/e2e/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/e2e/test_anonymization_layers.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/e2e/test_audio_broken.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/e2e/test_cli.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/e2e/test_diagnostics_integration.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/e2e/test_executor.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/e2e/test_multi_system.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/e2e/test_network_broken.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/e2e/test_thumbnails_broken.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/test_fixos.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_anonymizer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_cache_discovery.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_core.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_dev_project_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_executor.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_llm_provider.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_orchestrator.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_project_scanner.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_projects_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_quick_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_quick_snapshot.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_resources_quick.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_security_quick.py +0 -0
- {fixos-2.2.39 → fixos-2.2.41}/tests/unit/test_system_checks_parallel.py +0 -0
|
@@ -8,9 +8,41 @@
|
|
|
8
8
|
dnia oraz alarmami o szybkim wzroście dysku, RAM, swapu lub obciążenia CPU.
|
|
9
9
|
- Rozpoznawanie systemu, profilu użytkownika i stosu technologicznego oraz
|
|
10
10
|
opcjonalne przejście do wolniejszej analizy przez `fixos quick --deep`.
|
|
11
|
+
- Uporządkowana dokumentacja użytkownika: szybki start, model bezpieczeństwa
|
|
12
|
+
cleanup, aktualna architektura i rozdzielenie aktywnego TODO od archiwalnych
|
|
13
|
+
artykułów.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Zakończone elementy historycznych roadmap zostały przeniesione z TODO do
|
|
18
|
+
changelogu: modułowy pakiet CLI, klasowe sesje HITL, wspólny
|
|
19
|
+
`SessionTimeout`, plugin registry, structured output LLM, rollback, profile
|
|
20
|
+
diagnostyczne i watch mode.
|
|
21
|
+
- `TODO.md` zawiera teraz wyłącznie ręcznie zweryfikowane, aktualne zadania;
|
|
22
|
+
usunięto nieaktualny raport statyczny z 311 wpisami opartymi na dawnych
|
|
23
|
+
numerach linii i fałszywych alarmach.
|
|
11
24
|
|
|
12
25
|
### Fixed
|
|
13
26
|
|
|
27
|
+
- Zablokowano zbiorcze kasowanie chronionych danych LM Studio, Hugging Face,
|
|
28
|
+
Podman/containerd, Jupyter, Minikube, AppImage, VirtualBox, VMware oraz
|
|
29
|
+
rozszerzeń VS Code/Cursor. Takie wpisy pokazują teraz wyłącznie bezpieczny
|
|
30
|
+
podgląd i wymagają ręcznego wskazania konkretnego elementu poza fixOS.
|
|
31
|
+
- Doprecyzowano estymatę Dockera: wartość `RECLAIMABLE` jest informacyjna,
|
|
32
|
+
natomiast ograniczony filtr cache buildów starszych niż 7 dni może zwolnić
|
|
33
|
+
znacznie mniej miejsca.
|
|
34
|
+
- Tryb `fixos cleanup` → „Wybierz pojedyncze” przechodzi teraz kolejno przez
|
|
35
|
+
wszystkie usługi: bezpieczne, wymagające przeglądu i chronione. Pozycje bez
|
|
36
|
+
bezpiecznej operacji zbiorczej pokazują komendę podglądu, dane chronione
|
|
37
|
+
wymagają dodatkowego potwierdzenia, a wykonanie jest przypięte do dokładnie
|
|
38
|
+
wybranej ścieżki i poziomu ryzyka.
|
|
39
|
+
- Skany cache npm, pnpm, Yarn, Maven i uv obejmują teraz wyłącznie
|
|
40
|
+
odtwarzalne katalogi. `~/.local/share/uv` (narzędzia, interpretery i
|
|
41
|
+
credentials) oraz `.tools` pnpm nie są już błędnie liczone jako bezpieczne
|
|
42
|
+
cache; czyszczenie npm faktycznie obejmuje raportowane `_npx`.
|
|
43
|
+
- Naprawiono scenariusze TestQL i dodano punkt wejścia `python -m fixos`.
|
|
44
|
+
`cleanup -c <chroniona-usługa> --dry-run` pokazuje bezpieczną komendę
|
|
45
|
+
diagnostyczną zamiast kończyć się mylącym błędem.
|
|
14
46
|
- Stabilny raport Docker z osobnym rozmiarem aktywnym i odzyskiwalnym oraz
|
|
15
47
|
poprawnym pomiarem przed/po czyszczeniu.
|
|
16
48
|
- Usunięto niebezpieczne zbiorcze komendy kasowania wolumenów Docker i
|
|
@@ -19,6 +51,42 @@
|
|
|
19
51
|
rekurencyjnych skanów `/` oraz `/home` z szybkich kontroli.
|
|
20
52
|
- Czyszczenie cache JetBrains trafia w aktualną ścieżkę i wymaga zamknięcia IDE.
|
|
21
53
|
|
|
54
|
+
## [2.2.41] - 2026-07-23
|
|
55
|
+
|
|
56
|
+
### Docs
|
|
57
|
+
- Update CHANGELOG.md
|
|
58
|
+
- Update README.md
|
|
59
|
+
|
|
60
|
+
### Test
|
|
61
|
+
- Update tests/unit/test_cleanup_cmd.py
|
|
62
|
+
- Update tests/unit/test_service_cleanup.py
|
|
63
|
+
- Update tests/unit/test_service_scanner.py
|
|
64
|
+
|
|
65
|
+
### Other
|
|
66
|
+
- Update fixos/cli/cleanup_cmd.py
|
|
67
|
+
- Update fixos/diagnostics/service_cleanup.py
|
|
68
|
+
|
|
69
|
+
## [2.2.40] - 2026-07-23
|
|
70
|
+
|
|
71
|
+
### Docs
|
|
72
|
+
- Update CHANGELOG.md
|
|
73
|
+
- Update README.md
|
|
74
|
+
|
|
75
|
+
### Test
|
|
76
|
+
- Update testql-scenarios/generated-cli-tests.testql.toon.yaml
|
|
77
|
+
- Update testql-scenarios/generated-from-pytests.testql.toon.yaml
|
|
78
|
+
- Update tests/unit/test_cleanup_cmd.py
|
|
79
|
+
- Update tests/unit/test_service_cleanup.py
|
|
80
|
+
- Update tests/unit/test_service_scanner.py
|
|
81
|
+
|
|
82
|
+
### Other
|
|
83
|
+
- Update fixos/__main__.py
|
|
84
|
+
- Update fixos/cli/cleanup_cmd.py
|
|
85
|
+
- Update fixos/diagnostics/quick_snapshot.py
|
|
86
|
+
- Update fixos/diagnostics/service_cleanup.py
|
|
87
|
+
- Update fixos/diagnostics/service_scanner.py
|
|
88
|
+
- Update uv.lock
|
|
89
|
+
|
|
22
90
|
## [2.2.39] - 2026-07-23
|
|
23
91
|
|
|
24
92
|
### Docs
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fixos
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.41
|
|
4
4
|
Summary: AI-powered Linux/Windows diagnostics and repair – audio, hardware, system issues
|
|
5
5
|
Home-page: https://github.com/wronai/fixos
|
|
6
6
|
Author: fixos contributors
|
|
@@ -63,11 +63,11 @@ AI-powered OS Diagnostics
|
|
|
63
63
|
|
|
64
64
|
## AI Cost Tracking
|
|
65
65
|
|
|
66
|
-
    
|
|
67
|
+
  
|
|
68
68
|
|
|
69
|
-
- 🤖 **LLM usage:** $4.
|
|
70
|
-
- 👤 **Human dev:** ~$
|
|
69
|
+
- 🤖 **LLM usage:** $4.8653 (149 commits)
|
|
70
|
+
- 👤 **Human dev:** ~$3913 (39.1h @ $100/h, 30min dedup)
|
|
71
71
|
|
|
72
72
|
Generated on 2026-07-23 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
73
73
|
|
|
@@ -205,6 +205,8 @@ Pierwsze uruchomienie zapisuje mały punkt odniesienia w
|
|
|
205
205
|
swapu i znanych cache w wybranym oknie oraz od początku bieżącego dnia. Kwota
|
|
206
206
|
„bezpieczne cache” obejmuje wyłącznie jawnie odtwarzalne dane. Docker, modele
|
|
207
207
|
AI, rozszerzenia i cache IDE są raportowane osobno jako wymagające decyzji.
|
|
208
|
+
Nie są do niej zaliczane m.in. narzędzia i interpretery z
|
|
209
|
+
`~/.local/share/uv`, `.tools` pnpm, modele AI ani rozszerzenia edytorów.
|
|
208
210
|
|
|
209
211
|
### Przykładowy widok w terminalu (Czyszczenie dysku)
|
|
210
212
|
|
|
@@ -258,15 +260,24 @@ Tryb DRY-RUN - żadne akcje nie zostaną wykonane
|
|
|
258
260
|
Każda znaleziona usługa jest klasyfikowana do jednej z trzech grup:
|
|
259
261
|
|
|
260
262
|
- **bezpieczne** – cache do odtworzenia jednym poleceniem (pip/npm/cargo/conda/nix/brew...).
|
|
261
|
-
|
|
263
|
+
Tylko tę grupę można usunąć automatycznie opcją „wszystkie”.
|
|
262
264
|
- **do rozważenia** – reinstalowalne aplikacje, dane długo nieużywane, nierozpoznane
|
|
263
|
-
foldery (JetBrains, Snap, Flatpak) – pokazywane z
|
|
265
|
+
foldery (JetBrains, Snap, Flatpak) – pokazywane z komendą i wymagają
|
|
266
|
+
osobnego, świadomego potwierdzenia.
|
|
264
267
|
- **chronione lub mieszane** – realne dane aplikacji albo magazyny łączące dane aktywne
|
|
265
268
|
z cache (Ollama, LM Studio, HuggingFace hub, Docker/Podman/containerd, cała biblioteka
|
|
266
269
|
Steam, `.cursor/extensions`/`.vscode/extensions`
|
|
267
270
|
– zainstalowane rozszerzenia edytora, nie ich cache). Osobna sekcja z ostrzeżeniem;
|
|
268
|
-
zbiorcze kasowanie modeli
|
|
269
|
-
`SIZE` i `RECLAIMABLE`;
|
|
271
|
+
zbiorcze kasowanie modeli, klastrów, maszyn wirtualnych, rozszerzeń i
|
|
272
|
+
wolumenów jest wyłączone. Docker pokazuje osobno `SIZE` i `RECLAIMABLE`;
|
|
273
|
+
domyślne czyszczenie ogranicza się do starego cache buildów. Raportowane
|
|
274
|
+
`RECLAIMABLE` jest górną informacją z Dockera — filtr starszy niż 7 dni może
|
|
275
|
+
faktycznie zwolnić znacznie mniej.
|
|
276
|
+
|
|
277
|
+
Opcja „Wybierz pojedyncze” przechodzi kolejno przez wszystkie znalezione
|
|
278
|
+
usługi w tych trzech grupach. Dla pozycji bez bezpiecznej operacji zbiorczej
|
|
279
|
+
wyświetla wyłącznie komendę podglądu. Pozycje chronione wymagają dodatkowego
|
|
280
|
+
potwierdzenia.
|
|
270
281
|
|
|
271
282
|
### `fixos projects` – skaner artefaktów w projektach deweloperskich
|
|
272
283
|
|
|
@@ -565,7 +576,8 @@ fixos/
|
|
|
565
576
|
|
|
566
577
|
## 📋 Roadmap
|
|
567
578
|
|
|
568
|
-
|
|
579
|
+
Aktualne, ręcznie zweryfikowane zadania znajdują się w [TODO.md](./TODO.md).
|
|
580
|
+
Historyczne artykuły i plany są przechowywane w katalogu [TODO/](./TODO/).
|
|
569
581
|
|
|
570
582
|
---
|
|
571
583
|
|
|
@@ -620,7 +632,8 @@ fixos orchestrate --dry-run
|
|
|
620
632
|
|
|
621
633
|
### 🔗 Linki
|
|
622
634
|
- **GitHub**: https://github.com/wronai/fixos
|
|
623
|
-
- **
|
|
635
|
+
- **Dokumentacja**: [docs/README.md](./docs/README.md)
|
|
636
|
+
- **Aktualne zadania**: [TODO.md](./TODO.md)
|
|
624
637
|
---
|
|
625
638
|
|
|
626
639
|
## Licencja
|
|
@@ -19,11 +19,11 @@ AI-powered OS Diagnostics
|
|
|
19
19
|
|
|
20
20
|
## AI Cost Tracking
|
|
21
21
|
|
|
22
|
-
    
|
|
23
|
+
  
|
|
24
24
|
|
|
25
|
-
- 🤖 **LLM usage:** $4.
|
|
26
|
-
- 👤 **Human dev:** ~$
|
|
25
|
+
- 🤖 **LLM usage:** $4.8653 (149 commits)
|
|
26
|
+
- 👤 **Human dev:** ~$3913 (39.1h @ $100/h, 30min dedup)
|
|
27
27
|
|
|
28
28
|
Generated on 2026-07-23 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
29
29
|
|
|
@@ -161,6 +161,8 @@ Pierwsze uruchomienie zapisuje mały punkt odniesienia w
|
|
|
161
161
|
swapu i znanych cache w wybranym oknie oraz od początku bieżącego dnia. Kwota
|
|
162
162
|
„bezpieczne cache” obejmuje wyłącznie jawnie odtwarzalne dane. Docker, modele
|
|
163
163
|
AI, rozszerzenia i cache IDE są raportowane osobno jako wymagające decyzji.
|
|
164
|
+
Nie są do niej zaliczane m.in. narzędzia i interpretery z
|
|
165
|
+
`~/.local/share/uv`, `.tools` pnpm, modele AI ani rozszerzenia edytorów.
|
|
164
166
|
|
|
165
167
|
### Przykładowy widok w terminalu (Czyszczenie dysku)
|
|
166
168
|
|
|
@@ -214,15 +216,24 @@ Tryb DRY-RUN - żadne akcje nie zostaną wykonane
|
|
|
214
216
|
Każda znaleziona usługa jest klasyfikowana do jednej z trzech grup:
|
|
215
217
|
|
|
216
218
|
- **bezpieczne** – cache do odtworzenia jednym poleceniem (pip/npm/cargo/conda/nix/brew...).
|
|
217
|
-
|
|
219
|
+
Tylko tę grupę można usunąć automatycznie opcją „wszystkie”.
|
|
218
220
|
- **do rozważenia** – reinstalowalne aplikacje, dane długo nieużywane, nierozpoznane
|
|
219
|
-
foldery (JetBrains, Snap, Flatpak) – pokazywane z
|
|
221
|
+
foldery (JetBrains, Snap, Flatpak) – pokazywane z komendą i wymagają
|
|
222
|
+
osobnego, świadomego potwierdzenia.
|
|
220
223
|
- **chronione lub mieszane** – realne dane aplikacji albo magazyny łączące dane aktywne
|
|
221
224
|
z cache (Ollama, LM Studio, HuggingFace hub, Docker/Podman/containerd, cała biblioteka
|
|
222
225
|
Steam, `.cursor/extensions`/`.vscode/extensions`
|
|
223
226
|
– zainstalowane rozszerzenia edytora, nie ich cache). Osobna sekcja z ostrzeżeniem;
|
|
224
|
-
zbiorcze kasowanie modeli
|
|
225
|
-
`SIZE` i `RECLAIMABLE`;
|
|
227
|
+
zbiorcze kasowanie modeli, klastrów, maszyn wirtualnych, rozszerzeń i
|
|
228
|
+
wolumenów jest wyłączone. Docker pokazuje osobno `SIZE` i `RECLAIMABLE`;
|
|
229
|
+
domyślne czyszczenie ogranicza się do starego cache buildów. Raportowane
|
|
230
|
+
`RECLAIMABLE` jest górną informacją z Dockera — filtr starszy niż 7 dni może
|
|
231
|
+
faktycznie zwolnić znacznie mniej.
|
|
232
|
+
|
|
233
|
+
Opcja „Wybierz pojedyncze” przechodzi kolejno przez wszystkie znalezione
|
|
234
|
+
usługi w tych trzech grupach. Dla pozycji bez bezpiecznej operacji zbiorczej
|
|
235
|
+
wyświetla wyłącznie komendę podglądu. Pozycje chronione wymagają dodatkowego
|
|
236
|
+
potwierdzenia.
|
|
226
237
|
|
|
227
238
|
### `fixos projects` – skaner artefaktów w projektach deweloperskich
|
|
228
239
|
|
|
@@ -521,7 +532,8 @@ fixos/
|
|
|
521
532
|
|
|
522
533
|
## 📋 Roadmap
|
|
523
534
|
|
|
524
|
-
|
|
535
|
+
Aktualne, ręcznie zweryfikowane zadania znajdują się w [TODO.md](./TODO.md).
|
|
536
|
+
Historyczne artykuły i plany są przechowywane w katalogu [TODO/](./TODO/).
|
|
525
537
|
|
|
526
538
|
---
|
|
527
539
|
|
|
@@ -576,7 +588,8 @@ fixos orchestrate --dry-run
|
|
|
576
588
|
|
|
577
589
|
### 🔗 Linki
|
|
578
590
|
- **GitHub**: https://github.com/wronai/fixos
|
|
579
|
-
- **
|
|
591
|
+
- **Dokumentacja**: [docs/README.md](./docs/README.md)
|
|
592
|
+
- **Aktualne zadania**: [TODO.md](./TODO.md)
|
|
580
593
|
---
|
|
581
594
|
|
|
582
595
|
## Licencja
|
|
@@ -55,7 +55,8 @@ def _display_cleanup_summary(plan: dict, threshold: int) -> None:
|
|
|
55
55
|
if reclaimable:
|
|
56
56
|
click.echo(
|
|
57
57
|
click.style(
|
|
58
|
-
f" Odzyskiwalne wg menedżerów usług
|
|
58
|
+
f" Odzyskiwalne wg menedżerów usług (informacyjnie, nie plan "
|
|
59
|
+
f"automatyczny): {reclaimable:.2f} GB",
|
|
59
60
|
fg="cyan",
|
|
60
61
|
)
|
|
61
62
|
)
|
|
@@ -79,9 +80,7 @@ def _display_service_item(svc: dict) -> None:
|
|
|
79
80
|
risk = svc.get("risk_level") or ("safe" if svc["safe_to_cleanup"] else "review")
|
|
80
81
|
safe_text, safe_color = _RISK_LABELS.get(risk, _RISK_LABELS["review"])
|
|
81
82
|
|
|
82
|
-
click.echo(
|
|
83
|
-
f" {click.style(svc['name'], fg='yellow', bold=True)} - {size_str}"
|
|
84
|
-
)
|
|
83
|
+
click.echo(f" {click.style(svc['name'], fg='yellow', bold=True)} - {size_str}")
|
|
85
84
|
click.echo(f" {svc['description']}")
|
|
86
85
|
paths = svc.get("details", {}).get("paths") or [svc["path"]]
|
|
87
86
|
if len(paths) > 1:
|
|
@@ -90,7 +89,9 @@ def _display_service_item(svc: dict) -> None:
|
|
|
90
89
|
click.echo(f" • {path}")
|
|
91
90
|
else:
|
|
92
91
|
click.echo(f" Ścieżka: {svc['path']}")
|
|
93
|
-
click.echo(
|
|
92
|
+
click.echo(
|
|
93
|
+
f" {click.style(safe_text, fg=safe_color, bold=(risk == 'dangerous'))}"
|
|
94
|
+
)
|
|
94
95
|
|
|
95
96
|
# Show details for specific services
|
|
96
97
|
if svc.get("details"):
|
|
@@ -134,7 +135,11 @@ def _execute_safe_cleanup(services: list, scanner) -> float:
|
|
|
134
135
|
for svc in services:
|
|
135
136
|
svc_type = svc["service_type"]
|
|
136
137
|
click.echo(f"Czyszczenie {svc_type}...")
|
|
137
|
-
result = scanner.cleanup_service(
|
|
138
|
+
result = scanner.cleanup_service(
|
|
139
|
+
svc_type,
|
|
140
|
+
dry_run=False,
|
|
141
|
+
planned_service=svc,
|
|
142
|
+
)
|
|
138
143
|
if result["success"]:
|
|
139
144
|
freed = result.get("space_freed_gb", 0)
|
|
140
145
|
total_freed += freed
|
|
@@ -294,62 +299,140 @@ def _display_dangerous_services(services: list) -> None:
|
|
|
294
299
|
)
|
|
295
300
|
|
|
296
301
|
|
|
297
|
-
def
|
|
298
|
-
"""
|
|
299
|
-
|
|
302
|
+
def _single_service_target(service_name: str, scanner) -> dict | None:
|
|
303
|
+
"""Resolve ``cleanup -c NAME`` to the safest executable scanned entry.
|
|
304
|
+
|
|
305
|
+
Some service types expose both rebuildable cache and protected data. The
|
|
306
|
+
direct command must pin execution to the cache entry instead of warning
|
|
307
|
+
about extensions/models and then letting a rescan pick whichever entry is
|
|
308
|
+
largest.
|
|
309
|
+
"""
|
|
310
|
+
from fixos.diagnostics.service_scanner import ServiceType
|
|
300
311
|
|
|
301
312
|
try:
|
|
302
313
|
service_enum = ServiceType(service_name)
|
|
303
314
|
except ValueError:
|
|
304
|
-
return
|
|
305
|
-
|
|
306
|
-
|
|
315
|
+
return None
|
|
316
|
+
|
|
317
|
+
entries = scanner.scan_service(service_enum)
|
|
318
|
+
if not entries:
|
|
319
|
+
return None
|
|
320
|
+
|
|
321
|
+
risk_order = {"safe": 0, "review": 1, "dangerous": 2}
|
|
322
|
+
executable = [
|
|
323
|
+
item
|
|
324
|
+
for item in entries
|
|
325
|
+
if item.can_cleanup and item.cleanup_command.strip()
|
|
326
|
+
]
|
|
327
|
+
candidates = executable or entries
|
|
328
|
+
selected = min(
|
|
329
|
+
candidates,
|
|
330
|
+
key=lambda item: (risk_order.get(item.risk_level, 1), -item.size_mb),
|
|
331
|
+
)
|
|
332
|
+
return {
|
|
333
|
+
"service_type": selected.service_type.value,
|
|
334
|
+
"name": selected.name,
|
|
335
|
+
"path": selected.path,
|
|
336
|
+
"size_mb": selected.size_mb,
|
|
337
|
+
"size_gb": selected.size_gb,
|
|
338
|
+
"description": selected.description,
|
|
339
|
+
"can_cleanup": selected.can_cleanup,
|
|
340
|
+
"cleanup_command": selected.cleanup_command,
|
|
341
|
+
"preview_command": selected.preview_command,
|
|
342
|
+
"safe_to_cleanup": selected.safe_to_cleanup,
|
|
343
|
+
"risk_level": selected.risk_level,
|
|
344
|
+
"impact": selected.impact,
|
|
345
|
+
"items_count": selected.items_count,
|
|
346
|
+
"details": selected.details,
|
|
347
|
+
}
|
|
307
348
|
|
|
308
349
|
|
|
309
350
|
def _cleanup_single_service(
|
|
310
351
|
service_name: str, scanner, json_output: bool, dry_run: bool
|
|
311
352
|
) -> None:
|
|
312
353
|
"""Handle cleanup of a single specific service."""
|
|
354
|
+
target = _single_service_target(service_name, scanner)
|
|
355
|
+
|
|
313
356
|
if json_output:
|
|
314
|
-
result = scanner.cleanup_service(
|
|
357
|
+
result = scanner.cleanup_service(
|
|
358
|
+
service_name,
|
|
359
|
+
dry_run=dry_run,
|
|
360
|
+
planned_service=target,
|
|
361
|
+
)
|
|
315
362
|
import json
|
|
316
363
|
|
|
317
364
|
click.echo(json.dumps(result, indent=2, default=str))
|
|
318
365
|
return
|
|
319
366
|
|
|
320
|
-
if
|
|
367
|
+
if target is None:
|
|
368
|
+
click.echo(
|
|
369
|
+
click.style(
|
|
370
|
+
f"Nie znaleziono danych {service_name} powyżej progu.",
|
|
371
|
+
fg="yellow",
|
|
372
|
+
)
|
|
373
|
+
)
|
|
374
|
+
return
|
|
375
|
+
|
|
376
|
+
if not target["can_cleanup"] or not target["cleanup_command"].strip():
|
|
321
377
|
click.echo(
|
|
322
378
|
click.style(
|
|
323
|
-
f"
|
|
324
|
-
"
|
|
325
|
-
"
|
|
379
|
+
f"{target['name']}: zbiorcze czyszczenie jest wyłączone, "
|
|
380
|
+
"ponieważ wpis zawiera chronione dane.",
|
|
381
|
+
fg="yellow",
|
|
382
|
+
bold=True,
|
|
383
|
+
)
|
|
384
|
+
)
|
|
385
|
+
if target.get("preview_command"):
|
|
386
|
+
click.echo(f" Bezpieczny podgląd: {target['preview_command']}")
|
|
387
|
+
click.echo(" Usuń ręcznie tylko konkretny, wcześniej sprawdzony element.")
|
|
388
|
+
return
|
|
389
|
+
|
|
390
|
+
if not dry_run and target.get("risk_level") == "dangerous":
|
|
391
|
+
click.echo(
|
|
392
|
+
click.style(
|
|
393
|
+
f"⚠️ {target['name']} zawiera dane mieszane. fixOS wykona "
|
|
394
|
+
"wyłącznie ograniczoną operację pokazaną poniżej:",
|
|
326
395
|
fg="red",
|
|
327
396
|
bold=True,
|
|
328
397
|
)
|
|
329
398
|
)
|
|
330
|
-
click.echo(f"
|
|
331
|
-
if not click.confirm(f"
|
|
399
|
+
click.echo(f" {target['cleanup_command']}")
|
|
400
|
+
if not click.confirm(f"Wykonać ograniczone czyszczenie {target['name']}?"):
|
|
332
401
|
click.echo("Anulowano.")
|
|
333
402
|
return
|
|
334
403
|
|
|
335
|
-
click.echo(click.style(f"Czyszczenie usługi: {
|
|
404
|
+
click.echo(click.style(f"Czyszczenie usługi: {target['name']}", fg="yellow"))
|
|
336
405
|
if dry_run:
|
|
337
406
|
click.echo(click.style("[TRYB DRY-RUN] - brak faktycznych zmian", fg="cyan"))
|
|
338
407
|
|
|
339
|
-
result = scanner.cleanup_service(
|
|
408
|
+
result = scanner.cleanup_service(
|
|
409
|
+
service_name,
|
|
410
|
+
dry_run=dry_run,
|
|
411
|
+
planned_service=target,
|
|
412
|
+
)
|
|
340
413
|
|
|
341
414
|
if result["success"]:
|
|
342
415
|
if dry_run:
|
|
343
|
-
click.echo(
|
|
416
|
+
click.echo(
|
|
417
|
+
click.style(f"Symulacja dla {service_name} zakończona", fg="green")
|
|
418
|
+
)
|
|
344
419
|
if result.get("output"):
|
|
345
420
|
click.echo(f" {result['output']}")
|
|
346
421
|
if result["space_freed_gb"] > 0:
|
|
347
|
-
|
|
422
|
+
estimate = (
|
|
348
423
|
f" Szacowane maksimum do odzyskania: "
|
|
349
424
|
f"{result['space_freed_gb']:.2f} GB"
|
|
350
425
|
)
|
|
426
|
+
if service_name == "docker":
|
|
427
|
+
estimate += (
|
|
428
|
+
" (cały odzyskiwalny cache buildów wg Docker; "
|
|
429
|
+
"filtr >7 dni zwykle usunie mniej)"
|
|
430
|
+
)
|
|
431
|
+
click.echo(estimate)
|
|
351
432
|
else:
|
|
352
|
-
click.echo(
|
|
433
|
+
click.echo(
|
|
434
|
+
click.style(f"Zakończono czyszczenie {service_name}", fg="green")
|
|
435
|
+
)
|
|
353
436
|
if result["space_freed_gb"] > 0:
|
|
354
437
|
click.echo(f" Zwolniono: {result['space_freed_gb']:.2f} GB")
|
|
355
438
|
else:
|
|
@@ -362,11 +445,15 @@ def _cleanup_single_service(
|
|
|
362
445
|
|
|
363
446
|
|
|
364
447
|
def _size_str(svc: dict) -> str:
|
|
365
|
-
return
|
|
448
|
+
return (
|
|
449
|
+
f"{svc['size_gb']:.2f} GB"
|
|
450
|
+
if svc["size_gb"] >= 1
|
|
451
|
+
else f"{svc['size_mb']:.0f} MB"
|
|
452
|
+
)
|
|
366
453
|
|
|
367
454
|
|
|
368
|
-
def _select_safe_services(safe_services: list) -> list:
|
|
369
|
-
"""
|
|
455
|
+
def _select_safe_services(safe_services: list) -> tuple[str, list]:
|
|
456
|
+
"""Choose bulk-safe cleanup, full individual selection, or no cleanup."""
|
|
370
457
|
click.echo(click.style("Bezpieczne do wyczyszczenia:", fg="green"))
|
|
371
458
|
for svc in safe_services:
|
|
372
459
|
click.echo(f" • {svc['name']}: {_size_str(svc)}")
|
|
@@ -375,28 +462,115 @@ def _select_safe_services(safe_services: list) -> list:
|
|
|
375
462
|
click.echo()
|
|
376
463
|
click.echo("Co wyczyścić?")
|
|
377
464
|
click.echo(f" [1] Wszystkie bezpieczne (zwolni {safe_total:.2f} GB)")
|
|
378
|
-
click.echo(" [2] Wybierz pojedyncze
|
|
465
|
+
click.echo(" [2] Wybierz pojedyncze spośród wszystkich usług")
|
|
379
466
|
click.echo(" [0] Nic — pomiń")
|
|
380
467
|
choice = click.prompt(
|
|
381
468
|
"Wybór", type=click.Choice(["0", "1", "2"]), default="1", show_choices=False
|
|
382
469
|
)
|
|
383
470
|
|
|
384
471
|
if choice == "0":
|
|
385
|
-
return []
|
|
472
|
+
return "none", []
|
|
386
473
|
if choice == "1":
|
|
387
|
-
return safe_services
|
|
474
|
+
return "safe", safe_services
|
|
475
|
+
return "individual", []
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def _selection_description(svc: dict) -> str:
|
|
479
|
+
risk = svc.get("risk_level", "review")
|
|
480
|
+
labels = {
|
|
481
|
+
"safe": "bezpieczne cache",
|
|
482
|
+
"review": "do rozważenia",
|
|
483
|
+
"dangerous": "CHRONIONE/mieszane",
|
|
484
|
+
}
|
|
485
|
+
description = labels.get(risk, "do rozważenia")
|
|
486
|
+
if risk == "dangerous" and svc["service_type"] == "docker":
|
|
487
|
+
reclaimable = svc.get("details", {}).get("usage", {}).get("Build Cache", {})
|
|
488
|
+
reclaimable_gb = float(reclaimable.get("reclaimable_gb", 0))
|
|
489
|
+
if reclaimable_gb:
|
|
490
|
+
description += (
|
|
491
|
+
f"; Docker raportuje {reclaimable_gb:.2f} GB odzyskiwalnego "
|
|
492
|
+
"cache buildów, filtr >7 dni zwykle usunie mniej"
|
|
493
|
+
)
|
|
494
|
+
return description
|
|
388
495
|
|
|
389
|
-
|
|
390
|
-
|
|
496
|
+
|
|
497
|
+
def _select_individual_services(services: list) -> list:
|
|
498
|
+
"""Offer every scanned, executable entry in its displayed order."""
|
|
499
|
+
click.echo(
|
|
500
|
+
click.style(
|
|
501
|
+
"Wybierz kolejno spośród wszystkich możliwych usług:",
|
|
502
|
+
fg="cyan",
|
|
503
|
+
)
|
|
504
|
+
)
|
|
505
|
+
selected = []
|
|
506
|
+
for svc in services:
|
|
507
|
+
label = (
|
|
508
|
+
f" {svc['name']} ({_size_str(svc)}) " f"[{_selection_description(svc)}]"
|
|
509
|
+
)
|
|
510
|
+
if not svc.get("can_cleanup") or not svc.get("cleanup_command", "").strip():
|
|
511
|
+
click.echo(f"{label} — brak bezpiecznej operacji zbiorczej")
|
|
512
|
+
preview = svc.get("preview_command")
|
|
513
|
+
if preview:
|
|
514
|
+
click.echo(f" Podgląd: {preview}")
|
|
515
|
+
continue
|
|
516
|
+
if click.confirm(label, default=False):
|
|
517
|
+
selected.append(svc)
|
|
518
|
+
return selected
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
def _execute_individual_cleanup(services: list, scanner) -> float:
|
|
522
|
+
"""Execute hand-picked entries with an extra gate for protected data."""
|
|
523
|
+
total_freed = 0.0
|
|
524
|
+
for svc in services:
|
|
525
|
+
risk = svc.get("risk_level", "review")
|
|
526
|
+
if risk == "dangerous":
|
|
527
|
+
click.echo(
|
|
528
|
+
click.style(
|
|
529
|
+
f"⚠️ {svc['name']} zawiera dane chronione lub mieszane. "
|
|
530
|
+
"Operacji nie da się automatycznie cofnąć.",
|
|
531
|
+
fg="red",
|
|
532
|
+
bold=True,
|
|
533
|
+
)
|
|
534
|
+
)
|
|
535
|
+
if not click.confirm(
|
|
536
|
+
f"Potwierdź wykonanie dokładnie dla: {svc['name']}",
|
|
537
|
+
default=False,
|
|
538
|
+
):
|
|
539
|
+
click.echo(f" Pominięto {svc['name']}.")
|
|
540
|
+
continue
|
|
541
|
+
|
|
542
|
+
click.echo(f"Czyszczenie {svc['name']}...")
|
|
543
|
+
result = scanner.cleanup_service(
|
|
544
|
+
svc["service_type"],
|
|
545
|
+
dry_run=False,
|
|
546
|
+
planned_service=svc,
|
|
547
|
+
)
|
|
548
|
+
if result["success"]:
|
|
549
|
+
freed = float(result.get("space_freed_gb", 0))
|
|
550
|
+
total_freed += freed
|
|
551
|
+
click.echo(click.style(f" Zwolniono {freed:.2f} GB", fg="green"))
|
|
552
|
+
else:
|
|
553
|
+
click.echo(click.style(f" Błąd: {_error_message(result)}", fg="red"))
|
|
554
|
+
return total_freed
|
|
391
555
|
|
|
392
556
|
|
|
393
557
|
def _run_interactive_cleanup(plan: dict, list_only: bool, scanner) -> None:
|
|
394
558
|
"""Offer interactive safe cleanup and display unsafe services."""
|
|
395
|
-
if not list_only and plan["
|
|
396
|
-
|
|
559
|
+
if not list_only and plan["services"]:
|
|
560
|
+
if plan["safe_to_cleanup"]:
|
|
561
|
+
mode, selected = _select_safe_services(plan["safe_to_cleanup"])
|
|
562
|
+
else:
|
|
563
|
+
mode, selected = "individual", []
|
|
564
|
+
if mode == "individual":
|
|
565
|
+
selected = _select_individual_services(plan["services"])
|
|
566
|
+
if selected:
|
|
567
|
+
_execute_individual_cleanup(selected, scanner)
|
|
568
|
+
else:
|
|
569
|
+
click.echo(click.style("Pominięto czyszczenie.", fg="yellow"))
|
|
570
|
+
return
|
|
397
571
|
if selected:
|
|
398
572
|
_execute_safe_cleanup(selected, scanner)
|
|
399
|
-
|
|
573
|
+
elif mode == "none":
|
|
400
574
|
click.echo(click.style("Pominięto czyszczenie.", fg="yellow"))
|
|
401
575
|
if plan["requires_review"] and not list_only:
|
|
402
576
|
_display_unsafe_services(plan["requires_review"])
|
|
@@ -61,10 +61,14 @@ CACHE_RULES: tuple[CacheRule, ...] = (
|
|
|
61
61
|
(
|
|
62
62
|
"~/.npm/_cacache",
|
|
63
63
|
"~/.npm/_npx",
|
|
64
|
+
"~/.npm/_prebuilds",
|
|
64
65
|
"~/AppData/Local/npm-cache/_cacache",
|
|
65
66
|
"~/AppData/Local/npm-cache/_npx",
|
|
66
67
|
),
|
|
67
|
-
|
|
68
|
+
(
|
|
69
|
+
"npm cache clean --force 2>/dev/null || true; "
|
|
70
|
+
"rm -rf ~/.npm/_npx ~/.npm/_prebuilds"
|
|
71
|
+
),
|
|
68
72
|
stack="node",
|
|
69
73
|
),
|
|
70
74
|
CacheRule(
|