fixos 2.2.45__tar.gz → 2.2.46__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.45 → fixos-2.2.46}/CHANGELOG.md +35 -0
- {fixos-2.2.45 → fixos-2.2.46}/PKG-INFO +46 -15
- {fixos-2.2.45 → fixos-2.2.46}/README.md +45 -14
- {fixos-2.2.45 → fixos-2.2.46}/fixos/__init__.py +1 -1
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/cleanup_cmd.py +26 -2
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/service_cleanup.py +157 -40
- {fixos-2.2.45 → fixos-2.2.46}/fixos.egg-info/PKG-INFO +46 -15
- {fixos-2.2.45 → fixos-2.2.46}/pyproject.toml +1 -1
- {fixos-2.2.45 → fixos-2.2.46}/setup.py +1 -1
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_service_cleanup.py +37 -4
- {fixos-2.2.45 → fixos-2.2.46}/.env.example +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/LICENSE +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/MANIFEST.in +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/README.md +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/TEST_RESULTS.md +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/TEST_RESULTS_V2.md +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/alpine/Dockerfile +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/arch/Dockerfile +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/base/Dockerfile +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/broken-audio/Dockerfile +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/broken-full/Dockerfile +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/broken-network/Dockerfile +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/broken-thumbnails/Dockerfile +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/debian/Dockerfile +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/docker-compose.multi-system.yml +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/docker-compose.yml +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/fedora/Dockerfile +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/test-multi-system.sh +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/test-scenarios.sh +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/ubuntu/Dockerfile +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docker/validate-scenario.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docs/examples/advanced_usage.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/docs/examples/quickstart.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/__main__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/agent/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/agent/autonomous.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/agent/autonomous_session.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/agent/hitl.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/agent/hitl_session.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/agent/session_core.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/agent/session_handlers.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/agent/session_io.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/anonymizer.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/_cleanup_flatpak.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/_cleanup_home.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/_cleanup_snap.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/_cleanup_system.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/_cleanup_utils.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/ask_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/config_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/features_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/fix_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/history_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/main.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/orchestrate_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/output_formatter.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/profile_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/projects_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/provider_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/quick_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/quickfix_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/report_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/rollback_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/scan_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/shared.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/token_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli/watch_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/cli.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/config.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/config_interactive.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/constants.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/_flatpak_analysis_mixin.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/_flatpak_execution_mixin.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/_flatpak_recommendations_mixin.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/_storage_container_mixin.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/_storage_system_mixin.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/_storage_user_mixin.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/cache_discovery.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/checks/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/checks/_shared.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/checks/audio.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/checks/file_analysis.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/checks/hardware.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/checks/packages.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/checks/resources.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/checks/security.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/checks/storage_optimization.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/checks/system_core.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/checks/thumbnails.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/dev_project_analyzer.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/disk_analyzer.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/flatpak_analyzer.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/project_scanner.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/quick_snapshot.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/service_details.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/service_scanner.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/storage_analyzer.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/system_checks.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/diagnostics/utils.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/features/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/features/auditor.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/features/catalog.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/features/installer.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/features/profiles.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/features/renderer.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/fixes/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/interactive/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/interactive/cleanup_planner.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/llm_shell.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/orchestrator/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/orchestrator/executor.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/orchestrator/graph.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/orchestrator/orchestrator.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/orchestrator/rollback.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/platform_utils.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/plugins/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/plugins/base.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/plugins/builtin/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/plugins/builtin/audio.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/plugins/builtin/disk.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/plugins/builtin/hardware.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/plugins/builtin/resources.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/plugins/builtin/security.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/plugins/builtin/thumbnails.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/plugins/registry.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/profiles/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/providers/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/providers/llm.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/providers/llm_analyzer.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/providers/schemas.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/system_checks.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/utils/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/utils/anonymizer.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/utils/terminal.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/utils/timeout.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/utils/web_search.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos/watch.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos.egg-info/SOURCES.txt +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos.egg-info/dependency_links.txt +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos.egg-info/entry_points.txt +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos.egg-info/requires.txt +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/fixos.egg-info/top_level.txt +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/pytest.ini +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/requirements-dev.txt +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/requirements.txt +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/scripts/pyqual-calibrate.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/setup.cfg +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/conftest.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/e2e/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/e2e/test_anonymization_layers.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/e2e/test_audio_broken.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/e2e/test_cli.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/e2e/test_diagnostics_integration.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/e2e/test_executor.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/e2e/test_multi_system.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/e2e/test_network_broken.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/e2e/test_thumbnails_broken.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/test_fixos.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/__init__.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_anonymizer.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_cache_discovery.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_cleanup_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_core.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_dev_project_analyzer.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_executor.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_llm_provider.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_orchestrator.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_project_scanner.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_projects_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_quick_cmd.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_quick_snapshot.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_resources_quick.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_security_quick.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_service_scanner.py +0 -0
- {fixos-2.2.45 → fixos-2.2.46}/tests/unit/test_system_checks_parallel.py +0 -0
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
### Added
|
|
4
4
|
|
|
5
|
+
- `fixos cleanup --docker-old [--days N]` oraz `-c docker-old`: usuwa wyłącznie
|
|
6
|
+
nieużywane obrazy Docker i build cache starsze niż N dni (domyślnie 30);
|
|
7
|
+
bez wolumenów i bez obrazów używanych przez kontenery.
|
|
8
|
+
- `fixos cleanup --ollama-old [--days N]` oraz `-c ollama-old`: usuwa modele
|
|
9
|
+
Ollama niezmieniane od N dni (domyślnie 90), z pominięciem modeli
|
|
10
|
+
aktualnie załadowanych (`/api/ps`).
|
|
11
|
+
- Opcja interaktywna **[1] Wszystkie bezpieczne** obejmuje teraz także:
|
|
12
|
+
- **Docker (nieużywane obrazy)** — pełną pulę unused (zgodną z RECLAIMABLE
|
|
13
|
+
Images+Build Cache), bez filtra wieku,
|
|
14
|
+
- **Ollama (modele >90 dni)** — gdy takie modele istnieją.
|
|
15
|
+
- Pomiar zwolnionego miejsca Dockera przez `docker system df` przed/po oraz
|
|
16
|
+
parsowanie `Total reclaimed space`; ostrzeżenie przy 0.00 GB mimo sukcesu
|
|
17
|
+
komendy; przypomnienie, że listy po `[1]` pochodzą ze skanu sprzed cleanup.
|
|
5
18
|
- `fixos quick`: ograniczona czasowo analiza heurystyczna bez LLM, która od razu
|
|
6
19
|
pokazuje presję CPU/RAM/dysku i maksymalny rozmiar jawnie odtwarzalnych cache.
|
|
7
20
|
- Lokalna historia szybkich próbek z porównaniem ostatnich godzin i bieżącego
|
|
@@ -14,6 +27,9 @@
|
|
|
14
27
|
|
|
15
28
|
### Changed
|
|
16
29
|
|
|
30
|
+
- Dokumentacja README / getting-started / architecture opisuje model trzech
|
|
31
|
+
poziomów ryzyka z nowymi flagami `--docker-old` / `--ollama-old` i różnicą
|
|
32
|
+
między reclaimable a filtrem wieku.
|
|
17
33
|
- Zakończone elementy historycznych roadmap zostały przeniesione z TODO do
|
|
18
34
|
changelogu: modułowy pakiet CLI, klasowe sesje HITL, wspólny
|
|
19
35
|
`SessionTimeout`, plugin registry, structured output LLM, rollback, profile
|
|
@@ -24,6 +40,9 @@
|
|
|
24
40
|
|
|
25
41
|
### Fixed
|
|
26
42
|
|
|
43
|
+
- Szacunek Dockera w opcji `[1]` nie obiecuje już całej puli RECLAIMABLE przy
|
|
44
|
+
filtrze `until=30d` (świeże unused images nie były kasowane, a UI pokazywało
|
|
45
|
+
0.00 GB).
|
|
27
46
|
- Zablokowano zbiorcze kasowanie chronionych danych LM Studio, Hugging Face,
|
|
28
47
|
Podman/containerd, Jupyter, Minikube, AppImage, VirtualBox, VMware oraz
|
|
29
48
|
rozszerzeń VS Code/Cursor. Takie wpisy pokazują teraz wyłącznie bezpieczny
|
|
@@ -51,6 +70,22 @@
|
|
|
51
70
|
rekurencyjnych skanów `/` oraz `/home` z szybkich kontroli.
|
|
52
71
|
- Czyszczenie cache JetBrains trafia w aktualną ścieżkę i wymaga zamknięcia IDE.
|
|
53
72
|
|
|
73
|
+
## [2.2.46] - 2026-08-07
|
|
74
|
+
|
|
75
|
+
### Docs
|
|
76
|
+
- Update CHANGELOG.md
|
|
77
|
+
- Update README.md
|
|
78
|
+
- Update docs/architecture.md
|
|
79
|
+
- Update docs/getting-started.md
|
|
80
|
+
|
|
81
|
+
### Test
|
|
82
|
+
- Update tests/unit/test_service_cleanup.py
|
|
83
|
+
|
|
84
|
+
### Other
|
|
85
|
+
- Update fixos/cli/cleanup_cmd.py
|
|
86
|
+
- Update fixos/diagnostics/service_cleanup.py
|
|
87
|
+
- Update project/planfile-tickets.yaml
|
|
88
|
+
|
|
54
89
|
## [2.2.45] - 2026-08-07
|
|
55
90
|
|
|
56
91
|
### Docs
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fixos
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.46
|
|
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.8388 (151 commits)
|
|
70
|
+
- 👤 **Human dev:** ~$4059 (40.6h @ $100/h, 30min dedup)
|
|
71
71
|
|
|
72
72
|
Generated on 2026-08-07 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
73
73
|
|
|
@@ -118,6 +118,8 @@ fixos quick --deep – szybki wynik, potem pełny skan danych usług
|
|
|
118
118
|
fixos fix – diagnoza + sesja naprawcza z AI (HITL)
|
|
119
119
|
fixos scan – diagnostyka systemu bez AI
|
|
120
120
|
fixos cleanup – skanuj i czyść dane usług (Docker, npm, pip, ...)
|
|
121
|
+
fixos cleanup --docker-old – nieużywane obrazy Docker starsze niż N dni (--days)
|
|
122
|
+
fixos cleanup --ollama-old – modele Ollama niezmieniane od N dni (domyślnie 90)
|
|
121
123
|
fixos cleanup --full – pełny audit systemu + dev projects
|
|
122
124
|
fixos projects – skanuj projekty dev (venv, node_modules, ~/github/*/*)
|
|
123
125
|
fixos orchestrate – zaawansowana orkiestracja (graf problemów DAG)
|
|
@@ -153,6 +155,17 @@ fixos fix --disc
|
|
|
153
155
|
# Pełny audit systemu (DNF, Docker, Flatpak, dev projects)
|
|
154
156
|
fixos cleanup --full --dry-run
|
|
155
157
|
|
|
158
|
+
# Podgląd usług + interaktywne czyszczenie (opcja [1] = wszystkie bezpieczne)
|
|
159
|
+
fixos cleanup --list
|
|
160
|
+
fixos cleanup --dry-run # tylko gdy -c / --docker-old / --ollama-old
|
|
161
|
+
fixos cleanup
|
|
162
|
+
|
|
163
|
+
# Nieużywane obrazy Docker starsze niż 30 dni (filtr wieku; może zwolnić mniej niż RECLAIMABLE)
|
|
164
|
+
fixos cleanup --docker-old --days 30 --dry-run
|
|
165
|
+
|
|
166
|
+
# Modele Ollama niezmieniane od 90+ dni (pomija uruchomione)
|
|
167
|
+
fixos cleanup --ollama-old --days 90 --dry-run
|
|
168
|
+
|
|
156
169
|
# Usuń tylko foldery venv z projektów
|
|
157
170
|
fixos cleanup --full
|
|
158
171
|
> type:venv
|
|
@@ -259,20 +272,38 @@ Tryb DRY-RUN - żadne akcje nie zostaną wykonane
|
|
|
259
272
|
|
|
260
273
|
Każda znaleziona usługa jest klasyfikowana do jednej z trzech grup:
|
|
261
274
|
|
|
262
|
-
- **bezpieczne** – cache do odtworzenia jednym poleceniem (pip/npm/cargo/conda/nix/brew...)
|
|
263
|
-
|
|
275
|
+
- **bezpieczne** – cache do odtworzenia jednym poleceniem (pip/npm/cargo/conda/nix/brew...)
|
|
276
|
+
oraz ograniczone, jawnie bezpieczne akcje wiekowe / reclaimable:
|
|
277
|
+
- **Docker (nieużywane obrazy)** — wszystkie unused images + build cache
|
|
278
|
+
(bez wolumenów, bez obrazów podpiętych do kontenerów); odpowiada puli
|
|
279
|
+
`RECLAIMABLE` Images+Build Cache,
|
|
280
|
+
- **Ollama (modele >90 dni)** — modele niezmieniane od 90+ dni; pomija
|
|
281
|
+
modele aktualnie załadowane w pamięci.
|
|
282
|
+
Tylko tę grupę usuwa opcja **[1] Wszystkie bezpieczne**.
|
|
264
283
|
- **do rozważenia** – reinstalowalne aplikacje, dane długo nieużywane, nierozpoznane
|
|
265
284
|
foldery (JetBrains, Snap, Flatpak) – pokazywane z komendą i wymagają
|
|
266
285
|
osobnego, świadomego potwierdzenia.
|
|
267
286
|
- **chronione lub mieszane** – realne dane aplikacji albo magazyny łączące dane aktywne
|
|
268
|
-
z cache (Ollama
|
|
269
|
-
Steam, `.cursor/extensions`/`.vscode/extensions`
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
287
|
+
z cache (cały sklep Ollama/LM Studio/HuggingFace, cały Docker z wolumenami,
|
|
288
|
+
Steam, `.cursor/extensions`/`.vscode/extensions`). Osobna sekcja z ostrzeżeniem;
|
|
289
|
+
zbiorcze kasowanie modeli „na ślepo”, klastrów, maszyn wirtualnych, rozszerzeń i
|
|
290
|
+
wolumenów jest wyłączone.
|
|
291
|
+
|
|
292
|
+
Dedykowane flagi (też dostępne jako `-c docker-old` / `-c ollama-old`):
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
fixos cleanup --docker-old --days 30 --dry-run # tylko unused starsze niż N dni
|
|
296
|
+
fixos cleanup --ollama-old --days 90 --dry-run # modele niezmieniane od N dni
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
`RECLAIMABLE` Dockera obejmuje też świeże unused images. Filtr `--docker-old`
|
|
300
|
+
(domyślnie 30 dni) może więc zwolnić **znacznie mniej** niż szacunek całej puli —
|
|
301
|
+
dlatego opcja `[1]` używa prune **wszystkich** nieużywanych obrazów, a
|
|
302
|
+
`--docker-old` zostaje dla świadomego cięcia po wieku. Domyślne
|
|
303
|
+
`fixos cleanup -c docker` nadal ogranicza się do cache buildów >7 dni.
|
|
304
|
+
|
|
305
|
+
Po wykonaniu opcji `[1]` listy „do rozważenia / chronione” pochodzą ze skanu
|
|
306
|
+
sprzed czyszczenia — uruchom ponownie `fixos cleanup --list`, by zobaczyć stan.
|
|
276
307
|
|
|
277
308
|
Opcja „Wybierz pojedyncze” przechodzi kolejno przez wszystkie znalezione
|
|
278
309
|
usługi w tych trzech grupach. Dla pozycji bez bezpiecznej operacji zbiorczej
|
|
@@ -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.8388 (151 commits)
|
|
26
|
+
- 👤 **Human dev:** ~$4059 (40.6h @ $100/h, 30min dedup)
|
|
27
27
|
|
|
28
28
|
Generated on 2026-08-07 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
29
29
|
|
|
@@ -74,6 +74,8 @@ fixos quick --deep – szybki wynik, potem pełny skan danych usług
|
|
|
74
74
|
fixos fix – diagnoza + sesja naprawcza z AI (HITL)
|
|
75
75
|
fixos scan – diagnostyka systemu bez AI
|
|
76
76
|
fixos cleanup – skanuj i czyść dane usług (Docker, npm, pip, ...)
|
|
77
|
+
fixos cleanup --docker-old – nieużywane obrazy Docker starsze niż N dni (--days)
|
|
78
|
+
fixos cleanup --ollama-old – modele Ollama niezmieniane od N dni (domyślnie 90)
|
|
77
79
|
fixos cleanup --full – pełny audit systemu + dev projects
|
|
78
80
|
fixos projects – skanuj projekty dev (venv, node_modules, ~/github/*/*)
|
|
79
81
|
fixos orchestrate – zaawansowana orkiestracja (graf problemów DAG)
|
|
@@ -109,6 +111,17 @@ fixos fix --disc
|
|
|
109
111
|
# Pełny audit systemu (DNF, Docker, Flatpak, dev projects)
|
|
110
112
|
fixos cleanup --full --dry-run
|
|
111
113
|
|
|
114
|
+
# Podgląd usług + interaktywne czyszczenie (opcja [1] = wszystkie bezpieczne)
|
|
115
|
+
fixos cleanup --list
|
|
116
|
+
fixos cleanup --dry-run # tylko gdy -c / --docker-old / --ollama-old
|
|
117
|
+
fixos cleanup
|
|
118
|
+
|
|
119
|
+
# Nieużywane obrazy Docker starsze niż 30 dni (filtr wieku; może zwolnić mniej niż RECLAIMABLE)
|
|
120
|
+
fixos cleanup --docker-old --days 30 --dry-run
|
|
121
|
+
|
|
122
|
+
# Modele Ollama niezmieniane od 90+ dni (pomija uruchomione)
|
|
123
|
+
fixos cleanup --ollama-old --days 90 --dry-run
|
|
124
|
+
|
|
112
125
|
# Usuń tylko foldery venv z projektów
|
|
113
126
|
fixos cleanup --full
|
|
114
127
|
> type:venv
|
|
@@ -215,20 +228,38 @@ Tryb DRY-RUN - żadne akcje nie zostaną wykonane
|
|
|
215
228
|
|
|
216
229
|
Każda znaleziona usługa jest klasyfikowana do jednej z trzech grup:
|
|
217
230
|
|
|
218
|
-
- **bezpieczne** – cache do odtworzenia jednym poleceniem (pip/npm/cargo/conda/nix/brew...)
|
|
219
|
-
|
|
231
|
+
- **bezpieczne** – cache do odtworzenia jednym poleceniem (pip/npm/cargo/conda/nix/brew...)
|
|
232
|
+
oraz ograniczone, jawnie bezpieczne akcje wiekowe / reclaimable:
|
|
233
|
+
- **Docker (nieużywane obrazy)** — wszystkie unused images + build cache
|
|
234
|
+
(bez wolumenów, bez obrazów podpiętych do kontenerów); odpowiada puli
|
|
235
|
+
`RECLAIMABLE` Images+Build Cache,
|
|
236
|
+
- **Ollama (modele >90 dni)** — modele niezmieniane od 90+ dni; pomija
|
|
237
|
+
modele aktualnie załadowane w pamięci.
|
|
238
|
+
Tylko tę grupę usuwa opcja **[1] Wszystkie bezpieczne**.
|
|
220
239
|
- **do rozważenia** – reinstalowalne aplikacje, dane długo nieużywane, nierozpoznane
|
|
221
240
|
foldery (JetBrains, Snap, Flatpak) – pokazywane z komendą i wymagają
|
|
222
241
|
osobnego, świadomego potwierdzenia.
|
|
223
242
|
- **chronione lub mieszane** – realne dane aplikacji albo magazyny łączące dane aktywne
|
|
224
|
-
z cache (Ollama
|
|
225
|
-
Steam, `.cursor/extensions`/`.vscode/extensions`
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
243
|
+
z cache (cały sklep Ollama/LM Studio/HuggingFace, cały Docker z wolumenami,
|
|
244
|
+
Steam, `.cursor/extensions`/`.vscode/extensions`). Osobna sekcja z ostrzeżeniem;
|
|
245
|
+
zbiorcze kasowanie modeli „na ślepo”, klastrów, maszyn wirtualnych, rozszerzeń i
|
|
246
|
+
wolumenów jest wyłączone.
|
|
247
|
+
|
|
248
|
+
Dedykowane flagi (też dostępne jako `-c docker-old` / `-c ollama-old`):
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
fixos cleanup --docker-old --days 30 --dry-run # tylko unused starsze niż N dni
|
|
252
|
+
fixos cleanup --ollama-old --days 90 --dry-run # modele niezmieniane od N dni
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
`RECLAIMABLE` Dockera obejmuje też świeże unused images. Filtr `--docker-old`
|
|
256
|
+
(domyślnie 30 dni) może więc zwolnić **znacznie mniej** niż szacunek całej puli —
|
|
257
|
+
dlatego opcja `[1]` używa prune **wszystkich** nieużywanych obrazów, a
|
|
258
|
+
`--docker-old` zostaje dla świadomego cięcia po wieku. Domyślne
|
|
259
|
+
`fixos cleanup -c docker` nadal ogranicza się do cache buildów >7 dni.
|
|
260
|
+
|
|
261
|
+
Po wykonaniu opcji `[1]` listy „do rozważenia / chronione” pochodzą ze skanu
|
|
262
|
+
sprzed czyszczenia — uruchom ponownie `fixos cleanup --list`, by zobaczyć stan.
|
|
232
263
|
|
|
233
264
|
Opcja „Wybierz pojedyncze” przechodzi kolejno przez wszystkie znalezione
|
|
234
265
|
usługi w tych trzech grupach. Dla pozycji bez bezpiecznej operacji zbiorczej
|
|
@@ -143,6 +143,8 @@ def _execute_planned_cleanup(scanner, svc: dict, *, dry_run: bool = False) -> di
|
|
|
143
143
|
days=int(svc.get("days") or DEFAULT_OLLAMA_OLD_UNUSED_DAYS),
|
|
144
144
|
dry_run=dry_run,
|
|
145
145
|
)
|
|
146
|
+
if kind == "docker-unused":
|
|
147
|
+
return cleaner.cleanup_docker_unused(dry_run=dry_run)
|
|
146
148
|
if kind == "docker-old":
|
|
147
149
|
return cleaner.cleanup_docker_old_unused(
|
|
148
150
|
days=int(svc.get("days") or DEFAULT_DOCKER_OLD_UNUSED_DAYS),
|
|
@@ -162,9 +164,23 @@ def _execute_safe_cleanup(services: list, scanner) -> float:
|
|
|
162
164
|
click.echo(f"Czyszczenie {svc.get('name') or svc['service_type']}...")
|
|
163
165
|
result = _execute_planned_cleanup(scanner, svc, dry_run=False)
|
|
164
166
|
if result["success"]:
|
|
165
|
-
freed = result.get("space_freed_gb", 0)
|
|
167
|
+
freed = float(result.get("space_freed_gb", 0) or 0)
|
|
166
168
|
total_freed += freed
|
|
167
|
-
|
|
169
|
+
if freed > 0:
|
|
170
|
+
click.echo(click.style(f" Zwolniono {freed:.2f} GB", fg="green"))
|
|
171
|
+
else:
|
|
172
|
+
click.echo(
|
|
173
|
+
click.style(
|
|
174
|
+
" Brak mierzalnej zmiany rozmiaru (0.00 GB) — "
|
|
175
|
+
"komenda zakończyła się OK, ale cache mógł być już pusty "
|
|
176
|
+
"albo filtr wieku nic nie trafił.",
|
|
177
|
+
fg="yellow",
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
note = (result.get("output") or result.get("error") or "").strip()
|
|
181
|
+
if note:
|
|
182
|
+
for line in note.splitlines()[:4]:
|
|
183
|
+
click.echo(f" {line}")
|
|
168
184
|
else:
|
|
169
185
|
click.echo(click.style(f" Błąd: {_error_message(result)}", fg="red"))
|
|
170
186
|
return total_freed
|
|
@@ -693,6 +709,14 @@ def _run_interactive_cleanup(plan: dict, list_only: bool, scanner) -> None:
|
|
|
693
709
|
return
|
|
694
710
|
if selected:
|
|
695
711
|
_execute_safe_cleanup(selected, scanner)
|
|
712
|
+
click.echo()
|
|
713
|
+
click.echo(
|
|
714
|
+
click.style(
|
|
715
|
+
"Uwaga: listy poniżej pochodzą ze skanu sprzed czyszczenia — "
|
|
716
|
+
"uruchom ponownie `fixos cleanup --list`, by zobaczyć aktualny stan.",
|
|
717
|
+
fg="cyan",
|
|
718
|
+
)
|
|
719
|
+
)
|
|
696
720
|
elif mode == "none":
|
|
697
721
|
click.echo(click.style("Pominięto czyszczenie.", fg="yellow"))
|
|
698
722
|
if plan["requires_review"] and not list_only:
|
|
@@ -263,31 +263,69 @@ class ServiceCleaner:
|
|
|
263
263
|
|
|
264
264
|
return result
|
|
265
265
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
dry_run: bool = False,
|
|
270
|
-
) -> Dict[str, Any]:
|
|
271
|
-
"""Remove unused Docker images (and rebuildable build cache) older than N days."""
|
|
272
|
-
from .service_scanner import ServiceType
|
|
266
|
+
@staticmethod
|
|
267
|
+
def get_docker_unused_command() -> str:
|
|
268
|
+
"""Prune all unused images and rebuildable build cache (no age filter).
|
|
273
269
|
|
|
274
|
-
|
|
275
|
-
|
|
270
|
+
Matches Docker's Images+Build Cache reclaimable pool. Does not touch
|
|
271
|
+
volumes or images still referenced by any container.
|
|
272
|
+
"""
|
|
273
|
+
return "docker image prune -a --force && docker builder prune --force"
|
|
274
|
+
|
|
275
|
+
@staticmethod
|
|
276
|
+
def _parse_docker_reclaimed_gb(output: str) -> float | None:
|
|
277
|
+
"""Parse ``Total reclaimed space: …`` from docker prune stdout/stderr."""
|
|
278
|
+
match = re.search(
|
|
279
|
+
r"Total reclaimed space:\s*([0-9]+(?:\.[0-9]+)?)\s*([KMGT]?B)",
|
|
280
|
+
output or "",
|
|
281
|
+
flags=re.IGNORECASE,
|
|
282
|
+
)
|
|
283
|
+
if not match:
|
|
284
|
+
return None
|
|
285
|
+
value = float(match.group(1))
|
|
286
|
+
unit = match.group(2).upper()
|
|
287
|
+
factor = {
|
|
288
|
+
"B": 1 / (1024**3),
|
|
289
|
+
"KB": 1 / (1024**2),
|
|
290
|
+
"MB": 1 / 1024,
|
|
291
|
+
"GB": 1.0,
|
|
292
|
+
"TB": 1024.0,
|
|
293
|
+
}.get(unit)
|
|
294
|
+
if factor is None:
|
|
295
|
+
return None
|
|
296
|
+
return round(value * factor, 3)
|
|
297
|
+
|
|
298
|
+
def _docker_images_and_cache_gb(self, *, refresh: bool = False) -> float | None:
|
|
299
|
+
"""Current Images + Build Cache size from ``docker system df``."""
|
|
300
|
+
usage_fn = getattr(self.scanner, "_get_docker_daemon_usage", None)
|
|
301
|
+
if not callable(usage_fn):
|
|
302
|
+
return None
|
|
303
|
+
usage = usage_fn(refresh=refresh)
|
|
304
|
+
if not usage:
|
|
305
|
+
return None
|
|
306
|
+
rows = usage.get("rows") or {}
|
|
307
|
+
images = float((rows.get("Images") or {}).get("size_gb", 0.0))
|
|
308
|
+
cache = float((rows.get("Build Cache") or {}).get("size_gb", 0.0))
|
|
309
|
+
return round(images + cache, 3)
|
|
310
|
+
|
|
311
|
+
def cleanup_docker_unused(self, dry_run: bool = False) -> Dict[str, Any]:
|
|
312
|
+
"""Remove all unused Docker images + build cache (safe reclaimable set)."""
|
|
313
|
+
command = self.get_docker_unused_command()
|
|
276
314
|
result: Dict[str, Any] = {
|
|
277
|
-
"service": "docker-
|
|
315
|
+
"service": "docker-unused",
|
|
278
316
|
"dry_run": dry_run,
|
|
279
317
|
"success": False,
|
|
280
318
|
"space_freed_gb": 0,
|
|
281
319
|
"output": "",
|
|
282
320
|
"error": "",
|
|
283
321
|
"command": command,
|
|
284
|
-
"days": int(days),
|
|
285
|
-
"until_hours": hours,
|
|
286
322
|
}
|
|
287
323
|
|
|
288
324
|
images_reclaimable = 0.0
|
|
289
325
|
build_cache_reclaimable = 0.0
|
|
290
326
|
try:
|
|
327
|
+
from .service_scanner import ServiceType
|
|
328
|
+
|
|
291
329
|
services = self.scanner.scan_service(ServiceType.DOCKER)
|
|
292
330
|
if services:
|
|
293
331
|
usage = (services[0].details or {}).get("usage") or {}
|
|
@@ -308,35 +346,121 @@ class ServiceCleaner:
|
|
|
308
346
|
result["space_freed_gb"] = estimated_gb
|
|
309
347
|
result["output"] = (
|
|
310
348
|
f"[DRY RUN] Would execute: {command}\n"
|
|
311
|
-
|
|
312
|
-
|
|
349
|
+
" Scope: all unused images + build cache. "
|
|
350
|
+
"Volumes and in-use images are kept."
|
|
313
351
|
)
|
|
314
352
|
return result
|
|
315
353
|
|
|
316
354
|
try:
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
355
|
+
before_gb = self._docker_images_and_cache_gb(refresh=True)
|
|
356
|
+
cleanup_result = subprocess.run(
|
|
357
|
+
command,
|
|
358
|
+
shell=True,
|
|
359
|
+
capture_output=True,
|
|
360
|
+
text=True,
|
|
361
|
+
timeout=max(DEFAULT_COMMAND_TIMEOUT, 1800),
|
|
362
|
+
)
|
|
363
|
+
combined = "\n".join(
|
|
364
|
+
part
|
|
365
|
+
for part in (cleanup_result.stdout, cleanup_result.stderr)
|
|
366
|
+
if part and part.strip()
|
|
367
|
+
)
|
|
368
|
+
result["returncode"] = cleanup_result.returncode
|
|
369
|
+
result["output"] = cleanup_result.stdout
|
|
370
|
+
result["error"] = cleanup_result.stderr
|
|
371
|
+
result["success"] = cleanup_result.returncode == 0
|
|
372
|
+
|
|
373
|
+
after_gb = self._docker_images_and_cache_gb(refresh=True)
|
|
374
|
+
if before_gb is not None and after_gb is not None:
|
|
375
|
+
result["space_freed_gb"] = round(max(0.0, before_gb - after_gb), 3)
|
|
376
|
+
else:
|
|
377
|
+
parsed = self._parse_docker_reclaimed_gb(combined)
|
|
378
|
+
if parsed is not None:
|
|
379
|
+
result["space_freed_gb"] = parsed
|
|
380
|
+
elif result["success"]:
|
|
381
|
+
result["space_freed_gb"] = 0
|
|
382
|
+
except Exception as exc:
|
|
383
|
+
result["error"] = str(exc)
|
|
384
|
+
|
|
385
|
+
return result
|
|
386
|
+
|
|
387
|
+
def cleanup_docker_old_unused(
|
|
388
|
+
self,
|
|
389
|
+
days: int = DEFAULT_DOCKER_OLD_UNUSED_DAYS,
|
|
390
|
+
dry_run: bool = False,
|
|
391
|
+
) -> Dict[str, Any]:
|
|
392
|
+
"""Remove unused Docker images (and rebuildable build cache) older than N days."""
|
|
393
|
+
command = self.get_docker_old_unused_command(days)
|
|
394
|
+
hours = self.docker_old_unused_until_hours(days)
|
|
395
|
+
result: Dict[str, Any] = {
|
|
396
|
+
"service": "docker-old",
|
|
397
|
+
"dry_run": dry_run,
|
|
398
|
+
"success": False,
|
|
399
|
+
"space_freed_gb": 0,
|
|
400
|
+
"output": "",
|
|
401
|
+
"error": "",
|
|
402
|
+
"command": command,
|
|
403
|
+
"days": int(days),
|
|
404
|
+
"until_hours": hours,
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
# Age-filtered prune usually frees less than the whole reclaimable pool.
|
|
408
|
+
result["estimated_max_gb"] = 0.0
|
|
409
|
+
try:
|
|
410
|
+
from .service_scanner import ServiceType
|
|
411
|
+
|
|
412
|
+
services = self.scanner.scan_service(ServiceType.DOCKER)
|
|
413
|
+
if services:
|
|
414
|
+
usage = (services[0].details or {}).get("usage") or {}
|
|
415
|
+
result["estimated_max_gb"] = round(
|
|
416
|
+
float((usage.get("Images") or {}).get("reclaimable_gb", 0.0))
|
|
417
|
+
+ float((usage.get("Build Cache") or {}).get("reclaimable_gb", 0.0)),
|
|
418
|
+
3,
|
|
419
|
+
)
|
|
420
|
+
result["estimate_note"] = (
|
|
421
|
+
"upper bound = all reclaimable Images+Build Cache; "
|
|
422
|
+
f"until={hours}h usually frees less"
|
|
423
|
+
)
|
|
424
|
+
except Exception:
|
|
425
|
+
pass
|
|
321
426
|
|
|
427
|
+
if dry_run:
|
|
428
|
+
result["success"] = True
|
|
429
|
+
result["space_freed_gb"] = 0
|
|
430
|
+
result["output"] = (
|
|
431
|
+
f"[DRY RUN] Would execute: {command}\n"
|
|
432
|
+
f" Scope: unused images + build cache older than {int(days)} days "
|
|
433
|
+
f"({hours}h). Volumes and in-use images are kept.\n"
|
|
434
|
+
f" Note: Docker reclaimable (~{result['estimated_max_gb']:.2f} GB) "
|
|
435
|
+
"includes younger unused images; age filter may free much less."
|
|
436
|
+
)
|
|
437
|
+
return result
|
|
438
|
+
|
|
439
|
+
try:
|
|
440
|
+
before_gb = self._docker_images_and_cache_gb(refresh=True)
|
|
322
441
|
cleanup_result = subprocess.run(
|
|
323
442
|
command,
|
|
324
443
|
shell=True,
|
|
325
444
|
capture_output=True,
|
|
326
445
|
text=True,
|
|
327
|
-
timeout=DEFAULT_COMMAND_TIMEOUT,
|
|
446
|
+
timeout=max(DEFAULT_COMMAND_TIMEOUT, 1800),
|
|
447
|
+
)
|
|
448
|
+
combined = "\n".join(
|
|
449
|
+
part
|
|
450
|
+
for part in (cleanup_result.stdout, cleanup_result.stderr)
|
|
451
|
+
if part and part.strip()
|
|
328
452
|
)
|
|
329
453
|
result["returncode"] = cleanup_result.returncode
|
|
330
454
|
result["output"] = cleanup_result.stdout
|
|
331
455
|
result["error"] = cleanup_result.stderr
|
|
332
456
|
result["success"] = cleanup_result.returncode == 0
|
|
333
457
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
result["space_freed_gb"] = round(max(0.0,
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
result["space_freed_gb"] = 0
|
|
458
|
+
after_gb = self._docker_images_and_cache_gb(refresh=True)
|
|
459
|
+
if before_gb is not None and after_gb is not None:
|
|
460
|
+
result["space_freed_gb"] = round(max(0.0, before_gb - after_gb), 3)
|
|
461
|
+
else:
|
|
462
|
+
parsed = self._parse_docker_reclaimed_gb(combined)
|
|
463
|
+
result["space_freed_gb"] = parsed if parsed is not None else 0
|
|
340
464
|
except Exception as exc:
|
|
341
465
|
result["error"] = str(exc)
|
|
342
466
|
|
|
@@ -349,7 +473,7 @@ class ServiceCleaner:
|
|
|
349
473
|
|
|
350
474
|
Includes:
|
|
351
475
|
- Ollama models not modified for ``DEFAULT_OLLAMA_OLD_UNUSED_DAYS``
|
|
352
|
-
-
|
|
476
|
+
- All unused Docker images + build cache (matches daemon reclaimable)
|
|
353
477
|
"""
|
|
354
478
|
allow = {item.strip() for item in (selected_services or []) if item.strip()}
|
|
355
479
|
|
|
@@ -405,7 +529,7 @@ class ServiceCleaner:
|
|
|
405
529
|
}
|
|
406
530
|
)
|
|
407
531
|
|
|
408
|
-
if allowed("docker", "docker-old"):
|
|
532
|
+
if allowed("docker", "docker-old", "docker-unused"):
|
|
409
533
|
estimated_gb = 0.0
|
|
410
534
|
try:
|
|
411
535
|
from .service_scanner import ServiceType
|
|
@@ -421,23 +545,18 @@ class ServiceCleaner:
|
|
|
421
545
|
except Exception:
|
|
422
546
|
estimated_gb = 0.0
|
|
423
547
|
if estimated_gb > 0:
|
|
424
|
-
command = self.
|
|
425
|
-
DEFAULT_DOCKER_OLD_UNUSED_DAYS
|
|
426
|
-
)
|
|
548
|
+
command = self.get_docker_unused_command()
|
|
427
549
|
actions.append(
|
|
428
550
|
{
|
|
429
|
-
"service_type": "docker-
|
|
430
|
-
"cleanup_kind": "docker-
|
|
431
|
-
"name": (
|
|
432
|
-
f"Docker (nieużywane obrazy >"
|
|
433
|
-
f"{DEFAULT_DOCKER_OLD_UNUSED_DAYS} dni)"
|
|
434
|
-
),
|
|
551
|
+
"service_type": "docker-unused",
|
|
552
|
+
"cleanup_kind": "docker-unused",
|
|
553
|
+
"name": "Docker (nieużywane obrazy)",
|
|
435
554
|
"path": "/var/lib/docker",
|
|
436
555
|
"size_mb": round(estimated_gb * 1024, 1),
|
|
437
556
|
"size_gb": round(estimated_gb, 3),
|
|
438
557
|
"description": (
|
|
439
|
-
"
|
|
440
|
-
|
|
558
|
+
"Wszystkie nieużywane obrazy Docker i build cache "
|
|
559
|
+
"(bez wolumenów, bez obrazów podpiętych do kontenerów)"
|
|
441
560
|
),
|
|
442
561
|
"can_cleanup": True,
|
|
443
562
|
"cleanup_command": command,
|
|
@@ -447,10 +566,8 @@ class ServiceCleaner:
|
|
|
447
566
|
"impact": "low",
|
|
448
567
|
"items_count": 0,
|
|
449
568
|
"details": {
|
|
450
|
-
"days": DEFAULT_DOCKER_OLD_UNUSED_DAYS,
|
|
451
569
|
"estimated_max_gb": round(estimated_gb, 3),
|
|
452
570
|
},
|
|
453
|
-
"days": DEFAULT_DOCKER_OLD_UNUSED_DAYS,
|
|
454
571
|
}
|
|
455
572
|
)
|
|
456
573
|
|