fixos 2.2.8__tar.gz → 2.2.10__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.8 → fixos-2.2.10}/CHANGELOG.md +19 -0
- {fixos-2.2.8 → fixos-2.2.10}/PKG-INFO +1 -1
- {fixos-2.2.8 → fixos-2.2.10}/fixos/__init__.py +1 -1
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/cleanup_cmd.py +84 -71
- {fixos-2.2.8 → fixos-2.2.10}/fixos/config.py +10 -4
- {fixos-2.2.8 → fixos-2.2.10}/fixos/diagnostics/flatpak_analyzer.py +45 -33
- {fixos-2.2.8 → fixos-2.2.10}/fixos/diagnostics/storage_analyzer.py +73 -64
- {fixos-2.2.8 → fixos-2.2.10}/fixos.egg-info/PKG-INFO +1 -1
- {fixos-2.2.8 → fixos-2.2.10}/fixos.egg-info/SOURCES.txt +0 -1
- {fixos-2.2.8 → fixos-2.2.10}/fixos.egg-info/top_level.txt +0 -2
- {fixos-2.2.8 → fixos-2.2.10}/pyproject.toml +1 -1
- fixos-2.2.8/No changes needed for /home/tom/github/wronai/fixOS/agent/__init__.py +0 -8
- {fixos-2.2.8 → fixos-2.2.10}/.env.example +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/LICENSE +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/MANIFEST.in +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/README.md +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/README.md +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/TEST_RESULTS.md +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/TEST_RESULTS_V2.md +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/alpine/Dockerfile +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/arch/Dockerfile +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/base/Dockerfile +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/broken-audio/Dockerfile +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/broken-full/Dockerfile +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/broken-network/Dockerfile +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/broken-thumbnails/Dockerfile +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/debian/Dockerfile +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/docker-compose.multi-system.yml +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/docker-compose.yml +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/fedora/Dockerfile +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/test-multi-system.sh +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docker/ubuntu/Dockerfile +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docs/examples/advanced_usage.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/docs/examples/quickstart.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/agent/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/agent/autonomous.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/agent/autonomous_session.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/agent/hitl.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/agent/hitl_session.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/anonymizer.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/ask_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/config_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/features_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/fix_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/history_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/main.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/orchestrate_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/profile_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/provider_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/quickfix_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/report_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/rollback_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/scan_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/shared.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/token_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli/watch_cmd.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/cli.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/diagnostics/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/diagnostics/dev_project_analyzer.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/diagnostics/disk_analyzer.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/diagnostics/service_cleanup.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/diagnostics/service_details.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/diagnostics/service_scanner.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/diagnostics/system_checks.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/features/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/features/auditor.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/features/catalog.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/features/installer.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/features/profiles.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/features/renderer.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/fixes/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/interactive/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/interactive/cleanup_planner.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/llm_shell.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/orchestrator/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/orchestrator/executor.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/orchestrator/graph.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/orchestrator/orchestrator.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/orchestrator/rollback.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/platform_utils.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/plugins/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/plugins/base.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/plugins/builtin/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/plugins/builtin/audio.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/plugins/builtin/disk.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/plugins/builtin/hardware.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/plugins/builtin/resources.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/plugins/builtin/security.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/plugins/builtin/thumbnails.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/plugins/registry.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/profiles/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/providers/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/providers/llm.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/providers/llm_analyzer.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/providers/schemas.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/system_checks.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/utils/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/utils/anonymizer.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/utils/terminal.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/utils/timeout.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/utils/web_search.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos/watch.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos.egg-info/dependency_links.txt +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos.egg-info/entry_points.txt +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/fixos.egg-info/requires.txt +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/pytest.ini +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/requirements-dev.txt +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/requirements.txt +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/scripts/pyqual-calibrate.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/setup.cfg +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/setup.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/conftest.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/e2e/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/e2e/test_anonymization_layers.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/e2e/test_audio_broken.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/e2e/test_cli.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/e2e/test_executor.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/e2e/test_multi_system.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/e2e/test_network_broken.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/e2e/test_thumbnails_broken.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/test_fixos.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/unit/__init__.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/unit/test_anonymizer.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/unit/test_core.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/unit/test_executor.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/unit/test_orchestrator.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/unit/test_service_cleanup.py +0 -0
- {fixos-2.2.8 → fixos-2.2.10}/tests/unit/test_service_scanner.py +0 -0
|
@@ -150,6 +150,25 @@ 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.10] - 2026-04-09
|
|
154
|
+
|
|
155
|
+
### Other
|
|
156
|
+
- Update No changes needed for /home/tom/github/wronai/fixOS/agent/__init__.py
|
|
157
|
+
- Update fixos/cli/cleanup_cmd.py
|
|
158
|
+
- Update fixos/config.py
|
|
159
|
+
- Update fixos/diagnostics/flatpak_analyzer.py
|
|
160
|
+
- Update fixos/diagnostics/storage_analyzer.py
|
|
161
|
+
|
|
162
|
+
## [2.2.9] - 2026-04-04
|
|
163
|
+
|
|
164
|
+
### Docs
|
|
165
|
+
- Update .pyqual/report.md
|
|
166
|
+
|
|
167
|
+
### Other
|
|
168
|
+
- Update .pyqual/pipeline.db
|
|
169
|
+
- Update VERSION
|
|
170
|
+
- Update fixos/__init__.py
|
|
171
|
+
|
|
153
172
|
## [2.2.7] - 2026-04-04
|
|
154
173
|
|
|
155
174
|
### Docs
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""fixos – AI-powered Linux/Windows diagnostics and repair."""
|
|
2
|
-
__version__ = "2.2.
|
|
2
|
+
__version__ = "2.2.10"
|
|
@@ -3,13 +3,26 @@ Cleanup command for fixOS CLI - service data cleanup with detailed flatpak suppo
|
|
|
3
3
|
"""
|
|
4
4
|
import click
|
|
5
5
|
import subprocess
|
|
6
|
-
from fixos.cli.shared import BANNER
|
|
7
6
|
from fixos.diagnostics.service_scanner import ServiceDataScanner
|
|
8
|
-
|
|
7
|
+
|
|
8
|
+
CONSTANT_3 = 3
|
|
9
|
+
CONSTANT_4 = 4
|
|
10
|
+
CONSTANT_5 = 5
|
|
11
|
+
CONSTANT_7 = 7
|
|
12
|
+
CONSTANT_9 = 9
|
|
13
|
+
CONSTANT_20 = 20
|
|
14
|
+
CONSTANT_30 = 30
|
|
15
|
+
CONSTANT_50 = 50
|
|
16
|
+
CONSTANT_60 = 60
|
|
17
|
+
CONSTANT_90 = 90
|
|
18
|
+
CONSTANT_120 = 120
|
|
19
|
+
CONSTANT_300 = 300
|
|
20
|
+
CONSTANT_500 = 500
|
|
21
|
+
CONSTANT_1024 = 1024
|
|
9
22
|
|
|
10
23
|
|
|
11
24
|
@click.command("cleanup")
|
|
12
|
-
@click.option("--threshold", "-t", default=
|
|
25
|
+
@click.option("--threshold", "-t", default=CONSTANT_500, type=int,
|
|
13
26
|
help="Próg wielkości w MB (domyślnie 500MB)")
|
|
14
27
|
@click.option("--services", "-s", default=None,
|
|
15
28
|
help="Usługi do przeskanowania: docker,ollama,npm,pip,... (domyślnie wszystkie)")
|
|
@@ -97,7 +110,7 @@ def cleanup_services(threshold, services, json_output, cleanup, dry_run, list_on
|
|
|
97
110
|
def _display_cleanup_summary(plan: dict, threshold: int) -> None:
|
|
98
111
|
"""Display cleanup plan summary header."""
|
|
99
112
|
click.echo(click.style(f"\nSkanowanie usług (próg: {threshold} MB)...", fg="cyan"))
|
|
100
|
-
click.echo(click.style("═" *
|
|
113
|
+
click.echo(click.style("═" * CONSTANT_60, fg="cyan"))
|
|
101
114
|
|
|
102
115
|
if plan["services_found"] == 0:
|
|
103
116
|
click.echo(click.style("\nNie znaleziono usług powyżej progu.", fg="green"))
|
|
@@ -128,7 +141,7 @@ def _display_service_item(svc: dict) -> None:
|
|
|
128
141
|
elif svc["service_type"] == "ollama" and svc["details"].get("models"):
|
|
129
142
|
models = svc["details"]["models"]
|
|
130
143
|
if models:
|
|
131
|
-
click.echo(f" Modele: {', '.join(models[:
|
|
144
|
+
click.echo(f" Modele: {', '.join(models[:CONSTANT_3])}{'...' if len(models) > CONSTANT_3 else ''}")
|
|
132
145
|
click.echo()
|
|
133
146
|
|
|
134
147
|
|
|
@@ -274,9 +287,9 @@ def _cleanup_flatpak_detailed(scanner, json_output: bool, dry_run: bool):
|
|
|
274
287
|
return
|
|
275
288
|
|
|
276
289
|
# Wyświetl menu z opcjami
|
|
277
|
-
click.echo("\n" + click.style("="*
|
|
290
|
+
click.echo("\n" + click.style("="*CONSTANT_60, fg="cyan"))
|
|
278
291
|
click.echo(click.style("📋 WYBIERZ OPCJE DO WYKONANIA", fg="cyan", bold=True))
|
|
279
|
-
click.echo(click.style("="*
|
|
292
|
+
click.echo(click.style("="*CONSTANT_60, fg="cyan"))
|
|
280
293
|
|
|
281
294
|
if dry_run:
|
|
282
295
|
click.echo(click.style("\n[TRYB DRY-RUN] - brak faktycznych zmian\n", fg="yellow"))
|
|
@@ -302,9 +315,9 @@ def _cleanup_flatpak_detailed(scanner, json_output: bool, dry_run: bool):
|
|
|
302
315
|
click.echo(f" {click.style(f'Elementów: {len(rec["items"])}', fg='white', dim=True)}")
|
|
303
316
|
|
|
304
317
|
# Podsumowanie potencjalnych korzyści
|
|
305
|
-
click.echo("\n" + click.style("-"*
|
|
318
|
+
click.echo("\n" + click.style("-"*CONSTANT_60, fg="cyan"))
|
|
306
319
|
click.echo(f"💰 {click.style('ŁĄCZNA POTENCJALNA KORZYŚĆ:', fg='green', bold=True)} ~{_format_bytes(total_potential_savings)}")
|
|
307
|
-
click.echo(click.style("-"*
|
|
320
|
+
click.echo(click.style("-"*CONSTANT_60, fg="cyan"))
|
|
308
321
|
|
|
309
322
|
# Menu wyboru
|
|
310
323
|
click.echo(f"\n{click.style('Dostępne opcje:', fg='white', bold=True)}")
|
|
@@ -346,9 +359,9 @@ def _cleanup_flatpak_detailed(scanner, json_output: bool, dry_run: bool):
|
|
|
346
359
|
"space_reclaimed": 0,
|
|
347
360
|
}
|
|
348
361
|
|
|
349
|
-
click.echo("\n" + click.style("="*
|
|
362
|
+
click.echo("\n" + click.style("="*CONSTANT_60, fg="cyan"))
|
|
350
363
|
click.echo(click.style("🚀 WYKONYWANIE WYBRANYCH AKCJI", fg="cyan", bold=True))
|
|
351
|
-
click.echo(click.style("="*
|
|
364
|
+
click.echo(click.style("="*CONSTANT_60, fg="cyan") + "\n")
|
|
352
365
|
|
|
353
366
|
for idx in selected_indices:
|
|
354
367
|
rec = recommendations[idx]
|
|
@@ -378,27 +391,27 @@ def _cleanup_flatpak_detailed(scanner, json_output: bool, dry_run: bool):
|
|
|
378
391
|
click.echo(click.style(f" ❌ Błąd: {result.get('error', 'Unknown error')}", fg="red"))
|
|
379
392
|
|
|
380
393
|
# Podsumowanie końcowe
|
|
381
|
-
click.echo("\n" + click.style("="*
|
|
394
|
+
click.echo("\n" + click.style("="*CONSTANT_60, fg="cyan"))
|
|
382
395
|
click.echo(click.style("📊 PODSUMOWANIE", fg="cyan", bold=True))
|
|
383
|
-
click.echo(click.style("="*
|
|
396
|
+
click.echo(click.style("="*CONSTANT_60, fg="cyan"))
|
|
384
397
|
click.echo(f" ✅ Wykonano: {len(results['executed'])}")
|
|
385
398
|
click.echo(f" ⏭️ Pominięto: {len(results['skipped'])}")
|
|
386
399
|
click.echo(f" ❌ Błędy: {len(results['failed'])}")
|
|
387
400
|
|
|
388
|
-
freed_gb = results['space_reclaimed'] / (
|
|
401
|
+
freed_gb = results['space_reclaimed'] / (CONSTANT_1024**CONSTANT_3)
|
|
389
402
|
if dry_run:
|
|
390
403
|
click.echo(click.style(f"\n 💰 [DRY-RUN] Zwolniono by: {freed_gb:.2f} GB", fg="cyan"))
|
|
391
404
|
else:
|
|
392
405
|
click.echo(click.style(f"\n 💰 Odzyskano: {freed_gb:.2f} GB", fg="green"))
|
|
393
406
|
|
|
394
|
-
click.echo(click.style("="*
|
|
407
|
+
click.echo(click.style("="*CONSTANT_60 + "\n", fg="cyan"))
|
|
395
408
|
|
|
396
409
|
|
|
397
410
|
def _display_flatpak_status(analysis: dict) -> None:
|
|
398
411
|
"""Wyświetl status Flatpak z rzeczywistymi danymi"""
|
|
399
|
-
click.echo("\n" + click.style("="*
|
|
412
|
+
click.echo("\n" + click.style("="*CONSTANT_60, fg="cyan"))
|
|
400
413
|
click.echo(click.style("📊 STATUS FLATPAK", fg="cyan", bold=True))
|
|
401
|
-
click.echo(click.style("="*
|
|
414
|
+
click.echo(click.style("="*CONSTANT_60, fg="cyan"))
|
|
402
415
|
|
|
403
416
|
# Aplikacje
|
|
404
417
|
apps_count = len(analysis.get('installed_apps', []))
|
|
@@ -424,7 +437,7 @@ def _display_flatpak_status(analysis: dict) -> None:
|
|
|
424
437
|
if duplicates:
|
|
425
438
|
dup_size = sum(d.get('total_size', 0) for d in duplicates)
|
|
426
439
|
click.echo(f"\n🔄 Duplikaty aplikacji: {click.style(str(len(duplicates)), fg='yellow')} ({_format_bytes(dup_size)})")
|
|
427
|
-
for dup in duplicates[:
|
|
440
|
+
for dup in duplicates[:CONSTANT_3]:
|
|
428
441
|
click.echo(f" • {dup.get('name', '?')} ({dup.get('count', 0)} wersje)")
|
|
429
442
|
|
|
430
443
|
# Nieużywane runtime'y
|
|
@@ -442,13 +455,13 @@ def _display_flatpak_status(analysis: dict) -> None:
|
|
|
442
455
|
|
|
443
456
|
def _display_detailed_recommendations(recommendations: list) -> None:
|
|
444
457
|
"""Wyświetl szczegółowe informacje o każdej rekomendacji"""
|
|
445
|
-
click.echo("\n" + click.style("="*
|
|
458
|
+
click.echo("\n" + click.style("="*CONSTANT_60, fg="cyan"))
|
|
446
459
|
click.echo(click.style("📖 SZCZEGÓŁY REKOMENDACJI", fg="cyan", bold=True))
|
|
447
|
-
click.echo(click.style("="*
|
|
460
|
+
click.echo(click.style("="*CONSTANT_60, fg="cyan"))
|
|
448
461
|
|
|
449
462
|
for i, rec in enumerate(recommendations, 1):
|
|
450
463
|
click.echo(f"\n{click.style(f'[{i}]', fg='cyan', bold=True)} {rec['description']}")
|
|
451
|
-
click.echo(click.style("-"*
|
|
464
|
+
click.echo(click.style("-"*CONSTANT_50, fg="white", dim=True))
|
|
452
465
|
click.echo(f"\n{rec['explanation']}")
|
|
453
466
|
|
|
454
467
|
if rec.get('items'):
|
|
@@ -495,10 +508,10 @@ def _parse_size_to_bytes(size_str: str) -> int:
|
|
|
495
508
|
size_str = size_str.strip().upper().replace(' ', '')
|
|
496
509
|
multipliers = {
|
|
497
510
|
'B': 1,
|
|
498
|
-
'KB':
|
|
499
|
-
'MB':
|
|
500
|
-
'GB':
|
|
501
|
-
'TB':
|
|
511
|
+
'KB': CONSTANT_1024,
|
|
512
|
+
'MB': CONSTANT_1024**2,
|
|
513
|
+
'GB': CONSTANT_1024**CONSTANT_3,
|
|
514
|
+
'TB': CONSTANT_1024**CONSTANT_4,
|
|
502
515
|
}
|
|
503
516
|
|
|
504
517
|
for suffix, mult in sorted(multipliers.items(), key=lambda x: -len(x[0])):
|
|
@@ -517,9 +530,9 @@ def _parse_size_to_bytes(size_str: str) -> int:
|
|
|
517
530
|
def _format_bytes(size_bytes: int) -> str:
|
|
518
531
|
"""Format bytes to human-readable string"""
|
|
519
532
|
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
|
|
520
|
-
if size_bytes <
|
|
533
|
+
if size_bytes < CONSTANT_1024:
|
|
521
534
|
return f"{size_bytes:.1f} {unit}"
|
|
522
|
-
size_bytes /=
|
|
535
|
+
size_bytes /= CONSTANT_1024
|
|
523
536
|
return f"{size_bytes:.1f} PB"
|
|
524
537
|
|
|
525
538
|
|
|
@@ -549,9 +562,9 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
549
562
|
return
|
|
550
563
|
|
|
551
564
|
# Show recommendations
|
|
552
|
-
click.echo("\n" + click.style("="*
|
|
565
|
+
click.echo("\n" + click.style("="*CONSTANT_60, fg="cyan"))
|
|
553
566
|
click.echo(click.style("📋 REKOMENDACJE", fg="cyan", bold=True))
|
|
554
|
-
click.echo(click.style("="*
|
|
567
|
+
click.echo(click.style("="*CONSTANT_60, fg="cyan"))
|
|
555
568
|
|
|
556
569
|
if dry_run:
|
|
557
570
|
click.echo(click.style("\n[TRYB DRY-RUN] - brak faktycznych zmian\n", fg="yellow"))
|
|
@@ -573,15 +586,15 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
573
586
|
if medium_items:
|
|
574
587
|
total_medium = sum(item.size_bytes for item in medium_items)
|
|
575
588
|
click.echo(f"\n{click.style('🟡 WYMAGA POTWIERDZENIA:', fg='yellow', bold=True)}")
|
|
576
|
-
for item in medium_items[:
|
|
589
|
+
for item in medium_items[:CONSTANT_5]:
|
|
577
590
|
click.echo(f" • {item.name}: {_format_bytes(item.size_bytes)}")
|
|
578
591
|
click.echo(f" → {click.style(item.cleanup_command, fg='cyan', dim=True)}")
|
|
579
592
|
click.echo(f"\n 💰 Łącznie: {click.style(_format_bytes(total_medium), fg='yellow')}")
|
|
580
593
|
|
|
581
594
|
# Menu
|
|
582
|
-
click.echo("\n" + click.style("-"*
|
|
595
|
+
click.echo("\n" + click.style("-"*CONSTANT_60, fg="cyan"))
|
|
583
596
|
click.echo(f"💰 {click.style('ŁĄCZNIE DO ODZYSKANIA:', fg='green', bold=True)} {analysis['total_reclaimable_human']}")
|
|
584
|
-
click.echo(click.style("-"*
|
|
597
|
+
click.echo(click.style("-"*CONSTANT_60, fg="cyan"))
|
|
585
598
|
|
|
586
599
|
# Show category breakdown for dev_projects
|
|
587
600
|
dev_items = [item for item in analyzer.items if item.category == 'dev_projects']
|
|
@@ -639,10 +652,10 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
639
652
|
count = len(data["items"])
|
|
640
653
|
total = data["total"]
|
|
641
654
|
click.echo(f"\n{click.style(dep_type, fg='yellow', bold=True)}: {count} folderów, {_format_bytes(total)}")
|
|
642
|
-
for item in data["items"][:
|
|
655
|
+
for item in data["items"][:CONSTANT_5]:
|
|
643
656
|
click.echo(f" • {item.path}: {_format_bytes(item.size_bytes)}")
|
|
644
|
-
if count >
|
|
645
|
-
click.echo(f" ... i {count -
|
|
657
|
+
if count > CONSTANT_5:
|
|
658
|
+
click.echo(f" ... i {count - CONSTANT_5} więcej")
|
|
646
659
|
return
|
|
647
660
|
|
|
648
661
|
# Snap package management
|
|
@@ -660,7 +673,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
660
673
|
snap_packages = []
|
|
661
674
|
for line in lines:
|
|
662
675
|
parts = line.split()
|
|
663
|
-
if len(parts) >=
|
|
676
|
+
if len(parts) >= CONSTANT_4:
|
|
664
677
|
snap_packages.append({
|
|
665
678
|
'name': parts[0],
|
|
666
679
|
'version': parts[1],
|
|
@@ -759,7 +772,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
759
772
|
['sudo', 'snap', 'remove', pkg['name']],
|
|
760
773
|
capture_output=True,
|
|
761
774
|
text=True,
|
|
762
|
-
timeout=
|
|
775
|
+
timeout=CONSTANT_120,
|
|
763
776
|
)
|
|
764
777
|
if result.returncode == 0:
|
|
765
778
|
click.echo(click.style(" ✅ Odinstalowano", fg="green"))
|
|
@@ -786,21 +799,21 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
786
799
|
# Show large files
|
|
787
800
|
if large_files:
|
|
788
801
|
click.echo(f"\n{click.style('📄 DUŻE PLIKI (>200MB):', fg='red', bold=True)}")
|
|
789
|
-
for i, f in enumerate(large_files[:
|
|
802
|
+
for i, f in enumerate(large_files[:CONSTANT_30], 1):
|
|
790
803
|
click.echo(f" [{i:3d}] 📄 {click.style(f['path'], fg='cyan')}: {f['size_human']}")
|
|
791
804
|
|
|
792
|
-
if len(large_files) >
|
|
793
|
-
click.echo(f" ... i {len(large_files) -
|
|
805
|
+
if len(large_files) > CONSTANT_30:
|
|
806
|
+
click.echo(f" ... i {len(large_files) - CONSTANT_30} więcej")
|
|
794
807
|
|
|
795
808
|
# Show large directories
|
|
796
809
|
if large_dirs:
|
|
797
810
|
click.echo(f"\n{click.style('📁 DUŻE FOLDERY (>500MB):', fg='magenta', bold=True)}")
|
|
798
811
|
offset = len(large_files)
|
|
799
|
-
for i, d in enumerate(large_dirs[:
|
|
812
|
+
for i, d in enumerate(large_dirs[:CONSTANT_20], 1):
|
|
800
813
|
click.echo(f" [{offset + i:3d}] 📁 {click.style(d['path'], fg='yellow')}: {d['size_human']}")
|
|
801
814
|
|
|
802
|
-
if len(large_dirs) >
|
|
803
|
-
click.echo(f" ... i {len(large_dirs) -
|
|
815
|
+
if len(large_dirs) > CONSTANT_20:
|
|
816
|
+
click.echo(f" ... i {len(large_dirs) - CONSTANT_20} więcej")
|
|
804
817
|
|
|
805
818
|
# Get selection
|
|
806
819
|
total_items = len(large_files) + len(large_dirs)
|
|
@@ -818,7 +831,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
818
831
|
# Handle info:N
|
|
819
832
|
if nums.startswith('info:'):
|
|
820
833
|
try:
|
|
821
|
-
idx = int(nums[
|
|
834
|
+
idx = int(nums[CONSTANT_5:])
|
|
822
835
|
if 1 <= idx <= len(large_files):
|
|
823
836
|
f = large_files[idx - 1]
|
|
824
837
|
click.echo(f"\n{click.style('📦 SZCZEGÓŁY PLIKU:', fg='yellow', bold=True)}")
|
|
@@ -920,12 +933,12 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
920
933
|
click.echo(f" {click.style('filter:TYPE', fg='magenta')} - filtruj po typie (np. filter:venv)")
|
|
921
934
|
|
|
922
935
|
# Show numbered list
|
|
923
|
-
for i, item in enumerate(analyzer.items[:
|
|
936
|
+
for i, item in enumerate(analyzer.items[:CONSTANT_50], 1):
|
|
924
937
|
risk_icon = {"none": "✅", "low": "🟢", "medium": "🟡", "high": "🔴"}.get(item.risk, "•")
|
|
925
938
|
click.echo(f" [{i:3d}] {risk_icon} {item.name}: {_format_bytes(item.size_bytes)}")
|
|
926
939
|
|
|
927
|
-
if len(analyzer.items) >
|
|
928
|
-
click.echo(f" ... i {len(analyzer.items) -
|
|
940
|
+
if len(analyzer.items) > CONSTANT_50:
|
|
941
|
+
click.echo(f" ... i {len(analyzer.items) - CONSTANT_50} więcej (użyj filter:TYPE lub top:N)")
|
|
929
942
|
|
|
930
943
|
# Interactive loop for selection
|
|
931
944
|
items_to_clean = []
|
|
@@ -942,7 +955,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
942
955
|
# Handle info:N
|
|
943
956
|
if nums.startswith('info:'):
|
|
944
957
|
try:
|
|
945
|
-
idx = int(nums[
|
|
958
|
+
idx = int(nums[CONSTANT_5:])
|
|
946
959
|
if 1 <= idx <= len(analyzer.items):
|
|
947
960
|
item = analyzer.items[idx - 1]
|
|
948
961
|
click.echo(f"\n{click.style('📦 SZCZEGÓŁY ELEMENTU:', fg='yellow', bold=True)}")
|
|
@@ -962,7 +975,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
962
975
|
# Handle path:N
|
|
963
976
|
if nums.startswith('path:'):
|
|
964
977
|
try:
|
|
965
|
-
idx = int(nums[
|
|
978
|
+
idx = int(nums[CONSTANT_5:])
|
|
966
979
|
if 1 <= idx <= len(analyzer.items):
|
|
967
980
|
item = analyzer.items[idx - 1]
|
|
968
981
|
click.echo(f"\n{click.style('📁 ŚCIEŻKA:', fg='yellow')}")
|
|
@@ -982,7 +995,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
982
995
|
# Handle cmd:N
|
|
983
996
|
if nums.startswith('cmd:'):
|
|
984
997
|
try:
|
|
985
|
-
idx = int(nums[
|
|
998
|
+
idx = int(nums[CONSTANT_4:])
|
|
986
999
|
if 1 <= idx <= len(analyzer.items):
|
|
987
1000
|
item = analyzer.items[idx - 1]
|
|
988
1001
|
click.echo(f"\n{click.style('🔧 KOMENDA CZYSZCZENIA:', fg='yellow')}")
|
|
@@ -1000,7 +1013,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
1000
1013
|
|
|
1001
1014
|
# Handle filter:TYPE
|
|
1002
1015
|
if nums.startswith('filter:'):
|
|
1003
|
-
filter_type = nums[
|
|
1016
|
+
filter_type = nums[CONSTANT_7:].strip()
|
|
1004
1017
|
filtered_items = []
|
|
1005
1018
|
for item in analyzer.items:
|
|
1006
1019
|
item_type = item.name.split(' (')[0] if ' (' in item.name else item.name
|
|
@@ -1012,7 +1025,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
1012
1025
|
continue
|
|
1013
1026
|
|
|
1014
1027
|
click.echo(f"\n{click.style(f'🔍 FILTR: {filter_type}', fg='magenta', bold=True)}")
|
|
1015
|
-
for i, item in enumerate(filtered_items[:
|
|
1028
|
+
for i, item in enumerate(filtered_items[:CONSTANT_50], 1):
|
|
1016
1029
|
risk_icon = {"none": "✅", "low": "🟢", "medium": "🟡", "high": "🔴"}.get(item.risk, "•")
|
|
1017
1030
|
original_idx = analyzer.items.index(item) + 1
|
|
1018
1031
|
click.echo(f" [{original_idx:3d}] {risk_icon} {item.name}: {_format_bytes(item.size_bytes)}")
|
|
@@ -1081,18 +1094,18 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
1081
1094
|
items_to_clean = analyzer.items
|
|
1082
1095
|
elif selection == 'large':
|
|
1083
1096
|
# Items > 1 GB
|
|
1084
|
-
items_to_clean = [item for item in analyzer.items if item.size_bytes >
|
|
1097
|
+
items_to_clean = [item for item in analyzer.items if item.size_bytes > CONSTANT_1024**CONSTANT_3]
|
|
1085
1098
|
total_large = sum(item.size_bytes for item in items_to_clean)
|
|
1086
1099
|
click.echo(click.style(f"\n🔴 Duże elementy (>1 GB): {len(items_to_clean)} sztuk, {_format_bytes(total_large)}", fg="red"))
|
|
1087
1100
|
elif selection == 'huge':
|
|
1088
1101
|
# Items > 5 GB
|
|
1089
|
-
items_to_clean = [item for item in analyzer.items if item.size_bytes >
|
|
1102
|
+
items_to_clean = [item for item in analyzer.items if item.size_bytes > CONSTANT_5 * CONSTANT_1024**CONSTANT_3]
|
|
1090
1103
|
total_huge = sum(item.size_bytes for item in items_to_clean)
|
|
1091
|
-
click.echo(click.style(f"\n🔴 Bardzo duże elementy (>
|
|
1104
|
+
click.echo(click.style(f"\n🔴 Bardzo duże elementy (>CONSTANT_5 GB): {len(items_to_clean)} sztuk, {_format_bytes(total_huge)}", fg="red"))
|
|
1092
1105
|
elif selection == 'old':
|
|
1093
1106
|
# Items not modified in 30+ days
|
|
1094
1107
|
from datetime import datetime, timedelta
|
|
1095
|
-
cutoff = datetime.now() - timedelta(days=
|
|
1108
|
+
cutoff = datetime.now() - timedelta(days=CONSTANT_30)
|
|
1096
1109
|
items_to_clean = [
|
|
1097
1110
|
item for item in analyzer.items
|
|
1098
1111
|
if hasattr(item, 'last_modified') and item.last_modified and item.last_modified < cutoff
|
|
@@ -1102,7 +1115,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
1102
1115
|
elif selection == 'stale':
|
|
1103
1116
|
# Items not modified in 90+ days
|
|
1104
1117
|
from datetime import datetime, timedelta
|
|
1105
|
-
cutoff = datetime.now() - timedelta(days=
|
|
1118
|
+
cutoff = datetime.now() - timedelta(days=CONSTANT_90)
|
|
1106
1119
|
items_to_clean = [
|
|
1107
1120
|
item for item in analyzer.items
|
|
1108
1121
|
if hasattr(item, 'last_modified') and item.last_modified and item.last_modified < cutoff
|
|
@@ -1112,7 +1125,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
1112
1125
|
elif selection.startswith('top:'):
|
|
1113
1126
|
# Top N largest items
|
|
1114
1127
|
try:
|
|
1115
|
-
n = int(selection[
|
|
1128
|
+
n = int(selection[CONSTANT_4:])
|
|
1116
1129
|
items_to_clean = analyzer.items[:n]
|
|
1117
1130
|
total_top = sum(item.size_bytes for item in items_to_clean)
|
|
1118
1131
|
click.echo(click.style(f"\n🏆 Top {n} największych: {_format_bytes(total_top)}", fg="yellow"))
|
|
@@ -1121,7 +1134,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
1121
1134
|
return
|
|
1122
1135
|
elif selection.startswith('category:'):
|
|
1123
1136
|
# Filter by category
|
|
1124
|
-
selected_category = selection[
|
|
1137
|
+
selected_category = selection[CONSTANT_9:].strip()
|
|
1125
1138
|
items_to_clean = [item for item in analyzer.items if item.category == selected_category]
|
|
1126
1139
|
|
|
1127
1140
|
if not items_to_clean:
|
|
@@ -1134,7 +1147,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
1134
1147
|
click.echo(click.style(f"\n📁 Kategoria '{selected_category}': {len(items_to_clean)} elementów, {_format_bytes(total_cat)}", fg="blue"))
|
|
1135
1148
|
elif selection.startswith('type:'):
|
|
1136
1149
|
# Filter by type (single or multiple)
|
|
1137
|
-
selected_types = [t.strip() for t in selection[
|
|
1150
|
+
selected_types = [t.strip() for t in selection[CONSTANT_5:].split(',')]
|
|
1138
1151
|
|
|
1139
1152
|
for item in analyzer.items:
|
|
1140
1153
|
item_type = item.name.split(' (')[0] if ' (' in item.name else item.name
|
|
@@ -1154,9 +1167,9 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
1154
1167
|
if not items_to_clean:
|
|
1155
1168
|
return
|
|
1156
1169
|
|
|
1157
|
-
click.echo("\n" + click.style("="*
|
|
1170
|
+
click.echo("\n" + click.style("="*CONSTANT_60, fg="cyan"))
|
|
1158
1171
|
click.echo(click.style("🚀 WYKONYWANIE CZYSZCZENIA", fg="cyan", bold=True))
|
|
1159
|
-
click.echo(click.style("="*
|
|
1172
|
+
click.echo(click.style("="*CONSTANT_60, fg="cyan") + "\n")
|
|
1160
1173
|
|
|
1161
1174
|
results = {"success": 0, "failed": 0, "space_reclaimed": 0}
|
|
1162
1175
|
|
|
@@ -1181,7 +1194,7 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
1181
1194
|
item.cleanup_command.split(),
|
|
1182
1195
|
capture_output=True,
|
|
1183
1196
|
text=True,
|
|
1184
|
-
timeout=
|
|
1197
|
+
timeout=CONSTANT_300,
|
|
1185
1198
|
)
|
|
1186
1199
|
if result.returncode == 0:
|
|
1187
1200
|
click.echo(click.style(" ✅ Sukces", fg="green"))
|
|
@@ -1195,9 +1208,9 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
1195
1208
|
results['failed'] += 1
|
|
1196
1209
|
|
|
1197
1210
|
# Summary
|
|
1198
|
-
click.echo("\n" + click.style("="*
|
|
1211
|
+
click.echo("\n" + click.style("="*CONSTANT_60, fg="cyan"))
|
|
1199
1212
|
click.echo(click.style("📊 PODSUMOWANIE", fg="cyan", bold=True))
|
|
1200
|
-
click.echo(click.style("="*
|
|
1213
|
+
click.echo(click.style("="*CONSTANT_60, fg="cyan"))
|
|
1201
1214
|
click.echo(f" ✅ Sukces: {results['success']}")
|
|
1202
1215
|
click.echo(f" ❌ Błędy: {results['failed']}")
|
|
1203
1216
|
|
|
@@ -1206,18 +1219,18 @@ def _cleanup_full_system(json_output: bool, dry_run: bool):
|
|
|
1206
1219
|
else:
|
|
1207
1220
|
click.echo(click.style(f"\n 💰 Odzyskano: {_format_bytes(results['space_reclaimed'])}", fg="green"))
|
|
1208
1221
|
|
|
1209
|
-
click.echo(click.style("="*
|
|
1222
|
+
click.echo(click.style("="*CONSTANT_60 + "\n", fg="cyan"))
|
|
1210
1223
|
|
|
1211
1224
|
|
|
1212
1225
|
def _parse_size_to_gb(size_str: str) -> float:
|
|
1213
1226
|
"""Parse human-readable size to GB"""
|
|
1214
1227
|
size_str = size_str.strip().upper()
|
|
1215
1228
|
multipliers = {
|
|
1216
|
-
'B': 1 / (
|
|
1217
|
-
'KB': 1 / (
|
|
1218
|
-
'MB': 1 /
|
|
1229
|
+
'B': 1 / (CONSTANT_1024**CONSTANT_3),
|
|
1230
|
+
'KB': 1 / (CONSTANT_1024**2),
|
|
1231
|
+
'MB': 1 / CONSTANT_1024,
|
|
1219
1232
|
'GB': 1,
|
|
1220
|
-
'TB':
|
|
1233
|
+
'TB': CONSTANT_1024,
|
|
1221
1234
|
}
|
|
1222
1235
|
|
|
1223
1236
|
for suffix, mult in sorted(multipliers.items(), key=lambda x: -len(x[0])):
|
|
@@ -1228,6 +1241,6 @@ def _parse_size_to_gb(size_str: str) -> float:
|
|
|
1228
1241
|
return 0
|
|
1229
1242
|
|
|
1230
1243
|
try:
|
|
1231
|
-
return float(size_str) / (
|
|
1244
|
+
return float(size_str) / (CONSTANT_1024**CONSTANT_3)
|
|
1232
1245
|
except ValueError:
|
|
1233
1246
|
return 0
|
|
@@ -12,6 +12,12 @@ from dataclasses import dataclass, field
|
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import Optional
|
|
14
14
|
|
|
15
|
+
CONSTANT_4 = 4
|
|
16
|
+
CONSTANT_8 = 8
|
|
17
|
+
CONSTANT_12 = 12
|
|
18
|
+
CONSTANT_384 = 384
|
|
19
|
+
TIMEOUT_3600 = 3600
|
|
20
|
+
|
|
15
21
|
# Próbuj załadować python-dotenv
|
|
16
22
|
try:
|
|
17
23
|
from dotenv import load_dotenv
|
|
@@ -162,7 +168,7 @@ class FixOsConfig:
|
|
|
162
168
|
|
|
163
169
|
# Agent
|
|
164
170
|
agent_mode: str = "hitl" # hitl | autonomous
|
|
165
|
-
session_timeout: int =
|
|
171
|
+
session_timeout: int = TIMEOUT_3600
|
|
166
172
|
max_auto_fixes: int = 10 # limit dla trybu autonomous
|
|
167
173
|
|
|
168
174
|
# UI
|
|
@@ -274,8 +280,8 @@ class FixOsConfig:
|
|
|
274
280
|
def summary(self) -> str:
|
|
275
281
|
"""Krótkie podsumowanie konfiguracji (bez klucza API)."""
|
|
276
282
|
if self.api_key:
|
|
277
|
-
if len(self.api_key) >
|
|
278
|
-
key_masked = f"{self.api_key[:
|
|
283
|
+
if len(self.api_key) > CONSTANT_12:
|
|
284
|
+
key_masked = f"{self.api_key[:CONSTANT_8]}...{self.api_key[-CONSTANT_4:]}"
|
|
279
285
|
else:
|
|
280
286
|
key_masked = "***"
|
|
281
287
|
else:
|
|
@@ -411,7 +417,7 @@ def interactive_provider_setup() -> Optional["FixOsConfig"]:
|
|
|
411
417
|
env_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
412
418
|
env_path.chmod(0o600)
|
|
413
419
|
|
|
414
|
-
masked = f"{key[:
|
|
420
|
+
masked = f"{key[:CONSTANT_8]}...{key[-CONSTANT_4:]}" if len(key) > CONSTANT_12 else "***"
|
|
415
421
|
print(f" 💾 Zapisano {key_env}={masked} → {env_path}")
|
|
416
422
|
print()
|
|
417
423
|
|