fixos 2.2.39__tar.gz → 2.2.40__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.40}/CHANGELOG.md +33 -0
- {fixos-2.2.39 → fixos-2.2.40}/PKG-INFO +5 -5
- {fixos-2.2.39 → fixos-2.2.40}/README.md +4 -4
- {fixos-2.2.39 → fixos-2.2.40}/fixos/__init__.py +1 -1
- fixos-2.2.40/fixos/__main__.py +7 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/cleanup_cmd.py +117 -19
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/quick_snapshot.py +5 -1
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/service_cleanup.py +64 -22
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/service_scanner.py +19 -7
- {fixos-2.2.39 → fixos-2.2.40}/fixos.egg-info/PKG-INFO +5 -5
- {fixos-2.2.39 → fixos-2.2.40}/fixos.egg-info/SOURCES.txt +2 -0
- {fixos-2.2.39 → fixos-2.2.40}/pyproject.toml +1 -1
- {fixos-2.2.39 → fixos-2.2.40}/setup.py +1 -1
- fixos-2.2.40/tests/unit/test_cleanup_cmd.py +87 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_service_cleanup.py +84 -6
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_service_scanner.py +20 -0
- {fixos-2.2.39 → fixos-2.2.40}/.env.example +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/LICENSE +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/MANIFEST.in +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/README.md +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/TEST_RESULTS.md +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/TEST_RESULTS_V2.md +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/alpine/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/arch/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/base/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/broken-audio/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/broken-full/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/broken-network/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/broken-thumbnails/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/debian/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/docker-compose.multi-system.yml +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/docker-compose.yml +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/fedora/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/test-multi-system.sh +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/test-scenarios.sh +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/ubuntu/Dockerfile +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docker/validate-scenario.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docs/examples/advanced_usage.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/docs/examples/quickstart.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/agent/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/agent/autonomous.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/agent/autonomous_session.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/agent/hitl.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/agent/hitl_session.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/agent/session_core.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/agent/session_handlers.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/agent/session_io.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/anonymizer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/_cleanup_flatpak.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/_cleanup_home.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/_cleanup_snap.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/_cleanup_system.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/_cleanup_utils.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/ask_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/config_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/features_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/fix_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/history_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/main.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/orchestrate_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/output_formatter.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/profile_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/projects_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/provider_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/quick_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/quickfix_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/report_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/rollback_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/scan_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/shared.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/token_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli/watch_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/cli.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/config.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/config_interactive.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/constants.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/_flatpak_analysis_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/_flatpak_execution_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/_flatpak_recommendations_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/_storage_container_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/_storage_system_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/_storage_user_mixin.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/cache_discovery.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/checks/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/checks/_shared.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/checks/audio.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/checks/file_analysis.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/checks/hardware.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/checks/packages.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/checks/resources.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/checks/security.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/checks/storage_optimization.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/checks/system_core.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/checks/thumbnails.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/dev_project_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/disk_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/flatpak_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/project_scanner.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/service_details.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/storage_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/system_checks.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/diagnostics/utils.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/features/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/features/auditor.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/features/catalog.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/features/installer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/features/profiles.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/features/renderer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/fixes/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/interactive/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/interactive/cleanup_planner.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/llm_shell.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/orchestrator/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/orchestrator/executor.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/orchestrator/graph.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/orchestrator/orchestrator.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/orchestrator/rollback.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/platform_utils.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/plugins/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/plugins/base.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/plugins/builtin/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/plugins/builtin/audio.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/plugins/builtin/disk.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/plugins/builtin/hardware.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/plugins/builtin/resources.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/plugins/builtin/security.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/plugins/builtin/thumbnails.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/plugins/registry.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/profiles/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/providers/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/providers/llm.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/providers/llm_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/providers/schemas.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/system_checks.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/utils/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/utils/anonymizer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/utils/terminal.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/utils/timeout.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/utils/web_search.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos/watch.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos.egg-info/dependency_links.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos.egg-info/entry_points.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos.egg-info/requires.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/fixos.egg-info/top_level.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/pytest.ini +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/requirements-dev.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/requirements.txt +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/scripts/pyqual-calibrate.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/setup.cfg +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/conftest.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/e2e/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/e2e/test_anonymization_layers.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/e2e/test_audio_broken.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/e2e/test_cli.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/e2e/test_diagnostics_integration.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/e2e/test_executor.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/e2e/test_multi_system.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/e2e/test_network_broken.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/e2e/test_thumbnails_broken.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/test_fixos.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/__init__.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_anonymizer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_cache_discovery.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_core.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_dev_project_analyzer.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_executor.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_llm_provider.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_orchestrator.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_project_scanner.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_projects_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_quick_cmd.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_quick_snapshot.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_resources_quick.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_security_quick.py +0 -0
- {fixos-2.2.39 → fixos-2.2.40}/tests/unit/test_system_checks_parallel.py +0 -0
|
@@ -11,6 +11,18 @@
|
|
|
11
11
|
|
|
12
12
|
### Fixed
|
|
13
13
|
|
|
14
|
+
- Tryb `fixos cleanup` → „Wybierz pojedyncze” przechodzi teraz kolejno przez
|
|
15
|
+
wszystkie usługi: bezpieczne, wymagające przeglądu i chronione. Pozycje bez
|
|
16
|
+
bezpiecznej operacji zbiorczej pokazują komendę podglądu, dane chronione
|
|
17
|
+
wymagają dodatkowego potwierdzenia, a wykonanie jest przypięte do dokładnie
|
|
18
|
+
wybranej ścieżki i poziomu ryzyka.
|
|
19
|
+
- Skany cache npm, pnpm, Yarn, Maven i uv obejmują teraz wyłącznie
|
|
20
|
+
odtwarzalne katalogi. `~/.local/share/uv` (narzędzia, interpretery i
|
|
21
|
+
credentials) oraz `.tools` pnpm nie są już błędnie liczone jako bezpieczne
|
|
22
|
+
cache; czyszczenie npm faktycznie obejmuje raportowane `_npx`.
|
|
23
|
+
- Naprawiono scenariusze TestQL i dodano punkt wejścia `python -m fixos`.
|
|
24
|
+
`cleanup -c <chroniona-usługa> --dry-run` pokazuje bezpieczną komendę
|
|
25
|
+
diagnostyczną zamiast kończyć się mylącym błędem.
|
|
14
26
|
- Stabilny raport Docker z osobnym rozmiarem aktywnym i odzyskiwalnym oraz
|
|
15
27
|
poprawnym pomiarem przed/po czyszczeniu.
|
|
16
28
|
- Usunięto niebezpieczne zbiorcze komendy kasowania wolumenów Docker i
|
|
@@ -19,6 +31,27 @@
|
|
|
19
31
|
rekurencyjnych skanów `/` oraz `/home` z szybkich kontroli.
|
|
20
32
|
- Czyszczenie cache JetBrains trafia w aktualną ścieżkę i wymaga zamknięcia IDE.
|
|
21
33
|
|
|
34
|
+
## [2.2.40] - 2026-07-23
|
|
35
|
+
|
|
36
|
+
### Docs
|
|
37
|
+
- Update CHANGELOG.md
|
|
38
|
+
- Update README.md
|
|
39
|
+
|
|
40
|
+
### Test
|
|
41
|
+
- Update testql-scenarios/generated-cli-tests.testql.toon.yaml
|
|
42
|
+
- Update testql-scenarios/generated-from-pytests.testql.toon.yaml
|
|
43
|
+
- Update tests/unit/test_cleanup_cmd.py
|
|
44
|
+
- Update tests/unit/test_service_cleanup.py
|
|
45
|
+
- Update tests/unit/test_service_scanner.py
|
|
46
|
+
|
|
47
|
+
### Other
|
|
48
|
+
- Update fixos/__main__.py
|
|
49
|
+
- Update fixos/cli/cleanup_cmd.py
|
|
50
|
+
- Update fixos/diagnostics/quick_snapshot.py
|
|
51
|
+
- Update fixos/diagnostics/service_cleanup.py
|
|
52
|
+
- Update fixos/diagnostics/service_scanner.py
|
|
53
|
+
- Update uv.lock
|
|
54
|
+
|
|
22
55
|
## [2.2.39] - 2026-07-23
|
|
23
56
|
|
|
24
57
|
### Docs
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fixos
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.40
|
|
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.8451 (147 commits)
|
|
70
|
+
- 👤 **Human dev:** ~$3817 (38.2h @ $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
|
|
|
@@ -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.8451 (147 commits)
|
|
26
|
+
- 👤 **Human dev:** ~$3817 (38.2h @ $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
|
|
|
@@ -79,9 +79,7 @@ def _display_service_item(svc: dict) -> None:
|
|
|
79
79
|
risk = svc.get("risk_level") or ("safe" if svc["safe_to_cleanup"] else "review")
|
|
80
80
|
safe_text, safe_color = _RISK_LABELS.get(risk, _RISK_LABELS["review"])
|
|
81
81
|
|
|
82
|
-
click.echo(
|
|
83
|
-
f" {click.style(svc['name'], fg='yellow', bold=True)} - {size_str}"
|
|
84
|
-
)
|
|
82
|
+
click.echo(f" {click.style(svc['name'], fg='yellow', bold=True)} - {size_str}")
|
|
85
83
|
click.echo(f" {svc['description']}")
|
|
86
84
|
paths = svc.get("details", {}).get("paths") or [svc["path"]]
|
|
87
85
|
if len(paths) > 1:
|
|
@@ -90,7 +88,9 @@ def _display_service_item(svc: dict) -> None:
|
|
|
90
88
|
click.echo(f" • {path}")
|
|
91
89
|
else:
|
|
92
90
|
click.echo(f" Ścieżka: {svc['path']}")
|
|
93
|
-
click.echo(
|
|
91
|
+
click.echo(
|
|
92
|
+
f" {click.style(safe_text, fg=safe_color, bold=(risk == 'dangerous'))}"
|
|
93
|
+
)
|
|
94
94
|
|
|
95
95
|
# Show details for specific services
|
|
96
96
|
if svc.get("details"):
|
|
@@ -134,7 +134,11 @@ def _execute_safe_cleanup(services: list, scanner) -> float:
|
|
|
134
134
|
for svc in services:
|
|
135
135
|
svc_type = svc["service_type"]
|
|
136
136
|
click.echo(f"Czyszczenie {svc_type}...")
|
|
137
|
-
result = scanner.cleanup_service(
|
|
137
|
+
result = scanner.cleanup_service(
|
|
138
|
+
svc_type,
|
|
139
|
+
dry_run=False,
|
|
140
|
+
planned_service=svc,
|
|
141
|
+
)
|
|
138
142
|
if result["success"]:
|
|
139
143
|
freed = result.get("space_freed_gb", 0)
|
|
140
144
|
total_freed += freed
|
|
@@ -327,7 +331,9 @@ def _cleanup_single_service(
|
|
|
327
331
|
bold=True,
|
|
328
332
|
)
|
|
329
333
|
)
|
|
330
|
-
click.echo(
|
|
334
|
+
click.echo(
|
|
335
|
+
f" Podgląd bez usuwania: fixos cleanup -c {service_name} --dry-run"
|
|
336
|
+
)
|
|
331
337
|
if not click.confirm(f"Na pewno usunąć dane usługi {service_name}?"):
|
|
332
338
|
click.echo("Anulowano.")
|
|
333
339
|
return
|
|
@@ -340,7 +346,9 @@ def _cleanup_single_service(
|
|
|
340
346
|
|
|
341
347
|
if result["success"]:
|
|
342
348
|
if dry_run:
|
|
343
|
-
click.echo(
|
|
349
|
+
click.echo(
|
|
350
|
+
click.style(f"Symulacja dla {service_name} zakończona", fg="green")
|
|
351
|
+
)
|
|
344
352
|
if result.get("output"):
|
|
345
353
|
click.echo(f" {result['output']}")
|
|
346
354
|
if result["space_freed_gb"] > 0:
|
|
@@ -349,7 +357,9 @@ def _cleanup_single_service(
|
|
|
349
357
|
f"{result['space_freed_gb']:.2f} GB"
|
|
350
358
|
)
|
|
351
359
|
else:
|
|
352
|
-
click.echo(
|
|
360
|
+
click.echo(
|
|
361
|
+
click.style(f"Zakończono czyszczenie {service_name}", fg="green")
|
|
362
|
+
)
|
|
353
363
|
if result["space_freed_gb"] > 0:
|
|
354
364
|
click.echo(f" Zwolniono: {result['space_freed_gb']:.2f} GB")
|
|
355
365
|
else:
|
|
@@ -362,11 +372,15 @@ def _cleanup_single_service(
|
|
|
362
372
|
|
|
363
373
|
|
|
364
374
|
def _size_str(svc: dict) -> str:
|
|
365
|
-
return
|
|
375
|
+
return (
|
|
376
|
+
f"{svc['size_gb']:.2f} GB"
|
|
377
|
+
if svc["size_gb"] >= 1
|
|
378
|
+
else f"{svc['size_mb']:.0f} MB"
|
|
379
|
+
)
|
|
366
380
|
|
|
367
381
|
|
|
368
|
-
def _select_safe_services(safe_services: list) -> list:
|
|
369
|
-
"""
|
|
382
|
+
def _select_safe_services(safe_services: list) -> tuple[str, list]:
|
|
383
|
+
"""Choose bulk-safe cleanup, full individual selection, or no cleanup."""
|
|
370
384
|
click.echo(click.style("Bezpieczne do wyczyszczenia:", fg="green"))
|
|
371
385
|
for svc in safe_services:
|
|
372
386
|
click.echo(f" • {svc['name']}: {_size_str(svc)}")
|
|
@@ -375,28 +389,112 @@ def _select_safe_services(safe_services: list) -> list:
|
|
|
375
389
|
click.echo()
|
|
376
390
|
click.echo("Co wyczyścić?")
|
|
377
391
|
click.echo(f" [1] Wszystkie bezpieczne (zwolni {safe_total:.2f} GB)")
|
|
378
|
-
click.echo(" [2] Wybierz pojedyncze
|
|
392
|
+
click.echo(" [2] Wybierz pojedyncze spośród wszystkich usług")
|
|
379
393
|
click.echo(" [0] Nic — pomiń")
|
|
380
394
|
choice = click.prompt(
|
|
381
395
|
"Wybór", type=click.Choice(["0", "1", "2"]), default="1", show_choices=False
|
|
382
396
|
)
|
|
383
397
|
|
|
384
398
|
if choice == "0":
|
|
385
|
-
return []
|
|
399
|
+
return "none", []
|
|
386
400
|
if choice == "1":
|
|
387
|
-
return safe_services
|
|
401
|
+
return "safe", safe_services
|
|
402
|
+
return "individual", []
|
|
388
403
|
|
|
389
|
-
|
|
390
|
-
|
|
404
|
+
|
|
405
|
+
def _selection_description(svc: dict) -> str:
|
|
406
|
+
risk = svc.get("risk_level", "review")
|
|
407
|
+
labels = {
|
|
408
|
+
"safe": "bezpieczne cache",
|
|
409
|
+
"review": "do rozważenia",
|
|
410
|
+
"dangerous": "CHRONIONE/mieszane",
|
|
411
|
+
}
|
|
412
|
+
description = labels.get(risk, "do rozważenia")
|
|
413
|
+
if risk == "dangerous" and svc["service_type"] == "docker":
|
|
414
|
+
reclaimable = svc.get("details", {}).get("usage", {}).get("Build Cache", {})
|
|
415
|
+
reclaimable_gb = float(reclaimable.get("reclaimable_gb", 0))
|
|
416
|
+
if reclaimable_gb:
|
|
417
|
+
description += f"; komenda dotyczy do {reclaimable_gb:.2f} GB cache buildów"
|
|
418
|
+
return description
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def _select_individual_services(services: list) -> list:
|
|
422
|
+
"""Offer every scanned, executable entry in its displayed order."""
|
|
423
|
+
click.echo(
|
|
424
|
+
click.style(
|
|
425
|
+
"Wybierz kolejno spośród wszystkich możliwych usług:",
|
|
426
|
+
fg="cyan",
|
|
427
|
+
)
|
|
428
|
+
)
|
|
429
|
+
selected = []
|
|
430
|
+
for svc in services:
|
|
431
|
+
label = (
|
|
432
|
+
f" {svc['name']} ({_size_str(svc)}) " f"[{_selection_description(svc)}]"
|
|
433
|
+
)
|
|
434
|
+
if not svc.get("can_cleanup") or not svc.get("cleanup_command", "").strip():
|
|
435
|
+
click.echo(f"{label} — brak bezpiecznej operacji zbiorczej")
|
|
436
|
+
preview = svc.get("preview_command")
|
|
437
|
+
if preview:
|
|
438
|
+
click.echo(f" Podgląd: {preview}")
|
|
439
|
+
continue
|
|
440
|
+
if click.confirm(label, default=False):
|
|
441
|
+
selected.append(svc)
|
|
442
|
+
return selected
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def _execute_individual_cleanup(services: list, scanner) -> float:
|
|
446
|
+
"""Execute hand-picked entries with an extra gate for protected data."""
|
|
447
|
+
total_freed = 0.0
|
|
448
|
+
for svc in services:
|
|
449
|
+
risk = svc.get("risk_level", "review")
|
|
450
|
+
if risk == "dangerous":
|
|
451
|
+
click.echo(
|
|
452
|
+
click.style(
|
|
453
|
+
f"⚠️ {svc['name']} zawiera dane chronione lub mieszane. "
|
|
454
|
+
"Operacji nie da się automatycznie cofnąć.",
|
|
455
|
+
fg="red",
|
|
456
|
+
bold=True,
|
|
457
|
+
)
|
|
458
|
+
)
|
|
459
|
+
if not click.confirm(
|
|
460
|
+
f"Potwierdź wykonanie dokładnie dla: {svc['name']}",
|
|
461
|
+
default=False,
|
|
462
|
+
):
|
|
463
|
+
click.echo(f" Pominięto {svc['name']}.")
|
|
464
|
+
continue
|
|
465
|
+
|
|
466
|
+
click.echo(f"Czyszczenie {svc['name']}...")
|
|
467
|
+
result = scanner.cleanup_service(
|
|
468
|
+
svc["service_type"],
|
|
469
|
+
dry_run=False,
|
|
470
|
+
planned_service=svc,
|
|
471
|
+
)
|
|
472
|
+
if result["success"]:
|
|
473
|
+
freed = float(result.get("space_freed_gb", 0))
|
|
474
|
+
total_freed += freed
|
|
475
|
+
click.echo(click.style(f" Zwolniono {freed:.2f} GB", fg="green"))
|
|
476
|
+
else:
|
|
477
|
+
click.echo(click.style(f" Błąd: {_error_message(result)}", fg="red"))
|
|
478
|
+
return total_freed
|
|
391
479
|
|
|
392
480
|
|
|
393
481
|
def _run_interactive_cleanup(plan: dict, list_only: bool, scanner) -> None:
|
|
394
482
|
"""Offer interactive safe cleanup and display unsafe services."""
|
|
395
|
-
if not list_only and plan["
|
|
396
|
-
|
|
483
|
+
if not list_only and plan["services"]:
|
|
484
|
+
if plan["safe_to_cleanup"]:
|
|
485
|
+
mode, selected = _select_safe_services(plan["safe_to_cleanup"])
|
|
486
|
+
else:
|
|
487
|
+
mode, selected = "individual", []
|
|
488
|
+
if mode == "individual":
|
|
489
|
+
selected = _select_individual_services(plan["services"])
|
|
490
|
+
if selected:
|
|
491
|
+
_execute_individual_cleanup(selected, scanner)
|
|
492
|
+
else:
|
|
493
|
+
click.echo(click.style("Pominięto czyszczenie.", fg="yellow"))
|
|
494
|
+
return
|
|
397
495
|
if selected:
|
|
398
496
|
_execute_safe_cleanup(selected, scanner)
|
|
399
|
-
|
|
497
|
+
elif mode == "none":
|
|
400
498
|
click.echo(click.style("Pominięto czyszczenie.", fg="yellow"))
|
|
401
499
|
if plan["requires_review"] and not list_only:
|
|
402
500
|
_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(
|
|
@@ -6,6 +6,7 @@ Handles planning and execution of service data cleanup operations.
|
|
|
6
6
|
import os
|
|
7
7
|
import shlex
|
|
8
8
|
import subprocess
|
|
9
|
+
from types import SimpleNamespace
|
|
9
10
|
from typing import Dict, Any, List
|
|
10
11
|
from ..constants import (
|
|
11
12
|
DEFAULT_COMMAND_TIMEOUT,
|
|
@@ -47,10 +48,7 @@ class ServiceCleaner:
|
|
|
47
48
|
"requires_review_gb": round(sum(s.size_gb for s in review_services), 2),
|
|
48
49
|
"dangerous_gb": round(sum(s.size_gb for s in dangerous_services), 2),
|
|
49
50
|
"manager_reported_reclaimable_gb": round(
|
|
50
|
-
sum(
|
|
51
|
-
float(s.details.get("reclaimable_size_gb", 0.0))
|
|
52
|
-
for s in services
|
|
53
|
-
),
|
|
51
|
+
sum(float(s.details.get("reclaimable_size_gb", 0.0)) for s in services),
|
|
54
52
|
2,
|
|
55
53
|
),
|
|
56
54
|
"services": [self._service_to_dict(s) for s in services],
|
|
@@ -62,9 +60,19 @@ class ServiceCleaner:
|
|
|
62
60
|
return plan
|
|
63
61
|
|
|
64
62
|
def cleanup_service(
|
|
65
|
-
self,
|
|
63
|
+
self,
|
|
64
|
+
service_type: str,
|
|
65
|
+
dry_run: bool = False,
|
|
66
|
+
planned_service: Dict[str, Any] | None = None,
|
|
66
67
|
) -> Dict[str, Any]:
|
|
67
|
-
"""Execute cleanup for a specific service.
|
|
68
|
+
"""Execute cleanup for a specific service or exact planned entry.
|
|
69
|
+
|
|
70
|
+
One service type can have entries in multiple risk tiers (for example
|
|
71
|
+
VS Code cache and VS Code extensions). Re-scanning and blindly taking
|
|
72
|
+
the largest entry could therefore execute a different cleanup than the
|
|
73
|
+
one selected in the CLI. ``planned_service`` pins execution to the
|
|
74
|
+
displayed path, command and risk entry.
|
|
75
|
+
"""
|
|
68
76
|
from .service_scanner import ServiceType
|
|
69
77
|
|
|
70
78
|
result = {
|
|
@@ -78,16 +86,38 @@ class ServiceCleaner:
|
|
|
78
86
|
|
|
79
87
|
try:
|
|
80
88
|
service_enum = ServiceType(service_type)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
if planned_service is not None:
|
|
90
|
+
if planned_service.get("service_type") != service_type:
|
|
91
|
+
result["error"] = "Selected cleanup entry does not match service"
|
|
92
|
+
return result
|
|
93
|
+
service = SimpleNamespace(
|
|
94
|
+
service_type=service_enum,
|
|
95
|
+
name=planned_service.get("name", service_type),
|
|
96
|
+
path=planned_service.get("path", ""),
|
|
97
|
+
size_gb=float(planned_service.get("size_gb", 0)),
|
|
98
|
+
can_cleanup=bool(planned_service.get("can_cleanup")),
|
|
99
|
+
cleanup_command=planned_service.get("cleanup_command", ""),
|
|
100
|
+
preview_command=planned_service.get("preview_command", ""),
|
|
101
|
+
details=planned_service.get("details") or {},
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
services = self.scanner.scan_service(service_enum)
|
|
105
|
+
if not services:
|
|
106
|
+
result["error"] = f"No {service_type} data found above threshold"
|
|
107
|
+
return result
|
|
108
|
+
service = services[0] # Backward-compatible single-service mode.
|
|
88
109
|
initial_size = service.size_gb
|
|
89
110
|
|
|
90
111
|
if not service.can_cleanup or not service.cleanup_command.strip():
|
|
112
|
+
if dry_run:
|
|
113
|
+
preview = getattr(service, "preview_command", "")
|
|
114
|
+
result["success"] = True
|
|
115
|
+
result["requires_item_selection"] = True
|
|
116
|
+
result["output"] = (
|
|
117
|
+
"[DRY RUN] Zbiorcze czyszczenie jest wyłączone. "
|
|
118
|
+
f"Bezpieczny podgląd: {preview or 'brak komendy podglądu'}"
|
|
119
|
+
)
|
|
120
|
+
return result
|
|
91
121
|
result["error"] = (
|
|
92
122
|
f"{service.name}: wybierz konkretne elementy do usunięcia; "
|
|
93
123
|
"zbiorcze czyszczenie jest wyłączone, aby chronić dane"
|
|
@@ -113,12 +143,15 @@ class ServiceCleaner:
|
|
|
113
143
|
|
|
114
144
|
# Check new size
|
|
115
145
|
measure = getattr(self.scanner, "measure_service_size_mb", None)
|
|
146
|
+
planned_paths = service.details.get("paths") or [service.path]
|
|
116
147
|
if callable(measure):
|
|
117
|
-
new_size_mb =
|
|
118
|
-
service_enum,
|
|
148
|
+
new_size_mb = sum(
|
|
149
|
+
measure(service_enum, path, refresh=True) for path in planned_paths
|
|
119
150
|
)
|
|
120
151
|
else:
|
|
121
|
-
new_size_mb =
|
|
152
|
+
new_size_mb = sum(
|
|
153
|
+
self.scanner._get_path_size_mb(path) for path in planned_paths
|
|
154
|
+
)
|
|
122
155
|
new_size_gb = new_size_mb / 1024
|
|
123
156
|
freed_gb = max(0, initial_size - new_size_gb)
|
|
124
157
|
|
|
@@ -492,7 +525,7 @@ class ServiceCleaner:
|
|
|
492
525
|
# Python
|
|
493
526
|
ServiceType.PIP: "Python pip cache",
|
|
494
527
|
ServiceType.CONDA: "Conda package cache (pkgs directories)",
|
|
495
|
-
ServiceType.POETRY: "Poetry
|
|
528
|
+
ServiceType.POETRY: "Poetry package cache",
|
|
496
529
|
# Java
|
|
497
530
|
ServiceType.GRADLE: "Gradle build cache",
|
|
498
531
|
ServiceType.MAVEN: "Maven repository cache",
|
|
@@ -578,12 +611,15 @@ class ServiceCleaner:
|
|
|
578
611
|
ServiceType.CONTAINERD: "sudo rm -rf /var/lib/containerd",
|
|
579
612
|
ServiceType.PODMAN: "podman system prune -af --volumes",
|
|
580
613
|
# JS/Node
|
|
581
|
-
ServiceType.NPM:
|
|
614
|
+
ServiceType.NPM: (
|
|
615
|
+
"npm cache clean --force 2>/dev/null || true; "
|
|
616
|
+
"rm -rf ~/.npm/_npx ~/.npm/_prebuilds"
|
|
617
|
+
),
|
|
582
618
|
ServiceType.YARN: "yarn cache clean --all",
|
|
583
619
|
ServiceType.PNPM: "pnpm store prune",
|
|
584
620
|
# Python
|
|
585
621
|
ServiceType.PIP: "pip cache purge || rm -rf ~/.cache/pip/*",
|
|
586
|
-
ServiceType.CONDA: "conda clean --all -y
|
|
622
|
+
ServiceType.CONDA: "conda clean --all -y",
|
|
587
623
|
ServiceType.POETRY: "poetry cache clear --all pypi || rm -rf ~/.cache/pypoetry",
|
|
588
624
|
# Java
|
|
589
625
|
ServiceType.GRADLE: "rm -rf ~/.gradle/caches ~/.gradle/daemon ~/.gradle/wrapper",
|
|
@@ -641,7 +677,7 @@ class ServiceCleaner:
|
|
|
641
677
|
ServiceType.TRASH: "rm -rf ~/.local/share/Trash/* ~/.Trash/*",
|
|
642
678
|
ServiceType.LOGS: "find ~/.cache/log ~/.local/state -name '*.log' -mtime +7 -delete 2>/dev/null; journalctl --vacuum-time=7d 2>/dev/null || true",
|
|
643
679
|
ServiceType.NVIDIA: "rm -rf ~/.cache/nvidia ~/.nv/ComputeCache ~/.cache/mesa_shader_cache",
|
|
644
|
-
ServiceType.UV: "uv cache clean
|
|
680
|
+
ServiceType.UV: "uv cache clean",
|
|
645
681
|
ServiceType.TORCH: "rm -rf ~/.cache/torch ~/.torch",
|
|
646
682
|
ServiceType.BUN: "rm -rf ~/.bun/install/cache",
|
|
647
683
|
ServiceType.PLAYWRIGHT: "rm -rf ~/.cache/ms-playwright ~/.cache/puppeteer",
|
|
@@ -730,9 +766,15 @@ class ServiceCleaner:
|
|
|
730
766
|
ServiceType.CONTAINERD: "sudo ls -la /var/lib/containerd 2>/dev/null || echo 'Requires sudo access'",
|
|
731
767
|
ServiceType.PODMAN: "podman system df -v || podman images",
|
|
732
768
|
# JS/Node
|
|
733
|
-
ServiceType.NPM:
|
|
769
|
+
ServiceType.NPM: (
|
|
770
|
+
"npm cache ls 2>/dev/null; "
|
|
771
|
+
"du -sh ~/.npm/_cacache ~/.npm/_npx ~/.npm/_prebuilds 2>/dev/null"
|
|
772
|
+
),
|
|
734
773
|
ServiceType.YARN: "yarn cache list 2>/dev/null || du -sh ~/.cache/yarn",
|
|
735
|
-
ServiceType.PNPM:
|
|
774
|
+
ServiceType.PNPM: (
|
|
775
|
+
"pnpm store status 2>/dev/null || "
|
|
776
|
+
"du -sh ~/.pnpm-store ~/.local/share/pnpm/store 2>/dev/null"
|
|
777
|
+
),
|
|
736
778
|
# Python
|
|
737
779
|
ServiceType.PIP: "pip cache dir && pip cache info 2>/dev/null || du -sh ~/.cache/pip",
|
|
738
780
|
ServiceType.CONDA: "conda info --envs 2>/dev/null && conda list 2>/dev/null | head -20 || du -sh ~/miniconda3",
|
|
@@ -146,9 +146,14 @@ class ServiceDataScanner:
|
|
|
146
146
|
],
|
|
147
147
|
ServiceType.CONTAINERD: ["/var/lib/containerd", "/run/containerd"],
|
|
148
148
|
ServiceType.PODMAN: ["~/.local/share/containers", "~/.config/containers"],
|
|
149
|
-
ServiceType.NPM: [
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
ServiceType.NPM: [
|
|
150
|
+
"~/.npm/_cacache",
|
|
151
|
+
"~/.npm/_npx",
|
|
152
|
+
"~/.npm/_prebuilds",
|
|
153
|
+
"~/.cache/npm",
|
|
154
|
+
],
|
|
155
|
+
ServiceType.YARN: ["~/.cache/yarn", "~/.yarn/berry/cache"],
|
|
156
|
+
ServiceType.PNPM: ["~/.pnpm-store", "~/.local/share/pnpm/store"],
|
|
152
157
|
ServiceType.PIP: ["~/.cache/pip"],
|
|
153
158
|
ServiceType.CONDA: [
|
|
154
159
|
"~/miniconda3/pkgs",
|
|
@@ -159,7 +164,7 @@ class ServiceDataScanner:
|
|
|
159
164
|
],
|
|
160
165
|
ServiceType.POETRY: ["~/.cache/pypoetry"],
|
|
161
166
|
ServiceType.GRADLE: ["~/.gradle", "~/.cache/gradle"],
|
|
162
|
-
ServiceType.MAVEN: ["~/.m2"],
|
|
167
|
+
ServiceType.MAVEN: ["~/.m2/repository"],
|
|
163
168
|
ServiceType.CARGO: ["~/.cargo/registry", "~/.cargo/git"],
|
|
164
169
|
ServiceType.GO: ["~/go/pkg", "~/.go/pkg"],
|
|
165
170
|
ServiceType.FLUTTER: ["~/.flutter-sdk", "~/flutter", "~/.pub-cache"],
|
|
@@ -224,7 +229,7 @@ class ServiceDataScanner:
|
|
|
224
229
|
"~/.nv/ComputeCache",
|
|
225
230
|
"~/.cache/mesa_shader_cache",
|
|
226
231
|
],
|
|
227
|
-
ServiceType.UV: ["~/.cache/uv"
|
|
232
|
+
ServiceType.UV: ["~/.cache/uv"],
|
|
228
233
|
ServiceType.TORCH: ["~/.cache/torch", "~/.torch"],
|
|
229
234
|
ServiceType.BUN: ["~/.bun/install/cache"],
|
|
230
235
|
ServiceType.PLAYWRIGHT: ["~/.cache/ms-playwright", "~/.cache/puppeteer"],
|
|
@@ -644,10 +649,17 @@ class ServiceDataScanner:
|
|
|
644
649
|
return self._cleaner.get_cleanup_plan(selected_services)
|
|
645
650
|
|
|
646
651
|
def cleanup_service(
|
|
647
|
-
self,
|
|
652
|
+
self,
|
|
653
|
+
service_type: str,
|
|
654
|
+
dry_run: bool = False,
|
|
655
|
+
planned_service: Dict[str, Any] | None = None,
|
|
648
656
|
) -> Dict[str, Any]:
|
|
649
657
|
"""Execute cleanup for a specific service."""
|
|
650
|
-
return self._cleaner.cleanup_service(
|
|
658
|
+
return self._cleaner.cleanup_service(
|
|
659
|
+
service_type,
|
|
660
|
+
dry_run,
|
|
661
|
+
planned_service=planned_service,
|
|
662
|
+
)
|
|
651
663
|
|
|
652
664
|
|
|
653
665
|
def main():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fixos
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.40
|
|
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.8451 (147 commits)
|
|
70
|
+
- 👤 **Human dev:** ~$3817 (38.2h @ $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
|
|
|
@@ -29,6 +29,7 @@ docker/ubuntu/Dockerfile
|
|
|
29
29
|
docs/examples/advanced_usage.py
|
|
30
30
|
docs/examples/quickstart.py
|
|
31
31
|
fixos/__init__.py
|
|
32
|
+
fixos/__main__.py
|
|
32
33
|
fixos/anonymizer.py
|
|
33
34
|
fixos/cli.py
|
|
34
35
|
fixos/config.py
|
|
@@ -158,6 +159,7 @@ tests/e2e/test_thumbnails_broken.py
|
|
|
158
159
|
tests/unit/__init__.py
|
|
159
160
|
tests/unit/test_anonymizer.py
|
|
160
161
|
tests/unit/test_cache_discovery.py
|
|
162
|
+
tests/unit/test_cleanup_cmd.py
|
|
161
163
|
tests/unit/test_core.py
|
|
162
164
|
tests/unit/test_dev_project_analyzer.py
|
|
163
165
|
tests/unit/test_executor.py
|
|
@@ -5,7 +5,7 @@ long_description = (Path(__file__).parent / "README.md").read_text(encoding="utf
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="fixos",
|
|
8
|
-
version="2.2.
|
|
8
|
+
version="2.2.40",
|
|
9
9
|
description="AI-powered Linux/Windows diagnostics and repair with anonymization",
|
|
10
10
|
long_description=long_description,
|
|
11
11
|
long_description_content_type="text/markdown",
|