fixos 2.2.41__tar.gz → 2.2.45__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.
Files changed (178) hide show
  1. {fixos-2.2.41 → fixos-2.2.45}/CHANGELOG.md +17 -0
  2. {fixos-2.2.41 → fixos-2.2.45}/PKG-INFO +6 -6
  3. {fixos-2.2.41 → fixos-2.2.45}/README.md +5 -5
  4. {fixos-2.2.41 → fixos-2.2.45}/fixos/__init__.py +1 -1
  5. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/cleanup_cmd.py +205 -15
  6. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/main.py +17 -1
  7. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/service_cleanup.py +457 -7
  8. {fixos-2.2.41 → fixos-2.2.45}/fixos.egg-info/PKG-INFO +6 -6
  9. {fixos-2.2.41 → fixos-2.2.45}/pyproject.toml +1 -1
  10. {fixos-2.2.41 → fixos-2.2.45}/setup.py +1 -1
  11. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_cleanup_cmd.py +195 -0
  12. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_service_cleanup.py +187 -0
  13. {fixos-2.2.41 → fixos-2.2.45}/.env.example +0 -0
  14. {fixos-2.2.41 → fixos-2.2.45}/LICENSE +0 -0
  15. {fixos-2.2.41 → fixos-2.2.45}/MANIFEST.in +0 -0
  16. {fixos-2.2.41 → fixos-2.2.45}/docker/README.md +0 -0
  17. {fixos-2.2.41 → fixos-2.2.45}/docker/TEST_RESULTS.md +0 -0
  18. {fixos-2.2.41 → fixos-2.2.45}/docker/TEST_RESULTS_V2.md +0 -0
  19. {fixos-2.2.41 → fixos-2.2.45}/docker/alpine/Dockerfile +0 -0
  20. {fixos-2.2.41 → fixos-2.2.45}/docker/arch/Dockerfile +0 -0
  21. {fixos-2.2.41 → fixos-2.2.45}/docker/base/Dockerfile +0 -0
  22. {fixos-2.2.41 → fixos-2.2.45}/docker/broken-audio/Dockerfile +0 -0
  23. {fixos-2.2.41 → fixos-2.2.45}/docker/broken-full/Dockerfile +0 -0
  24. {fixos-2.2.41 → fixos-2.2.45}/docker/broken-network/Dockerfile +0 -0
  25. {fixos-2.2.41 → fixos-2.2.45}/docker/broken-thumbnails/Dockerfile +0 -0
  26. {fixos-2.2.41 → fixos-2.2.45}/docker/debian/Dockerfile +0 -0
  27. {fixos-2.2.41 → fixos-2.2.45}/docker/docker-compose.multi-system.yml +0 -0
  28. {fixos-2.2.41 → fixos-2.2.45}/docker/docker-compose.yml +0 -0
  29. {fixos-2.2.41 → fixos-2.2.45}/docker/fedora/Dockerfile +0 -0
  30. {fixos-2.2.41 → fixos-2.2.45}/docker/test-multi-system.sh +0 -0
  31. {fixos-2.2.41 → fixos-2.2.45}/docker/test-scenarios.sh +0 -0
  32. {fixos-2.2.41 → fixos-2.2.45}/docker/ubuntu/Dockerfile +0 -0
  33. {fixos-2.2.41 → fixos-2.2.45}/docker/validate-scenario.py +0 -0
  34. {fixos-2.2.41 → fixos-2.2.45}/docs/examples/advanced_usage.py +0 -0
  35. {fixos-2.2.41 → fixos-2.2.45}/docs/examples/quickstart.py +0 -0
  36. {fixos-2.2.41 → fixos-2.2.45}/fixos/__main__.py +0 -0
  37. {fixos-2.2.41 → fixos-2.2.45}/fixos/agent/__init__.py +0 -0
  38. {fixos-2.2.41 → fixos-2.2.45}/fixos/agent/autonomous.py +0 -0
  39. {fixos-2.2.41 → fixos-2.2.45}/fixos/agent/autonomous_session.py +0 -0
  40. {fixos-2.2.41 → fixos-2.2.45}/fixos/agent/hitl.py +0 -0
  41. {fixos-2.2.41 → fixos-2.2.45}/fixos/agent/hitl_session.py +0 -0
  42. {fixos-2.2.41 → fixos-2.2.45}/fixos/agent/session_core.py +0 -0
  43. {fixos-2.2.41 → fixos-2.2.45}/fixos/agent/session_handlers.py +0 -0
  44. {fixos-2.2.41 → fixos-2.2.45}/fixos/agent/session_io.py +0 -0
  45. {fixos-2.2.41 → fixos-2.2.45}/fixos/anonymizer.py +0 -0
  46. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/__init__.py +0 -0
  47. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/_cleanup_flatpak.py +0 -0
  48. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/_cleanup_home.py +0 -0
  49. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/_cleanup_snap.py +0 -0
  50. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/_cleanup_system.py +0 -0
  51. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/_cleanup_utils.py +0 -0
  52. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/ask_cmd.py +0 -0
  53. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/config_cmd.py +0 -0
  54. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/features_cmd.py +0 -0
  55. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/fix_cmd.py +0 -0
  56. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/history_cmd.py +0 -0
  57. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/orchestrate_cmd.py +0 -0
  58. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/output_formatter.py +0 -0
  59. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/profile_cmd.py +0 -0
  60. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/projects_cmd.py +0 -0
  61. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/provider_cmd.py +0 -0
  62. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/quick_cmd.py +0 -0
  63. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/quickfix_cmd.py +0 -0
  64. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/report_cmd.py +0 -0
  65. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/rollback_cmd.py +0 -0
  66. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/scan_cmd.py +0 -0
  67. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/shared.py +0 -0
  68. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/token_cmd.py +0 -0
  69. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli/watch_cmd.py +0 -0
  70. {fixos-2.2.41 → fixos-2.2.45}/fixos/cli.py +0 -0
  71. {fixos-2.2.41 → fixos-2.2.45}/fixos/config.py +0 -0
  72. {fixos-2.2.41 → fixos-2.2.45}/fixos/config_interactive.py +0 -0
  73. {fixos-2.2.41 → fixos-2.2.45}/fixos/constants.py +0 -0
  74. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/__init__.py +0 -0
  75. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/_flatpak_analysis_mixin.py +0 -0
  76. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/_flatpak_execution_mixin.py +0 -0
  77. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/_flatpak_recommendations_mixin.py +0 -0
  78. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/_storage_container_mixin.py +0 -0
  79. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/_storage_system_mixin.py +0 -0
  80. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/_storage_user_mixin.py +0 -0
  81. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/cache_discovery.py +0 -0
  82. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/checks/__init__.py +0 -0
  83. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/checks/_shared.py +0 -0
  84. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/checks/audio.py +0 -0
  85. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/checks/file_analysis.py +0 -0
  86. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/checks/hardware.py +0 -0
  87. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/checks/packages.py +0 -0
  88. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/checks/resources.py +0 -0
  89. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/checks/security.py +0 -0
  90. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/checks/storage_optimization.py +0 -0
  91. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/checks/system_core.py +0 -0
  92. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/checks/thumbnails.py +0 -0
  93. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/dev_project_analyzer.py +0 -0
  94. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/disk_analyzer.py +0 -0
  95. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/flatpak_analyzer.py +0 -0
  96. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/project_scanner.py +0 -0
  97. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/quick_snapshot.py +0 -0
  98. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/service_details.py +0 -0
  99. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/service_scanner.py +0 -0
  100. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/storage_analyzer.py +0 -0
  101. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/system_checks.py +0 -0
  102. {fixos-2.2.41 → fixos-2.2.45}/fixos/diagnostics/utils.py +0 -0
  103. {fixos-2.2.41 → fixos-2.2.45}/fixos/features/__init__.py +0 -0
  104. {fixos-2.2.41 → fixos-2.2.45}/fixos/features/auditor.py +0 -0
  105. {fixos-2.2.41 → fixos-2.2.45}/fixos/features/catalog.py +0 -0
  106. {fixos-2.2.41 → fixos-2.2.45}/fixos/features/installer.py +0 -0
  107. {fixos-2.2.41 → fixos-2.2.45}/fixos/features/profiles.py +0 -0
  108. {fixos-2.2.41 → fixos-2.2.45}/fixos/features/renderer.py +0 -0
  109. {fixos-2.2.41 → fixos-2.2.45}/fixos/fixes/__init__.py +0 -0
  110. {fixos-2.2.41 → fixos-2.2.45}/fixos/interactive/__init__.py +0 -0
  111. {fixos-2.2.41 → fixos-2.2.45}/fixos/interactive/cleanup_planner.py +0 -0
  112. {fixos-2.2.41 → fixos-2.2.45}/fixos/llm_shell.py +0 -0
  113. {fixos-2.2.41 → fixos-2.2.45}/fixos/orchestrator/__init__.py +0 -0
  114. {fixos-2.2.41 → fixos-2.2.45}/fixos/orchestrator/executor.py +0 -0
  115. {fixos-2.2.41 → fixos-2.2.45}/fixos/orchestrator/graph.py +0 -0
  116. {fixos-2.2.41 → fixos-2.2.45}/fixos/orchestrator/orchestrator.py +0 -0
  117. {fixos-2.2.41 → fixos-2.2.45}/fixos/orchestrator/rollback.py +0 -0
  118. {fixos-2.2.41 → fixos-2.2.45}/fixos/platform_utils.py +0 -0
  119. {fixos-2.2.41 → fixos-2.2.45}/fixos/plugins/__init__.py +0 -0
  120. {fixos-2.2.41 → fixos-2.2.45}/fixos/plugins/base.py +0 -0
  121. {fixos-2.2.41 → fixos-2.2.45}/fixos/plugins/builtin/__init__.py +0 -0
  122. {fixos-2.2.41 → fixos-2.2.45}/fixos/plugins/builtin/audio.py +0 -0
  123. {fixos-2.2.41 → fixos-2.2.45}/fixos/plugins/builtin/disk.py +0 -0
  124. {fixos-2.2.41 → fixos-2.2.45}/fixos/plugins/builtin/hardware.py +0 -0
  125. {fixos-2.2.41 → fixos-2.2.45}/fixos/plugins/builtin/resources.py +0 -0
  126. {fixos-2.2.41 → fixos-2.2.45}/fixos/plugins/builtin/security.py +0 -0
  127. {fixos-2.2.41 → fixos-2.2.45}/fixos/plugins/builtin/thumbnails.py +0 -0
  128. {fixos-2.2.41 → fixos-2.2.45}/fixos/plugins/registry.py +0 -0
  129. {fixos-2.2.41 → fixos-2.2.45}/fixos/profiles/__init__.py +0 -0
  130. {fixos-2.2.41 → fixos-2.2.45}/fixos/providers/__init__.py +0 -0
  131. {fixos-2.2.41 → fixos-2.2.45}/fixos/providers/llm.py +0 -0
  132. {fixos-2.2.41 → fixos-2.2.45}/fixos/providers/llm_analyzer.py +0 -0
  133. {fixos-2.2.41 → fixos-2.2.45}/fixos/providers/schemas.py +0 -0
  134. {fixos-2.2.41 → fixos-2.2.45}/fixos/system_checks.py +0 -0
  135. {fixos-2.2.41 → fixos-2.2.45}/fixos/utils/__init__.py +0 -0
  136. {fixos-2.2.41 → fixos-2.2.45}/fixos/utils/anonymizer.py +0 -0
  137. {fixos-2.2.41 → fixos-2.2.45}/fixos/utils/terminal.py +0 -0
  138. {fixos-2.2.41 → fixos-2.2.45}/fixos/utils/timeout.py +0 -0
  139. {fixos-2.2.41 → fixos-2.2.45}/fixos/utils/web_search.py +0 -0
  140. {fixos-2.2.41 → fixos-2.2.45}/fixos/watch.py +0 -0
  141. {fixos-2.2.41 → fixos-2.2.45}/fixos.egg-info/SOURCES.txt +0 -0
  142. {fixos-2.2.41 → fixos-2.2.45}/fixos.egg-info/dependency_links.txt +0 -0
  143. {fixos-2.2.41 → fixos-2.2.45}/fixos.egg-info/entry_points.txt +0 -0
  144. {fixos-2.2.41 → fixos-2.2.45}/fixos.egg-info/requires.txt +0 -0
  145. {fixos-2.2.41 → fixos-2.2.45}/fixos.egg-info/top_level.txt +0 -0
  146. {fixos-2.2.41 → fixos-2.2.45}/pytest.ini +0 -0
  147. {fixos-2.2.41 → fixos-2.2.45}/requirements-dev.txt +0 -0
  148. {fixos-2.2.41 → fixos-2.2.45}/requirements.txt +0 -0
  149. {fixos-2.2.41 → fixos-2.2.45}/scripts/pyqual-calibrate.py +0 -0
  150. {fixos-2.2.41 → fixos-2.2.45}/setup.cfg +0 -0
  151. {fixos-2.2.41 → fixos-2.2.45}/tests/__init__.py +0 -0
  152. {fixos-2.2.41 → fixos-2.2.45}/tests/conftest.py +0 -0
  153. {fixos-2.2.41 → fixos-2.2.45}/tests/e2e/__init__.py +0 -0
  154. {fixos-2.2.41 → fixos-2.2.45}/tests/e2e/test_anonymization_layers.py +0 -0
  155. {fixos-2.2.41 → fixos-2.2.45}/tests/e2e/test_audio_broken.py +0 -0
  156. {fixos-2.2.41 → fixos-2.2.45}/tests/e2e/test_cli.py +0 -0
  157. {fixos-2.2.41 → fixos-2.2.45}/tests/e2e/test_diagnostics_integration.py +0 -0
  158. {fixos-2.2.41 → fixos-2.2.45}/tests/e2e/test_executor.py +0 -0
  159. {fixos-2.2.41 → fixos-2.2.45}/tests/e2e/test_multi_system.py +0 -0
  160. {fixos-2.2.41 → fixos-2.2.45}/tests/e2e/test_network_broken.py +0 -0
  161. {fixos-2.2.41 → fixos-2.2.45}/tests/e2e/test_thumbnails_broken.py +0 -0
  162. {fixos-2.2.41 → fixos-2.2.45}/tests/test_fixos.py +0 -0
  163. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/__init__.py +0 -0
  164. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_anonymizer.py +0 -0
  165. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_cache_discovery.py +0 -0
  166. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_core.py +0 -0
  167. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_dev_project_analyzer.py +0 -0
  168. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_executor.py +0 -0
  169. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_llm_provider.py +0 -0
  170. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_orchestrator.py +0 -0
  171. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_project_scanner.py +0 -0
  172. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_projects_cmd.py +0 -0
  173. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_quick_cmd.py +0 -0
  174. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_quick_snapshot.py +0 -0
  175. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_resources_quick.py +0 -0
  176. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_security_quick.py +0 -0
  177. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_service_scanner.py +0 -0
  178. {fixos-2.2.41 → fixos-2.2.45}/tests/unit/test_system_checks_parallel.py +0 -0
@@ -51,6 +51,23 @@
51
51
  rekurencyjnych skanów `/` oraz `/home` z szybkich kontroli.
52
52
  - Czyszczenie cache JetBrains trafia w aktualną ścieżkę i wymaga zamknięcia IDE.
53
53
 
54
+ ## [2.2.45] - 2026-08-07
55
+
56
+ ### Docs
57
+ - Update README.md
58
+
59
+ ### Test
60
+ - Update tests/unit/test_cleanup_cmd.py
61
+ - Update tests/unit/test_service_cleanup.py
62
+
63
+ ### Other
64
+ - Update VERSION
65
+ - Update fixos/__init__.py
66
+ - Update fixos/cli/cleanup_cmd.py
67
+ - Update fixos/cli/main.py
68
+ - Update fixos/diagnostics/service_cleanup.py
69
+ - Update uv.lock
70
+
54
71
  ## [2.2.41] - 2026-07-23
55
72
 
56
73
  ### Docs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fixos
3
- Version: 2.2.41
3
+ Version: 2.2.45
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,13 +63,13 @@ AI-powered OS Diagnostics
63
63
 
64
64
  ## AI Cost Tracking
65
65
 
66
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-2.2.41-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
67
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$4.87-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-39.1h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
66
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-2.2.45-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
67
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$4.81-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-39.6h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
68
68
 
69
- - 🤖 **LLM usage:** $4.8653 (149 commits)
70
- - 👤 **Human dev:** ~$3913 (39.1h @ $100/h, 30min dedup)
69
+ - 🤖 **LLM usage:** $4.8099 (150 commits)
70
+ - 👤 **Human dev:** ~$3959 (39.6h @ $100/h, 30min dedup)
71
71
 
72
- Generated on 2026-07-23 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
72
+ Generated on 2026-08-07 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
73
73
 
74
74
  ---
75
75
 
@@ -19,13 +19,13 @@ AI-powered OS Diagnostics
19
19
 
20
20
  ## AI Cost Tracking
21
21
 
22
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-2.2.41-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
23
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$4.87-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-39.1h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
22
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-2.2.45-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
23
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$4.81-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-39.6h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
24
24
 
25
- - 🤖 **LLM usage:** $4.8653 (149 commits)
26
- - 👤 **Human dev:** ~$3913 (39.1h @ $100/h, 30min dedup)
25
+ - 🤖 **LLM usage:** $4.8099 (150 commits)
26
+ - 👤 **Human dev:** ~$3959 (39.6h @ $100/h, 30min dedup)
27
27
 
28
- Generated on 2026-07-23 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
28
+ Generated on 2026-08-07 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
29
29
 
30
30
  ---
31
31
 
@@ -1,3 +1,3 @@
1
1
  """fixos – AI-powered Linux/Windows diagnostics and repair."""
2
2
 
3
- __version__ = "2.2.41"
3
+ __version__ = "2.2.45"
@@ -17,6 +17,11 @@ from fixos.constants import DEFAULT_CLEANUP_THRESHOLD_MB
17
17
  # Re-export public symbols used by fixos.cli (backward-compat)
18
18
  from fixos.cli._cleanup_flatpak import _cleanup_flatpak_detailed # noqa: F401
19
19
  from fixos.cli._cleanup_system import _cleanup_full_system
20
+ from fixos.diagnostics.service_cleanup import (
21
+ DEFAULT_DOCKER_OLD_UNUSED_DAYS,
22
+ DEFAULT_OLLAMA_OLD_UNUSED_DAYS,
23
+ ServiceCleaner,
24
+ )
20
25
 
21
26
 
22
27
  # ── Service display helpers ───────────────────────────────────────────────
@@ -129,17 +134,33 @@ def _error_message(result: dict) -> str:
129
134
  return "nieznany błąd"
130
135
 
131
136
 
137
+ def _execute_planned_cleanup(scanner, svc: dict, *, dry_run: bool = False) -> dict:
138
+ """Run a planned cleanup entry (including age-bounded docker/ollama actions)."""
139
+ kind = svc.get("cleanup_kind")
140
+ cleaner = ServiceCleaner(scanner)
141
+ if kind == "ollama-old":
142
+ return cleaner.cleanup_ollama_old_unused(
143
+ days=int(svc.get("days") or DEFAULT_OLLAMA_OLD_UNUSED_DAYS),
144
+ dry_run=dry_run,
145
+ )
146
+ if kind == "docker-old":
147
+ return cleaner.cleanup_docker_old_unused(
148
+ days=int(svc.get("days") or DEFAULT_DOCKER_OLD_UNUSED_DAYS),
149
+ dry_run=dry_run,
150
+ )
151
+ return scanner.cleanup_service(
152
+ svc["service_type"],
153
+ dry_run=dry_run,
154
+ planned_service=svc,
155
+ )
156
+
157
+
132
158
  def _execute_safe_cleanup(services: list, scanner) -> float:
133
159
  """Execute cleanup for safe-to-remove services. Returns total space freed in GB."""
134
160
  total_freed = 0.0
135
161
  for svc in services:
136
- svc_type = svc["service_type"]
137
- click.echo(f"Czyszczenie {svc_type}...")
138
- result = scanner.cleanup_service(
139
- svc_type,
140
- dry_run=False,
141
- planned_service=svc,
142
- )
162
+ click.echo(f"Czyszczenie {svc.get('name') or svc['service_type']}...")
163
+ result = _execute_planned_cleanup(scanner, svc, dry_run=False)
143
164
  if result["success"]:
144
165
  freed = result.get("space_freed_gb", 0)
145
166
  total_freed += freed
@@ -441,6 +462,112 @@ def _cleanup_single_service(
441
462
  click.echo(f"Output: {result['output']}")
442
463
 
443
464
 
465
+ def _cleanup_docker_old_unused(
466
+ scanner, days: int, json_output: bool, dry_run: bool
467
+ ) -> None:
468
+ """Prune unused Docker images (and old build cache) older than N days."""
469
+ cleaner = ServiceCleaner(scanner)
470
+ try:
471
+ result = cleaner.cleanup_docker_old_unused(days=days, dry_run=dry_run)
472
+ except ValueError as exc:
473
+ click.echo(click.style(f"Błąd: {exc}", fg="red"))
474
+ return
475
+
476
+ if json_output:
477
+ import json
478
+
479
+ click.echo(json.dumps(result, indent=2, default=str))
480
+ return
481
+
482
+ click.echo(
483
+ click.style(
484
+ f"Docker — nieużywane obrazy starsze niż {days} dni",
485
+ fg="yellow",
486
+ )
487
+ )
488
+ click.echo(f" Komenda: {result.get('command')}")
489
+ if dry_run:
490
+ click.echo(click.style("[TRYB DRY-RUN] - brak faktycznych zmian", fg="cyan"))
491
+
492
+ if result.get("success"):
493
+ if dry_run:
494
+ click.echo(click.style("Symulacja zakończona", fg="green"))
495
+ if result.get("output"):
496
+ for line in str(result["output"]).splitlines():
497
+ click.echo(f" {line}")
498
+ if result.get("estimated_max_gb", 0) > 0:
499
+ click.echo(
500
+ f" Szacowane maksimum (Images+Build Cache reclaimable): "
501
+ f"{result['estimated_max_gb']:.2f} GB "
502
+ f"(filtr until zwykle usunie mniej)"
503
+ )
504
+ else:
505
+ click.echo(click.style("Zakończono czyszczenie docker-old", fg="green"))
506
+ if result.get("space_freed_gb", 0) > 0:
507
+ click.echo(f" Zwolniono: {result['space_freed_gb']:.2f} GB")
508
+ elif result.get("output"):
509
+ click.echo(f" {result['output'].strip()[:500]}")
510
+ else:
511
+ click.echo(click.style(f"Błąd: {_error_message(result)}", fg="red"))
512
+ if result.get("output"):
513
+ click.echo(f"Output: {result['output']}")
514
+
515
+
516
+ def _cleanup_ollama_old_unused(
517
+ scanner, days: int, json_output: bool, dry_run: bool
518
+ ) -> None:
519
+ """Remove Ollama models not modified for more than N days."""
520
+ cleaner = ServiceCleaner(scanner)
521
+ try:
522
+ result = cleaner.cleanup_ollama_old_unused(days=days, dry_run=dry_run)
523
+ except ValueError as exc:
524
+ click.echo(click.style(f"Błąd: {exc}", fg="red"))
525
+ return
526
+
527
+ if json_output:
528
+ import json
529
+
530
+ click.echo(json.dumps(result, indent=2, default=str))
531
+ return
532
+
533
+ click.echo(
534
+ click.style(
535
+ f"Ollama — modele niezmieniane od {days}+ dni",
536
+ fg="yellow",
537
+ )
538
+ )
539
+ if result.get("command"):
540
+ click.echo(f" Komenda: {result['command']}")
541
+ if dry_run:
542
+ click.echo(click.style("[TRYB DRY-RUN] - brak faktycznych zmian", fg="cyan"))
543
+
544
+ if result.get("success"):
545
+ if dry_run:
546
+ click.echo(click.style("Symulacja zakończona", fg="green"))
547
+ if result.get("output"):
548
+ for line in str(result["output"]).splitlines():
549
+ click.echo(f" {line}")
550
+ if result.get("estimated_max_gb", 0) > 0:
551
+ click.echo(
552
+ f" Szacowane zwolnienie: {result['estimated_max_gb']:.2f} GB"
553
+ )
554
+ if result.get("skipped_running"):
555
+ click.echo(
556
+ " Pominięto uruchomione: "
557
+ + ", ".join(result["skipped_running"])
558
+ )
559
+ else:
560
+ click.echo(click.style("Zakończono czyszczenie ollama-old", fg="green"))
561
+ if result.get("space_freed_gb", 0) > 0:
562
+ click.echo(f" Zwolniono: {result['space_freed_gb']:.2f} GB")
563
+ if result.get("output"):
564
+ click.echo(f" {result['output'].strip()[:500]}")
565
+ else:
566
+ click.echo(click.style(f"Błąd: {_error_message(result)}", fg="red"))
567
+ if result.get("output"):
568
+ click.echo(f"Output: {result['output']}")
569
+
570
+
444
571
  # ── Interactive cleanup orchestration ─────────────────────────────────────
445
572
 
446
573
 
@@ -540,11 +667,7 @@ def _execute_individual_cleanup(services: list, scanner) -> float:
540
667
  continue
541
668
 
542
669
  click.echo(f"Czyszczenie {svc['name']}...")
543
- result = scanner.cleanup_service(
544
- svc["service_type"],
545
- dry_run=False,
546
- planned_service=svc,
547
- )
670
+ result = _execute_planned_cleanup(scanner, svc, dry_run=False)
548
671
  if result["success"]:
549
672
  freed = float(result.get("space_freed_gb", 0))
550
673
  total_freed += freed
@@ -602,7 +725,37 @@ def _run_interactive_cleanup(plan: dict, list_only: bool, scanner) -> None:
602
725
  "--cleanup",
603
726
  "-c",
604
727
  default=None,
605
- help="Wyczyść konkretną usługę (docker, ollama, npm, ...)",
728
+ help="Wyczyść konkretną usługę (docker, docker-old, ollama-old, ollama, npm, ...)",
729
+ )
730
+ @click.option(
731
+ "--docker-old",
732
+ "docker_old",
733
+ is_flag=True,
734
+ default=False,
735
+ help=(
736
+ "Usuń nieużywane obrazy Docker (i stary build cache) starsze niż --days "
737
+ f"(domyślnie {DEFAULT_DOCKER_OLD_UNUSED_DAYS}); nie rusza wolumenów ani obrazów w użyciu"
738
+ ),
739
+ )
740
+ @click.option(
741
+ "--ollama-old",
742
+ "ollama_old",
743
+ is_flag=True,
744
+ default=False,
745
+ help=(
746
+ "Usuń modele Ollama niezmieniane od --days dni "
747
+ f"(domyślnie {DEFAULT_OLLAMA_OLD_UNUSED_DAYS}); pomija modele aktualnie uruchomione"
748
+ ),
749
+ )
750
+ @click.option(
751
+ "--days",
752
+ default=None,
753
+ type=int,
754
+ help=(
755
+ "Wiek w dniach dla --docker-old "
756
+ f"(domyślnie {DEFAULT_DOCKER_OLD_UNUSED_DAYS}) lub --ollama-old "
757
+ f"(domyślnie {DEFAULT_OLLAMA_OLD_UNUSED_DAYS})"
758
+ ),
606
759
  )
607
760
  @click.option(
608
761
  "--dry-run",
@@ -626,7 +779,16 @@ def _run_interactive_cleanup(plan: dict, list_only: bool, scanner) -> None:
626
779
  help="Pełna analiza systemu (DNF, kernels, logs, Docker, cache)",
627
780
  )
628
781
  def cleanup_services(
629
- threshold, services, json_output, cleanup, dry_run, list_only, full_analysis
782
+ threshold,
783
+ services,
784
+ json_output,
785
+ cleanup,
786
+ docker_old,
787
+ ollama_old,
788
+ days,
789
+ dry_run,
790
+ list_only,
791
+ full_analysis,
630
792
  ) -> None:
631
793
  """
632
794
  Skanuje i czyści dane usług przekraczające próg.
@@ -643,7 +805,12 @@ def cleanup_services(
643
805
  fixos cleanup -t 1000 # próg 1000MB (1GB)
644
806
  fixos cleanup -s docker,ollama # tylko Docker i Ollama
645
807
  fixos cleanup --list # tylko lista, bez czyszczenia
646
- fixos cleanup -c docker --dry-run # symulacja czyszczenia Dockera
808
+ fixos cleanup -c docker --dry-run # tylko cache buildów >7 dni
809
+ fixos cleanup --docker-old --days 30 --dry-run
810
+ # nieużywane obrazy (+ cache) starsze niż 30 dni
811
+ fixos cleanup --ollama-old --days 90 --dry-run
812
+ # modele Ollama niezmieniane od 90+ dni
813
+ fixos cleanup -c ollama-old
647
814
  fixos cleanup --full # pełna analiza systemu
648
815
  """
649
816
  if full_analysis:
@@ -652,6 +819,29 @@ def cleanup_services(
652
819
 
653
820
  scanner = ServiceDataScanner(threshold_mb=threshold)
654
821
 
822
+ want_docker_old = docker_old or (cleanup == "docker-old")
823
+ want_ollama_old = ollama_old or (cleanup == "ollama-old")
824
+ if want_docker_old and want_ollama_old:
825
+ click.echo(
826
+ click.style(
827
+ "Wybierz jedno: --docker-old albo --ollama-old (nie oba naraz).",
828
+ fg="red",
829
+ )
830
+ )
831
+ return
832
+ if want_docker_old:
833
+ effective_days = (
834
+ days if days is not None else DEFAULT_DOCKER_OLD_UNUSED_DAYS
835
+ )
836
+ _cleanup_docker_old_unused(scanner, effective_days, json_output, dry_run)
837
+ return
838
+ if want_ollama_old:
839
+ effective_days = (
840
+ days if days is not None else DEFAULT_OLLAMA_OLD_UNUSED_DAYS
841
+ )
842
+ _cleanup_ollama_old_unused(scanner, effective_days, json_output, dry_run)
843
+ return
844
+
655
845
  if cleanup:
656
846
  if cleanup == "flatpak":
657
847
  _cleanup_flatpak_detailed(scanner, json_output, dry_run)
@@ -72,6 +72,16 @@ def _print_welcome() -> None:
72
72
  ("fixos scan", "", "Diagnostyka systemu bez AI"),
73
73
  ("fixos quickfix", "", "Naprawy offline bez API (baza znanych bugów)"),
74
74
  ("fixos cleanup", "", "Skanuj i czyść dane usług (Docker, Ollama)"),
75
+ (
76
+ "fixos cleanup --docker-old",
77
+ "",
78
+ "Usuń nieużywane obrazy Docker starsze niż 30 dni",
79
+ ),
80
+ (
81
+ "fixos cleanup --ollama-old",
82
+ "",
83
+ "Usuń modele Ollama niezmieniane od 90+ dni",
84
+ ),
75
85
  (
76
86
  "fixos projects",
77
87
  "",
@@ -90,7 +100,7 @@ def _print_welcome() -> None:
90
100
  ]
91
101
 
92
102
  for cmd, icon, desc in commands:
93
- cmd_styled = click.style(f"{cmd:<26}", fg="yellow")
103
+ cmd_styled = click.style(f"{cmd:<32}", fg="yellow")
94
104
  click.echo(f" {icon} {cmd_styled} {desc}")
95
105
 
96
106
  click.echo()
@@ -142,6 +152,12 @@ def _print_welcome() -> None:
142
152
  click.echo(
143
153
  f"{click.style(' fixos fix', fg='yellow')} # pełna diagnostyka + naprawa"
144
154
  )
155
+ click.echo(
156
+ f"{click.style(' fixos cleanup --docker-old --dry-run', fg='yellow')} # stare nieużywane obrazy Docker"
157
+ )
158
+ click.echo(
159
+ f"{click.style(' fixos cleanup --ollama-old --dry-run', fg='yellow')} # stare modele Ollama (90+ dni)"
160
+ )
145
161
  click.echo(
146
162
  f"{click.style(' fixos fix --modules security,resources', fg='yellow')} # bezpieczeństwo + zasoby"
147
163
  )