fixos 2.2.22__tar.gz → 2.2.23__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 (142) hide show
  1. {fixos-2.2.22 → fixos-2.2.23}/CHANGELOG.md +23 -0
  2. {fixos-2.2.22 → fixos-2.2.23}/PKG-INFO +5 -5
  3. {fixos-2.2.22 → fixos-2.2.23}/README.md +4 -4
  4. {fixos-2.2.22 → fixos-2.2.23}/fixos/__init__.py +1 -1
  5. {fixos-2.2.22 → fixos-2.2.23}/fixos/agent/autonomous_session.py +23 -16
  6. {fixos-2.2.22 → fixos-2.2.23}/fixos/agent/hitl_session.py +5 -5
  7. {fixos-2.2.22 → fixos-2.2.23}/fixos/agent/session_core.py +2 -1
  8. {fixos-2.2.22 → fixos-2.2.23}/fixos/agent/session_handlers.py +7 -5
  9. {fixos-2.2.22 → fixos-2.2.23}/fixos/agent/session_io.py +2 -2
  10. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/config_cmd.py +2 -2
  11. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/features_cmd.py +3 -3
  12. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/fix_cmd.py +9 -4
  13. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/history_cmd.py +1 -1
  14. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/orchestrate_cmd.py +1 -1
  15. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/profile_cmd.py +1 -1
  16. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/provider_cmd.py +2 -2
  17. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/scan_cmd.py +2 -2
  18. {fixos-2.2.22 → fixos-2.2.23}/fixos/constants.py +21 -0
  19. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/disk_analyzer.py +13 -14
  20. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/service_scanner.py +2 -1
  21. {fixos-2.2.22 → fixos-2.2.23}/fixos.egg-info/PKG-INFO +5 -5
  22. {fixos-2.2.22 → fixos-2.2.23}/pyproject.toml +1 -1
  23. {fixos-2.2.22 → fixos-2.2.23}/setup.py +1 -1
  24. {fixos-2.2.22 → fixos-2.2.23}/.env.example +0 -0
  25. {fixos-2.2.22 → fixos-2.2.23}/LICENSE +0 -0
  26. {fixos-2.2.22 → fixos-2.2.23}/MANIFEST.in +0 -0
  27. {fixos-2.2.22 → fixos-2.2.23}/docker/README.md +0 -0
  28. {fixos-2.2.22 → fixos-2.2.23}/docker/TEST_RESULTS.md +0 -0
  29. {fixos-2.2.22 → fixos-2.2.23}/docker/TEST_RESULTS_V2.md +0 -0
  30. {fixos-2.2.22 → fixos-2.2.23}/docker/alpine/Dockerfile +0 -0
  31. {fixos-2.2.22 → fixos-2.2.23}/docker/arch/Dockerfile +0 -0
  32. {fixos-2.2.22 → fixos-2.2.23}/docker/base/Dockerfile +0 -0
  33. {fixos-2.2.22 → fixos-2.2.23}/docker/broken-audio/Dockerfile +0 -0
  34. {fixos-2.2.22 → fixos-2.2.23}/docker/broken-full/Dockerfile +0 -0
  35. {fixos-2.2.22 → fixos-2.2.23}/docker/broken-network/Dockerfile +0 -0
  36. {fixos-2.2.22 → fixos-2.2.23}/docker/broken-thumbnails/Dockerfile +0 -0
  37. {fixos-2.2.22 → fixos-2.2.23}/docker/debian/Dockerfile +0 -0
  38. {fixos-2.2.22 → fixos-2.2.23}/docker/docker-compose.multi-system.yml +0 -0
  39. {fixos-2.2.22 → fixos-2.2.23}/docker/docker-compose.yml +0 -0
  40. {fixos-2.2.22 → fixos-2.2.23}/docker/fedora/Dockerfile +0 -0
  41. {fixos-2.2.22 → fixos-2.2.23}/docker/test-multi-system.sh +0 -0
  42. {fixos-2.2.22 → fixos-2.2.23}/docker/ubuntu/Dockerfile +0 -0
  43. {fixos-2.2.22 → fixos-2.2.23}/docs/examples/advanced_usage.py +0 -0
  44. {fixos-2.2.22 → fixos-2.2.23}/docs/examples/quickstart.py +0 -0
  45. {fixos-2.2.22 → fixos-2.2.23}/fixos/agent/__init__.py +0 -0
  46. {fixos-2.2.22 → fixos-2.2.23}/fixos/agent/autonomous.py +0 -0
  47. {fixos-2.2.22 → fixos-2.2.23}/fixos/agent/hitl.py +0 -0
  48. {fixos-2.2.22 → fixos-2.2.23}/fixos/anonymizer.py +0 -0
  49. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/__init__.py +0 -0
  50. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/ask_cmd.py +0 -0
  51. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/cleanup_cmd.py +0 -0
  52. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/main.py +0 -0
  53. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/quickfix_cmd.py +0 -0
  54. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/report_cmd.py +0 -0
  55. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/rollback_cmd.py +0 -0
  56. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/shared.py +0 -0
  57. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/token_cmd.py +0 -0
  58. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli/watch_cmd.py +0 -0
  59. {fixos-2.2.22 → fixos-2.2.23}/fixos/cli.py +0 -0
  60. {fixos-2.2.22 → fixos-2.2.23}/fixos/config.py +0 -0
  61. {fixos-2.2.22 → fixos-2.2.23}/fixos/config_interactive.py +0 -0
  62. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/__init__.py +0 -0
  63. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/checks/__init__.py +0 -0
  64. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/checks/_shared.py +0 -0
  65. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/checks/audio.py +0 -0
  66. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/checks/hardware.py +0 -0
  67. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/checks/resources.py +0 -0
  68. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/checks/security.py +0 -0
  69. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/checks/system_core.py +0 -0
  70. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/checks/thumbnails.py +0 -0
  71. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/dev_project_analyzer.py +0 -0
  72. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/flatpak_analyzer.py +0 -0
  73. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/service_cleanup.py +0 -0
  74. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/service_details.py +0 -0
  75. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/storage_analyzer.py +0 -0
  76. {fixos-2.2.22 → fixos-2.2.23}/fixos/diagnostics/system_checks.py +0 -0
  77. {fixos-2.2.22 → fixos-2.2.23}/fixos/features/__init__.py +0 -0
  78. {fixos-2.2.22 → fixos-2.2.23}/fixos/features/auditor.py +0 -0
  79. {fixos-2.2.22 → fixos-2.2.23}/fixos/features/catalog.py +0 -0
  80. {fixos-2.2.22 → fixos-2.2.23}/fixos/features/installer.py +0 -0
  81. {fixos-2.2.22 → fixos-2.2.23}/fixos/features/profiles.py +0 -0
  82. {fixos-2.2.22 → fixos-2.2.23}/fixos/features/renderer.py +0 -0
  83. {fixos-2.2.22 → fixos-2.2.23}/fixos/fixes/__init__.py +0 -0
  84. {fixos-2.2.22 → fixos-2.2.23}/fixos/interactive/__init__.py +0 -0
  85. {fixos-2.2.22 → fixos-2.2.23}/fixos/interactive/cleanup_planner.py +0 -0
  86. {fixos-2.2.22 → fixos-2.2.23}/fixos/llm_shell.py +0 -0
  87. {fixos-2.2.22 → fixos-2.2.23}/fixos/orchestrator/__init__.py +0 -0
  88. {fixos-2.2.22 → fixos-2.2.23}/fixos/orchestrator/executor.py +0 -0
  89. {fixos-2.2.22 → fixos-2.2.23}/fixos/orchestrator/graph.py +0 -0
  90. {fixos-2.2.22 → fixos-2.2.23}/fixos/orchestrator/orchestrator.py +0 -0
  91. {fixos-2.2.22 → fixos-2.2.23}/fixos/orchestrator/rollback.py +0 -0
  92. {fixos-2.2.22 → fixos-2.2.23}/fixos/platform_utils.py +0 -0
  93. {fixos-2.2.22 → fixos-2.2.23}/fixos/plugins/__init__.py +0 -0
  94. {fixos-2.2.22 → fixos-2.2.23}/fixos/plugins/base.py +0 -0
  95. {fixos-2.2.22 → fixos-2.2.23}/fixos/plugins/builtin/__init__.py +0 -0
  96. {fixos-2.2.22 → fixos-2.2.23}/fixos/plugins/builtin/audio.py +0 -0
  97. {fixos-2.2.22 → fixos-2.2.23}/fixos/plugins/builtin/disk.py +0 -0
  98. {fixos-2.2.22 → fixos-2.2.23}/fixos/plugins/builtin/hardware.py +0 -0
  99. {fixos-2.2.22 → fixos-2.2.23}/fixos/plugins/builtin/resources.py +0 -0
  100. {fixos-2.2.22 → fixos-2.2.23}/fixos/plugins/builtin/security.py +0 -0
  101. {fixos-2.2.22 → fixos-2.2.23}/fixos/plugins/builtin/thumbnails.py +0 -0
  102. {fixos-2.2.22 → fixos-2.2.23}/fixos/plugins/registry.py +0 -0
  103. {fixos-2.2.22 → fixos-2.2.23}/fixos/profiles/__init__.py +0 -0
  104. {fixos-2.2.22 → fixos-2.2.23}/fixos/providers/__init__.py +0 -0
  105. {fixos-2.2.22 → fixos-2.2.23}/fixos/providers/llm.py +0 -0
  106. {fixos-2.2.22 → fixos-2.2.23}/fixos/providers/llm_analyzer.py +0 -0
  107. {fixos-2.2.22 → fixos-2.2.23}/fixos/providers/schemas.py +0 -0
  108. {fixos-2.2.22 → fixos-2.2.23}/fixos/system_checks.py +0 -0
  109. {fixos-2.2.22 → fixos-2.2.23}/fixos/utils/__init__.py +0 -0
  110. {fixos-2.2.22 → fixos-2.2.23}/fixos/utils/anonymizer.py +0 -0
  111. {fixos-2.2.22 → fixos-2.2.23}/fixos/utils/terminal.py +0 -0
  112. {fixos-2.2.22 → fixos-2.2.23}/fixos/utils/timeout.py +0 -0
  113. {fixos-2.2.22 → fixos-2.2.23}/fixos/utils/web_search.py +0 -0
  114. {fixos-2.2.22 → fixos-2.2.23}/fixos/watch.py +0 -0
  115. {fixos-2.2.22 → fixos-2.2.23}/fixos.egg-info/SOURCES.txt +0 -0
  116. {fixos-2.2.22 → fixos-2.2.23}/fixos.egg-info/dependency_links.txt +0 -0
  117. {fixos-2.2.22 → fixos-2.2.23}/fixos.egg-info/entry_points.txt +0 -0
  118. {fixos-2.2.22 → fixos-2.2.23}/fixos.egg-info/requires.txt +0 -0
  119. {fixos-2.2.22 → fixos-2.2.23}/fixos.egg-info/top_level.txt +0 -0
  120. {fixos-2.2.22 → fixos-2.2.23}/pytest.ini +0 -0
  121. {fixos-2.2.22 → fixos-2.2.23}/requirements-dev.txt +0 -0
  122. {fixos-2.2.22 → fixos-2.2.23}/requirements.txt +0 -0
  123. {fixos-2.2.22 → fixos-2.2.23}/scripts/pyqual-calibrate.py +0 -0
  124. {fixos-2.2.22 → fixos-2.2.23}/setup.cfg +0 -0
  125. {fixos-2.2.22 → fixos-2.2.23}/tests/__init__.py +0 -0
  126. {fixos-2.2.22 → fixos-2.2.23}/tests/conftest.py +0 -0
  127. {fixos-2.2.22 → fixos-2.2.23}/tests/e2e/__init__.py +0 -0
  128. {fixos-2.2.22 → fixos-2.2.23}/tests/e2e/test_anonymization_layers.py +0 -0
  129. {fixos-2.2.22 → fixos-2.2.23}/tests/e2e/test_audio_broken.py +0 -0
  130. {fixos-2.2.22 → fixos-2.2.23}/tests/e2e/test_cli.py +0 -0
  131. {fixos-2.2.22 → fixos-2.2.23}/tests/e2e/test_executor.py +0 -0
  132. {fixos-2.2.22 → fixos-2.2.23}/tests/e2e/test_multi_system.py +0 -0
  133. {fixos-2.2.22 → fixos-2.2.23}/tests/e2e/test_network_broken.py +0 -0
  134. {fixos-2.2.22 → fixos-2.2.23}/tests/e2e/test_thumbnails_broken.py +0 -0
  135. {fixos-2.2.22 → fixos-2.2.23}/tests/test_fixos.py +0 -0
  136. {fixos-2.2.22 → fixos-2.2.23}/tests/unit/__init__.py +0 -0
  137. {fixos-2.2.22 → fixos-2.2.23}/tests/unit/test_anonymizer.py +0 -0
  138. {fixos-2.2.22 → fixos-2.2.23}/tests/unit/test_core.py +0 -0
  139. {fixos-2.2.22 → fixos-2.2.23}/tests/unit/test_executor.py +0 -0
  140. {fixos-2.2.22 → fixos-2.2.23}/tests/unit/test_orchestrator.py +0 -0
  141. {fixos-2.2.22 → fixos-2.2.23}/tests/unit/test_service_cleanup.py +0 -0
  142. {fixos-2.2.22 → fixos-2.2.23}/tests/unit/test_service_scanner.py +0 -0
@@ -150,6 +150,29 @@ fix(goal): code analysis engine
150
150
  - **refactor(cli):** Usunięto zduplikowany kod ujednolicając funkcje analizy dysku do wspólnego helpera `_run_disk_analysis`.
151
151
  - **refactor(ui):** Usunięto ikony Unicode z CLI i sformatowano wyjście `stderr` oraz standardowego logowania na czysty kod Markdown dla poprawy czytelności w oknach terminalowych.
152
152
 
153
+ ## [2.2.23] - 2026-05-04
154
+
155
+ ### Docs
156
+ - Update README.md
157
+ - Update REFACTORING_PROGRESS.md
158
+ - Update SUMD.md
159
+ - Update SUMR.md
160
+ - Update project/README.md
161
+ - Update project/context.md
162
+
163
+ ### Other
164
+ - Update app.doql.less
165
+ - Update fixos/agent/autonomous_session.py
166
+ - Update fixos/agent/hitl_session.py
167
+ - Update fixos/agent/session_core.py
168
+ - Update fixos/agent/session_handlers.py
169
+ - Update fixos/agent/session_io.py
170
+ - Update fixos/cli/cleanup_cmd.py
171
+ - Update fixos/cli/config_cmd.py
172
+ - Update fixos/cli/features_cmd.py
173
+ - Update fixos/cli/fix_cmd.py
174
+ - ... and 23 more files
175
+
153
176
  ## [2.2.22] - 2026-05-04
154
177
 
155
178
  ### Docs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fixos
3
- Version: 2.2.22
3
+ Version: 2.2.23
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
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-2.2.22-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-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-22.8h-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.23-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-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-23.4h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
68
68
 
69
- - 🤖 **LLM usage:** $7.5000 (121 commits)
70
- - 👤 **Human dev:** ~$2280 (22.8h @ $100/h, 30min dedup)
69
+ - 🤖 **LLM usage:** $7.5000 (122 commits)
70
+ - 👤 **Human dev:** ~$2341 (23.4h @ $100/h, 30min dedup)
71
71
 
72
72
  Generated on 2026-05-04 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
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-2.2.22-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-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-22.8h-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.23-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-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-23.4h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
24
24
 
25
- - 🤖 **LLM usage:** $7.5000 (121 commits)
26
- - 👤 **Human dev:** ~$2280 (22.8h @ $100/h, 30min dedup)
25
+ - 🤖 **LLM usage:** $7.5000 (122 commits)
26
+ - 👤 **Human dev:** ~$2341 (23.4h @ $100/h, 30min dedup)
27
27
 
28
28
  Generated on 2026-05-04 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
29
29
 
@@ -1,2 +1,2 @@
1
1
  """fixos – AI-powered Linux/Windows diagnostics and repair."""
2
- __version__ = "2.2.22"
2
+ __version__ = "2.2.23"
@@ -15,9 +15,16 @@ from ..utils.anonymizer import anonymize, display_anonymized_preview
15
15
  from ..utils.web_search import search_all, format_results_for_llm
16
16
  from ..config import FixOsConfig
17
17
  from ..utils.timeout import SessionTimeout
18
+ from ..constants import (
19
+ UI_BORDER_WIDTH,
20
+ MAX_OUTPUT_PREVIEW_LENGTH,
21
+ MAX_ANON_PREVIEW_LENGTH,
22
+ DEFAULT_COMMAND_TIMEOUT,
23
+ DEFAULT_TOKEN_LIMIT,
24
+ MAX_COMMAND_LENGTH,
25
+ MAX_SEARCH_QUERY_LENGTH,
26
+ )
18
27
 
19
- # UI formatting constants
20
- UI_BORDER_WIDTH = 65
21
28
 
22
29
 
23
30
  # Commands NEVER executed automatically
@@ -121,14 +128,14 @@ class AutonomousSession:
121
128
  self.start_time = time.time()
122
129
  self._setup_timeout()
123
130
 
124
- def _setup_timeout(self):
131
+ def _setup_timeout(self) -> None:
125
132
  """Setup session timeout handler."""
126
- def _timeout_handler(signum, frame):
133
+ def _timeout_handler(signum, frame) -> None:
127
134
  raise SessionTimeout()
128
135
  signal.signal(signal.SIGALRM, _timeout_handler)
129
136
  signal.alarm(self.config.session_timeout)
130
137
 
131
- def _clear_timeout(self):
138
+ def _clear_timeout(self) -> None:
132
139
  """Clear the timeout alarm."""
133
140
  signal.alarm(0)
134
141
 
@@ -148,7 +155,7 @@ class AutonomousSession:
148
155
  return False
149
156
  return True
150
157
 
151
- def _initialize_messages(self):
158
+ def _initialize_messages(self) -> None:
152
159
  """Initialize LLM message history with system prompt and diagnostics."""
153
160
  anon_str, anon_report = anonymize(str(self.diagnostics))
154
161
  if self.show_data:
@@ -170,7 +177,7 @@ class AutonomousSession:
170
177
  from . import get_remaining_time
171
178
  return get_remaining_time(self)
172
179
 
173
- def _check_timeout(self):
180
+ def _check_timeout(self) -> None:
174
181
  """Check if session has timed out."""
175
182
  if self._get_remaining_time() <= 0:
176
183
  raise SessionTimeout()
@@ -178,7 +185,7 @@ class AutonomousSession:
178
185
  def _query_llm(self) -> Optional[str]:
179
186
  """Query LLM and return reply."""
180
187
  try:
181
- return self.llm.chat(self.messages, max_tokens=1000, temperature=0.1)
188
+ return self.llm.chat(self.messages, max_tokens=DEFAULT_TOKEN_LIMIT, temperature=0.1)
182
189
  except LLMError as e:
183
190
  print(f" ❌ LLM błąd: {e}")
184
191
  return None
@@ -235,12 +242,12 @@ class AutonomousSession:
235
242
  """Execute command and return (success, output)."""
236
243
  try:
237
244
  proc = subprocess.run(
238
- cmd, shell=True, capture_output=True, text=True, timeout=90
245
+ cmd, shell=True, capture_output=True, text=True, timeout=DEFAULT_COMMAND_TIMEOUT
239
246
  )
240
247
  out = proc.stdout.strip() or proc.stderr.strip() or "(brak outputu)"
241
- return proc.returncode == 0, out[:1000]
248
+ return proc.returncode == 0, out[:MAX_OUTPUT_PREVIEW_LENGTH]
242
249
  except subprocess.TimeoutExpired:
243
- return False, "[TIMEOUT 90s]"
250
+ return False, f"[TIMEOUT {DEFAULT_COMMAND_TIMEOUT}s]"
244
251
  except Exception as e:
245
252
  return False, f"[WYJĄTEK: {e}]"
246
253
 
@@ -299,7 +306,7 @@ class AutonomousSession:
299
306
  self.fix_count += 1
300
307
 
301
308
  icon = "✅" if ok else "❌"
302
- print(f" {icon} Wynik: {out[:200]}")
309
+ print(f" {icon} Wynik: {out[:MAX_COMMAND_LENGTH]}")
303
310
 
304
311
  # Anonymize before sending to LLM
305
312
  anon_out, _ = anonymize(out)
@@ -310,13 +317,13 @@ class AutonomousSession:
310
317
  "content": (
311
318
  f"Wykonano: `{anon_cmd}`\n"
312
319
  f"Sukces: {ok}\n"
313
- f"Output: {anon_out[:500]}\n"
320
+ f"Output: {anon_out[:MAX_SEARCH_QUERY_LENGTH]}\n"
314
321
  f"Zweryfikuj wynik i zaproponuj następną akcję."
315
322
  ),
316
323
  })
317
324
  return True
318
325
 
319
- def _handle_skip(self, action_data: Dict[str, Any]):
326
+ def _handle_skip(self, action_data: Dict[str, Any]) -> None:
320
327
  """Handle SKIP action."""
321
328
  reason = action_data.get("reason", "")
322
329
  print(f" ⏭️ Pomijam: {reason}")
@@ -326,7 +333,7 @@ class AutonomousSession:
326
333
  })
327
334
  self.fix_count += 1
328
335
 
329
- def _handle_done(self):
336
+ def _handle_done(self) -> None:
330
337
  """Handle DONE action - session complete."""
331
338
  print("\n ✅ Agent zakończył – wszystkie problemy naprawione!")
332
339
 
@@ -408,7 +415,7 @@ class AutonomousSession:
408
415
  self._print_report()
409
416
  return self.report
410
417
 
411
- def _print_report(self):
418
+ def _print_report(self) -> None:
412
419
  """Print session report."""
413
420
  print(f"\n{'═' * UI_BORDER_WIDTH}")
414
421
  print(" 📊 RAPORT SESJI AUTONOMICZNEJ")
@@ -51,16 +51,16 @@ class HITLSession:
51
51
  self.start_ts = time.time()
52
52
  self._setup_timeout()
53
53
 
54
- def _setup_timeout(self):
54
+ def _setup_timeout(self) -> None:
55
55
  """Setup session timeout handler."""
56
56
  from . import session_io
57
- def _timeout(signum, frame):
57
+ def _timeout(signum, frame) -> None:
58
58
  raise SessionTimeout()
59
59
  # Store reference in session_io for reinstatement during user input
60
60
  session_io._setup_timeout_ref(self, self.config.session_timeout, _timeout)
61
61
  setup_signal_timeout(self.config.session_timeout, _timeout)
62
62
 
63
- def _clear_timeout(self):
63
+ def _clear_timeout(self) -> None:
64
64
  """Clear the timeout alarm."""
65
65
  cancel_signal_timeout()
66
66
 
@@ -93,7 +93,7 @@ class HITLSession:
93
93
  ]
94
94
  return True
95
95
 
96
- def _print_header(self):
96
+ def _print_header(self) -> None:
97
97
  """Print session header with system info."""
98
98
  io.print_session_header(
99
99
  self.os_info, self.pkg_manager,
@@ -191,7 +191,7 @@ class HITLSession:
191
191
 
192
192
  self._print_summary()
193
193
 
194
- def _print_summary(self):
194
+ def _print_summary(self) -> None:
195
195
  """Print session summary."""
196
196
  elapsed = int(time.time() - self.start_ts)
197
197
  io.print_session_summary(len(self.messages)-2, elapsed, self.llm.total_tokens, self.executed)
@@ -9,6 +9,7 @@ from typing import List, Tuple
9
9
 
10
10
  from ..constants import (
11
11
  MAX_SUMMARY_LENGTH,
12
+ MAX_TECH_TERMS,
12
13
  )
13
14
 
14
15
 
@@ -144,6 +145,6 @@ def extract_search_topic(llm_reply: str) -> str:
144
145
  llm_reply, re.IGNORECASE
145
146
  )
146
147
  if tech_terms:
147
- return " ".join(dict.fromkeys(tech_terms[:4]))
148
+ return " ".join(dict.fromkeys(tech_terms[:MAX_TECH_TERMS]))
148
149
  first_sentence = llm_reply.split(".")[0][:MAX_SUMMARY_LENGTH]
149
150
  return first_sentence or "linux system diagnostics"
@@ -11,6 +11,8 @@ from ..constants import (
11
11
  DEFAULT_COMMAND_TIMEOUT,
12
12
  FAST_COMMAND_TIMEOUT,
13
13
  LONG_COMMAND_TIMEOUT,
14
+ MAX_ANON_PREVIEW_LENGTH,
15
+ MAX_STDERR_PREVIEW_LENGTH,
14
16
  )
15
17
  from ..platform_utils import (
16
18
  is_dangerous, is_interactive_blocker, elevate_cmd, run_command,
@@ -101,7 +103,7 @@ def _sort_fixes_by_priority(fixes: list) -> list:
101
103
  r"\bflatpak\s+(update|install)\b",
102
104
  )
103
105
 
104
- def score(item):
106
+ def score(item) -> int:
105
107
  cmd = item[0].lower()
106
108
  if any(re.search(p, cmd) for p in cleanup_patterns):
107
109
  return 0
@@ -164,8 +166,8 @@ def handle_fix_by_number(
164
166
  "content": (
165
167
  f"Executed: `{cmd}`\n"
166
168
  f"Success: {result.ok}\n"
167
- f"Stdout:\n```\n{anon_out[:800]}\n```\n"
168
- f"Stderr:\n```\n{anon_err[:300]}\n```\n"
169
+ f"Stdout:\n```\n{anon_out[:MAX_ANON_PREVIEW_LENGTH]}\n```\n"
170
+ f"Stderr:\n```\n{anon_err[:MAX_STDERR_PREVIEW_LENGTH]}\n```\n"
169
171
  f"What next?"
170
172
  ),
171
173
  })
@@ -184,7 +186,7 @@ def handle_direct_command(
184
186
  cmd = user_in[1:].strip()
185
187
  result = run_cmd_fn(cmd, "Komenda użytkownika")
186
188
  executed.append(result)
187
- anon_out, _ = anonymize(result.stdout + "\n" + result.stderr)
189
+ anon_out, _ = anonymize(f"{result.stdout}\n{result.stderr}")
188
190
  messages.append({
189
191
  "role": "user",
190
192
  "content": f"User ran: `{cmd}`\nResult: {anon_out[:600]}\nWhat next?"
@@ -252,7 +254,7 @@ def run_single_command(cmd: str, comment: str) -> CmdResult:
252
254
  with io.suspend_timeout():
253
255
  ok, stdout, stderr, rc = run_command(cmd, timeout=timeout)
254
256
 
255
- io.console.print("\r" + " " * 30 + "\r", end="")
257
+ io.console.print(f"\r{' ' * 30}\r", end="")
256
258
  result = CmdResult(cmd=cmd, comment=comment, ok=ok,
257
259
  stdout=stdout, stderr=stderr, returncode=rc)
258
260
  io.print_cmd_result(result)
@@ -30,7 +30,7 @@ _session_ref = None
30
30
 
31
31
 
32
32
  @contextmanager
33
- def suspend_timeout():
33
+ def suspend_timeout() -> object:
34
34
  """Context manager to temporarily suspend session timeout during user input."""
35
35
  global _timeout_handler, _timeout_seconds, _session_ref
36
36
  try:
@@ -167,7 +167,7 @@ def print_thinking() -> None:
167
167
 
168
168
  def clear_thinking() -> None:
169
169
  """Clear the 'Analyzing...' indicator."""
170
- console.print("\r" + " " * 30 + "\r", end="")
170
+ console.print(f"\r{' ' * 30}\r", end="")
171
171
 
172
172
 
173
173
  def print_llm_reply(reply: str) -> None:
@@ -63,7 +63,7 @@ def config_show() -> None:
63
63
 
64
64
  @config.command("init")
65
65
  @click.option("--force", is_flag=True, help="Nadpisz istniejący plik")
66
- def config_init(force) -> None:
66
+ def config_init(force: bool) -> None:
67
67
  """Zainicjalizuj plik konfiguracyjny .env."""
68
68
  from pathlib import Path
69
69
 
@@ -95,7 +95,7 @@ GEMINI_API_KEY=
95
95
  @config.command("set")
96
96
  @click.argument("key")
97
97
  @click.argument("value")
98
- def config_set(key, value) -> None:
98
+ def config_set(key: str, value: str) -> None:
99
99
  """Ustaw wartość konfiguracyjną w .env."""
100
100
  from dotenv import set_key
101
101
 
@@ -6,7 +6,7 @@ Manage packages and system features based on user profiles.
6
6
  import json
7
7
  import click
8
8
  from pathlib import Path
9
- from typing import Optional
9
+ from typing import Optional, List, Dict
10
10
 
11
11
  from ..features import SystemDetector
12
12
  from ..features.catalog import PackageCatalog
@@ -50,7 +50,7 @@ def features_audit(profile: Optional[str], json_output: bool) -> None:
50
50
  FeatureRenderer.render_audit(result)
51
51
 
52
52
 
53
- def _show_install_plan(to_install: list, yes: bool, dry_run: bool) -> bool:
53
+ def _show_install_plan(to_install: List, yes: bool, dry_run: bool) -> bool:
54
54
  """Display install plan and ask for confirmation. Returns False to abort."""
55
55
  console.print()
56
56
  console.print(f"[bold]Zostaną zainstalowane {len(to_install)} pakiety:[/bold]")
@@ -66,7 +66,7 @@ def _show_install_plan(to_install: list, yes: bool, dry_run: bool) -> bool:
66
66
  return True
67
67
 
68
68
 
69
- def _show_install_results(install_result: dict) -> None:
69
+ def _show_install_results(install_result: Dict) -> None:
70
70
  """Display installation results summary."""
71
71
  console.print()
72
72
  if install_result["installed"]:
@@ -12,6 +12,11 @@ from fixos.cli.shared import add_common_options, add_shared_options, BANNER
12
12
  from fixos.config import FixOsConfig, interactive_provider_setup
13
13
  from fixos.agent.hitl import run_hitl_session
14
14
  from fixos.agent.autonomous import run_autonomous_session
15
+ from fixos.constants import (
16
+ DEFAULT_SESSION_TIMEOUT,
17
+ MAX_FIXES_DEFAULT,
18
+ MAX_SEARCH_QUERY_LENGTH,
19
+ )
15
20
 
16
21
 
17
22
  def _collect_diagnostics(modules: str, disc: bool, json_output: bool, output: str) -> dict:
@@ -22,7 +27,7 @@ def _collect_diagnostics(modules: str, disc: bool, json_output: bool, output: st
22
27
  data: dict = {}
23
28
  else:
24
29
  click.echo(click.style("\nZbieranie diagnostyki...", fg="yellow"))
25
- def progress(name, desc):
30
+ def progress(name, desc) -> None:
26
31
  click.echo(f" → {desc}...")
27
32
  from fixos.diagnostics import get_full_diagnostics
28
33
  data = get_full_diagnostics(selected_modules, progress_callback=progress)
@@ -67,14 +72,14 @@ def _run_agent_session(cfg, data: dict, max_fixes: int) -> None:
67
72
  @add_common_options
68
73
  @click.option("--mode", type=click.Choice(["hitl", "autonomous"]), default=None,
69
74
  help="Tryb: hitl (domyślny) lub autonomous")
70
- @click.option("--timeout", default=300, show_default=True,
75
+ @click.option("--timeout", default=DEFAULT_SESSION_TIMEOUT, show_default=True,
71
76
  help="Timeout sesji agenta (sekundy)")
72
77
  @click.option("--modules", "-M", default=None,
73
78
  help="Moduły diagnostyki: audio,thumbnails,hardware,system")
74
79
  @click.option("--no-show-data", is_flag=True, default=False,
75
80
  help="Nie pokazuj danych diagnostycznych (tylko podsumowanie)")
76
81
  @click.option("--output", "-o", default=None, help="Zapisz log sesji do JSON")
77
- @click.option("--max-fixes", default=10, show_default=True,
82
+ @click.option("--max-fixes", default=MAX_FIXES_DEFAULT, show_default=True,
78
83
  help="Maksymalna liczba napraw w sesji")
79
84
  @add_shared_options
80
85
  def fix(provider, token, model, no_banner, mode, timeout, modules, no_show_data, output, max_fixes,
@@ -276,7 +281,7 @@ def try_llm_fallback_for_failures(failed_actions, cfg) -> None:
276
281
 
277
282
  Zaproponuj alternatywne komendy lub podejście. Odpowiedz krótko, maksymalnie 3 komendy.
278
283
  """
279
- response = llm.chat([{"role": "user", "content": prompt}], max_tokens=500)
284
+ response = llm.chat([{"role": "user", "content": prompt}], max_tokens=MAX_SEARCH_QUERY_LENGTH)
280
285
  click.echo(click.style("Sugestie LLM:", fg="cyan"))
281
286
  click.echo(response)
282
287
 
@@ -7,7 +7,7 @@ import click
7
7
  @click.command("history")
8
8
  @click.option("--limit", default=20, help="Ile sesji pokazać")
9
9
  @click.option("--json", "json_output", is_flag=True, default=False, help="Wyjście JSON")
10
- def history(limit, json_output) -> None:
10
+ def history(limit: int, json_output: bool) -> None:
11
11
  """
12
12
  Historia napraw fixOS.
13
13
 
@@ -20,7 +20,7 @@ from fixos.config import FixOsConfig
20
20
  help="Maksymalna liczba iteracji")
21
21
  @click.option("--output", "-o", default=None,
22
22
  help="Zapisz log wykonania do pliku JSON")
23
- def orchestrate(provider, token, model, no_banner, mode, modules, dry_run, max_iterations, output) -> None:
23
+ def orchestrate(provider: str, token: str, model: str, no_banner: bool, mode: str, modules: str, dry_run: bool, max_iterations: int, output: str) -> None:
24
24
  """
25
25
  Zaawansowana orkiestracja napraw z grafem problemów.
26
26
 
@@ -38,7 +38,7 @@ def profile_list() -> None:
38
38
 
39
39
  @profile.command("show")
40
40
  @click.argument("name")
41
- def profile_show(name) -> None:
41
+ def profile_show(name: str) -> None:
42
42
  """Pokaż szczegóły profilu diagnostycznego."""
43
43
  from fixos.profiles import Profile
44
44
  import yaml
@@ -106,7 +106,7 @@ PROVIDERS_INFO = {
106
106
 
107
107
  @click.command("llm")
108
108
  @click.option("--free", is_flag=True, help="Tylko darmowe providery")
109
- def llm_providers(free) -> None:
109
+ def llm_providers(free: bool) -> None:
110
110
  """
111
111
  Lista dostępnych providerów LLM.
112
112
 
@@ -189,7 +189,7 @@ def providers() -> None:
189
189
  @click.option("--token", "-t", default=None, envvar="API_KEY", help="Token API")
190
190
  @click.option("--model", "-m", default=None, help="Model")
191
191
  @click.option("--no-banner", is_flag=True, help="Ukryj baner")
192
- def test_llm(provider, token, model, no_banner) -> None:
192
+ def test_llm(provider: str, token: str, model: str, no_banner: bool) -> None:
193
193
  """
194
194
  Test połączenia z LLM.
195
195
 
@@ -16,7 +16,7 @@ from fixos.cli.shared import add_shared_options, BANNER
16
16
  @click.option("--no-banner", "no_banner", is_flag=True, default=False, help="Ukryj baner fixos")
17
17
  @click.option("--output", "-o", default=None, help="Zapisz wyniki do pliku")
18
18
  @click.option("--profile", "-p", default=None, help="Profil diagnostyczny (server/desktop/developer/minimal)")
19
- def scan(modules, output, show_raw, no_banner, disc, dry_run, interactive, json_output, llm_fallback, profile) -> None:
19
+ def scan(modules: str, output: str, show_raw: bool, no_banner: bool, disc: bool, dry_run: bool, interactive: bool, json_output: bool, llm_fallback: bool, profile: str) -> None:
20
20
  """
21
21
  Przeprowadza diagnostykę systemu.
22
22
 
@@ -60,7 +60,7 @@ def scan(modules, output, show_raw, no_banner, disc, dry_run, interactive, json_
60
60
  data = {}
61
61
  else:
62
62
  click.echo(click.style("Zbieranie diagnostyki...", fg="yellow"))
63
- def progress(name, desc):
63
+ def progress(name, desc) -> None:
64
64
  click.echo(f" → {desc}...")
65
65
  data = get_full_diagnostics(selected_modules, progress_callback=progress)
66
66
 
@@ -15,9 +15,15 @@ FAST_COMMAND_TIMEOUT = 60 # Read-only and quick diagnostic commands
15
15
  MAX_COMMAND_LENGTH = 200 # Maximum length for command display
16
16
  MAX_SEARCH_QUERY_LENGTH = 500 # Maximum length for search query
17
17
  MAX_OUTPUT_LINES = 40 # Maximum output lines to display
18
+ MAX_OUTPUT_PREVIEW_LENGTH = 1000 # Maximum length for output preview
19
+ MAX_ANON_PREVIEW_LENGTH = 800 # Maximum length for anonymized preview
20
+ MAX_STDERR_PREVIEW_LENGTH = 300 # Maximum length for stderr preview
21
+ MAX_TECH_TERMS = 4 # Maximum tech terms to extract for search topic
18
22
  HOSTNAME_DISPLAY_LENGTH = 65 # Length for hostname display
19
23
  CONFIG_DISPLAY_LENGTH = 40 # Length for config line display
20
24
  PROFILE_DISPLAY_LENGTH = 55 # Length for profile display
25
+ DIVIDER_LENGTH = 60 # Default divider length
26
+ UI_BORDER_WIDTH = 65 # Border width for panels
21
27
 
22
28
  # Token/API limits
23
29
  DEFAULT_TOKEN_LIMIT = 2000 # Default token estimate
@@ -25,7 +31,22 @@ MAX_WEB_SEARCH_COUNT = 5 # Maximum web searches per session
25
31
 
26
32
  # Service/process limits
27
33
  DEFAULT_HISTORY_LIMIT = 20 # Default history items to show
34
+ MAX_FIXES_DEFAULT = 10 # Default maximum number of fixes per session
35
+ SERVICE_SCAN_THRESHOLD_MB = 500 # Default threshold for service data scan
28
36
 
29
37
  # Text formatting
30
38
  COMMAND_PREFIX_LENGTH = 80 # Max length for command prefix in output
31
39
  MAX_SUMMARY_LENGTH = 200 # Max summary chars for derived search topic
40
+
41
+ # Disk / Resource thresholds
42
+ DISK_USAGE_CRITICAL = 95
43
+ DISK_USAGE_WARNING = 85
44
+ DISK_USAGE_MODERATE = 70
45
+ MAX_LARGE_FILES_DEFAULT = 20
46
+ MAX_CACHE_DIRS_DEFAULT = 15
47
+ MAX_LOG_DIRS_DEFAULT = 10
48
+ MAX_TEMP_DIRS_DEFAULT = 10
49
+ MIN_FILE_SIZE_MB = 100
50
+ LARGE_FILE_SIZE_MB = 500
51
+ CACHE_SIZE_HIGH_MB = 500
52
+ CACHE_SIZE_MEDIUM_MB = 100
@@ -9,21 +9,20 @@ import json
9
9
  from pathlib import Path
10
10
  from typing import Dict, List, Any
11
11
  from datetime import datetime
12
+ from ..constants import (
13
+ DISK_USAGE_CRITICAL,
14
+ DISK_USAGE_WARNING,
15
+ DISK_USAGE_MODERATE,
16
+ MAX_LARGE_FILES_DEFAULT,
17
+ MAX_CACHE_DIRS_DEFAULT,
18
+ MAX_LOG_DIRS_DEFAULT,
19
+ MAX_TEMP_DIRS_DEFAULT,
20
+ MIN_FILE_SIZE_MB,
21
+ LARGE_FILE_SIZE_MB,
22
+ CACHE_SIZE_HIGH_MB,
23
+ CACHE_SIZE_MEDIUM_MB,
24
+ )
12
25
 
13
- # Disk usage thresholds
14
- DISK_USAGE_CRITICAL = 95
15
- DISK_USAGE_WARNING = 85
16
- DISK_USAGE_MODERATE = 70
17
-
18
- # Analysis limits
19
- MAX_LARGE_FILES_DEFAULT = 20
20
- MAX_CACHE_DIRS_DEFAULT = 15
21
- MAX_LOG_DIRS_DEFAULT = 10
22
- MAX_TEMP_DIRS_DEFAULT = 10
23
- MIN_FILE_SIZE_MB = 100
24
- LARGE_FILE_SIZE_MB = 500
25
- CACHE_SIZE_HIGH_MB = 500
26
- CACHE_SIZE_MEDIUM_MB = 100
27
26
 
28
27
 
29
28
  class DiskAnalyzer:
@@ -16,6 +16,7 @@ from enum import Enum
16
16
 
17
17
  from .service_details import ServiceDetailsProvider
18
18
  from .service_cleanup import ServiceCleaner
19
+ from ..constants import SERVICE_SCAN_THRESHOLD_MB
19
20
 
20
21
 
21
22
  class ServiceType(Enum):
@@ -92,7 +93,7 @@ class ServiceDataInfo:
92
93
  class ServiceDataScanner:
93
94
  """Scans for large service data directories and allows cleanup."""
94
95
 
95
- DEFAULT_THRESHOLD_MB = 500
96
+ DEFAULT_THRESHOLD_MB = SERVICE_SCAN_THRESHOLD_MB
96
97
 
97
98
  SERVICE_PATHS = {
98
99
  ServiceType.DOCKER: ["/var/lib/docker", "~/.docker"],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fixos
3
- Version: 2.2.22
3
+ Version: 2.2.23
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
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-2.2.22-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-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-22.8h-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.23-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-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-23.4h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
68
68
 
69
- - 🤖 **LLM usage:** $7.5000 (121 commits)
70
- - 👤 **Human dev:** ~$2280 (22.8h @ $100/h, 30min dedup)
69
+ - 🤖 **LLM usage:** $7.5000 (122 commits)
70
+ - 👤 **Human dev:** ~$2341 (23.4h @ $100/h, 30min dedup)
71
71
 
72
72
  Generated on 2026-05-04 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
73
73
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "fixos"
7
- version = "2.2.22"
7
+ version = "2.2.23"
8
8
  description = "AI-powered Linux/Windows diagnostics and repair – audio, hardware, system issues"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -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.21",
8
+ version="2.2.22",
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",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes