diff --git a/src/sifty/cli/app.py b/src/sifty/cli/app.py index c3c0695..c83c837 100644 --- a/src/sifty/cli/app.py +++ b/src/sifty/cli/app.py @@ -335,7 +335,7 @@ def checkup_cmd() -> None: console.print(table) issues = sum(1 for f in findings if f.severity != "ok") if issues: - console.print(f"[bold]{issues}[/bold] item(s) worth a look - checkup never changes anything itself.") + console.print(f"[bold]{issues:,}[/bold] item(s) worth a look - checkup never changes anything itself.") else: success("All clear - nothing needs attention.") @@ -444,16 +444,16 @@ def undo_cmd( console.print("Nothing to undo - no restorable items in history.") return if not confirm( - f"Restore {run.restorable} item(s) from the {run.action} clean at {run.ts}?", + f"Restore {run.restorable:,} item(s) from the {run.action} clean at {run.ts}?", assume_yes=yes, ): warn("Cancelled.") return with console.status("Restoring from the Recycle Bin…"): restored, failed = undo.undo(run.id) - success(f"Restored {restored} item(s).") + success(f"Restored {restored:,} item(s).") if failed: - warn(f"{failed} item(s) could not be restored (see `sifty logs`).") + warn(f"{failed:,} item(s) could not be restored (see `sifty logs`).") def entrypoint() -> None: diff --git a/src/sifty/cli/commands/apps.py b/src/sifty/cli/commands/apps.py index c7d43dd..35326ae 100644 --- a/src/sifty/cli/commands/apps.py +++ b/src/sifty/cli/commands/apps.py @@ -37,7 +37,7 @@ def list_cmd( ]) return - table = Table(title=f"Installed apps ({len(items)})") + table = Table(title=f"Installed apps ({len(items):,})") table.add_column("Name") table.add_column("Version", style="dim") table.add_column("Publisher", style="dim") @@ -57,7 +57,7 @@ def startup_cmd() -> None: for e in entries ]) return - table = Table(title=f"Startup programs ({len(entries)})") + table = Table(title=f"Startup programs ({len(entries):,})") table.add_column("Name") table.add_column("Origin", style="dim") table.add_column("Command") @@ -86,7 +86,7 @@ def orphans_cmd() -> None: success("No orphaned uninstall entries found.") return - table = Table(title=f"Orphaned uninstall entries ({len(entries)})") + table = Table(title=f"Orphaned uninstall entries ({len(entries):,})") table.add_column("Application") table.add_column("Reason", style="dim") table.add_column("Key (hive)", style="dim") @@ -94,7 +94,7 @@ def orphans_cmd() -> None: table.add_row(e.display_name, e.reason, e.hive) console.print(table) console.print( - f"\n[dim]{len(entries)} entry/entries with broken uninstallers. " + f"\n[dim]{len(entries):,} entry/entries with broken uninstallers. " "These can be removed manually via regedit or a registry cleaner.[/dim]" ) @@ -139,7 +139,7 @@ def _report_leftovers(name: str) -> None: if not items: return total = sum(i.size_bytes for i in items) - warn(f"{len(items)} leftover item(s) found ({human_size(total)}).") + warn(f"{len(items):,} leftover item(s) found ({human_size(total)}).") console.print(f'[dim]Review and remove them with: [cyan]sifty apps leftovers "{name}"[/cyan][/dim]') @@ -180,11 +180,11 @@ def leftovers_cmd( if not apply: console.print("[dim]Dry-run - re-run with --apply to move them to the Recycle Bin.[/dim]") return - if not confirm(f"Move {len(items)} item(s) ({human_size(total)}) to the Recycle Bin?", assume_yes=yes): + if not confirm(f"Move {len(items):,} item(s) ({human_size(total)}) to the Recycle Bin?", assume_yes=yes): warn("Cancelled.") return result = clean_leftovers(items, dry_run=False) history.record_clean("leftovers", name, result.bytes_freed, result.items, result.trashed) - success(f"Sent {result.items} item(s) ({human_size(result.bytes_freed)}) to the Recycle Bin.") + success(f"Sent {result.items:,} item(s) ({human_size(result.bytes_freed)}) to the Recycle Bin.") if result.skipped: - warn(f"{len(result.skipped)} item(s) skipped (in use or protected).") + warn(f"{len(result.skipped):,} item(s) skipped (in use or protected).") diff --git a/src/sifty/cli/commands/cleanup.py b/src/sifty/cli/commands/cleanup.py index 19fbc32..bd67073 100644 --- a/src/sifty/cli/commands/cleanup.py +++ b/src/sifty/cli/commands/cleanup.py @@ -45,18 +45,18 @@ def duplicates_cmd( success("No duplicates to remove.") return console.print( - f"{len(groups)} duplicate group(s) · [bold]{preview.items}[/bold] redundant copies · " + f"{len(groups):,} duplicate group(s) · [bold]{preview.items:,}[/bold] redundant copies · " f"[bold]{human_size(preview.bytes_freed)}[/bold] reclaimable." ) if not apply: console.print("[dim]Dry-run - re-run with --apply to remove the extra copies.[/dim]") return - if not confirm(f"Move {preview.items} redundant copies ({human_size(preview.bytes_freed)}) to the Recycle Bin?", assume_yes=yes): + if not confirm(f"Move {preview.items:,} redundant copies ({human_size(preview.bytes_freed)}) to the Recycle Bin?", assume_yes=yes): warn("Cancelled.") return result = cleanup.trash_paths(to_delete, dry_run=False, extra_protected=extra) history.record_clean("cleanup-duplicates", str(path), result.bytes_freed, result.items, result.trashed) - success(f"Sent {result.items} copies ({human_size(result.bytes_freed)}) to the Recycle Bin.") + success(f"Sent {result.items:,} copies ({human_size(result.bytes_freed)}) to the Recycle Bin.") @app.command("large") @@ -114,17 +114,17 @@ def stale_cmd( for p, s, m in items: table.add_row(human_size(s), datetime.fromtimestamp(m).strftime("%Y-%m-%d"), p.name) console.print(table) - console.print(f"\n[bold]{len(items)} items · {human_size(total)}[/bold]") + console.print(f"\n[bold]{len(items):,} items · {human_size(total)}[/bold]") if not apply: console.print("[dim]Dry-run - re-run with --apply to remove them.[/dim]") return - if not confirm(f"Move {len(items)} stale items ({human_size(total)}) to the Recycle Bin?", assume_yes=yes): + if not confirm(f"Move {len(items):,} stale items ({human_size(total)}) to the Recycle Bin?", assume_yes=yes): warn("Cancelled.") return extra = list(exclude) if exclude else None result = cleanup.trash_paths([p for p, _s, _m in items], dry_run=False, extra_protected=extra) history.record_clean("cleanup-stale", f"Downloads >{days}d", result.bytes_freed, result.items, result.trashed) - success(f"Sent {result.items} items ({human_size(result.bytes_freed)}) to the Recycle Bin.") + success(f"Sent {result.items:,} items ({human_size(result.bytes_freed)}) to the Recycle Bin.") @app.command("worktrees") @@ -163,12 +163,12 @@ def worktrees_cmd( if not apply: console.print("[dim]Dry-run - re-run with --apply to prune and trash them.[/dim]") return - if not confirm(f"Prune {len(orphans)} orphaned worktree(s)?", assume_yes=yes): + if not confirm(f"Prune {len(orphans):,} orphaned worktree(s)?", assume_yes=yes): warn("Cancelled.") return result = prune_worktrees(path, dry_run=False) history.record_clean("cleanup-worktrees", str(path), result.bytes_freed, result.items, result.trashed) - success(f"Pruned {result.items} worktree(s) ({human_size(result.bytes_freed)}).") + success(f"Pruned {result.items:,} worktree(s) ({human_size(result.bytes_freed)}).") class _null: diff --git a/src/sifty/cli/commands/disk.py b/src/sifty/cli/commands/disk.py index 8d427bf..cfcbbc0 100644 --- a/src/sifty/cli/commands/disk.py +++ b/src/sifty/cli/commands/disk.py @@ -119,6 +119,6 @@ def duplicates_cmd( each = disk._entry_size(paths[0]) wasted = each * (len(paths) - 1) reclaimable += wasted - table.add_row(str(len(paths)), human_size(each), human_size(wasted), str(paths[0])) + table.add_row(f"{len(paths):,}", human_size(each), human_size(wasted), str(paths[0])) console.print(table) console.print(f"\n[bold]Reclaimable by de-duplicating: {human_size(reclaimable)}[/bold]") diff --git a/src/sifty/cli/commands/junk.py b/src/sifty/cli/commands/junk.py index 1d6cdf0..487ebfd 100644 --- a/src/sifty/cli/commands/junk.py +++ b/src/sifty/cli/commands/junk.py @@ -84,4 +84,4 @@ def clean_cmd( ) success(f"Sent {result.items:,} items ({human_size(result.bytes_freed)}) to the Recycle Bin.") if result.skipped: - warn(f"{len(result.skipped)} item(s) skipped (in use or protected).") + warn(f"{len(result.skipped):,} item(s) skipped (in use or protected).") diff --git a/src/sifty/cli/commands/optimize.py b/src/sifty/cli/commands/optimize.py index c9b3af7..1ae10c3 100644 --- a/src/sifty/cli/commands/optimize.py +++ b/src/sifty/cli/commands/optimize.py @@ -69,12 +69,12 @@ def run_cmd( for op in runnable: console.print(f" [cyan]{op.key}[/cyan] {op.description}") if skipped_admin: - console.print(f"\n[dim]{len(skipped_admin)} admin-only operation(s) skipped " + console.print(f"\n[dim]{len(skipped_admin):,} admin-only operation(s) skipped " f"(relaunch with --admin to include them).[/dim]") console.print("\n[dim]Dry-run - re-run with --apply to execute.[/dim]") return - if not confirm(f"Run {len(runnable)} optimization operation(s)?", assume_yes=yes): + if not confirm(f"Run {len(runnable):,} optimization operation(s)?", assume_yes=yes): warn("Cancelled.") return @@ -87,6 +87,6 @@ def run_cmd( console.print(f"[red]failed: {msg}[/red]") if skipped_admin: - warn(f"{len(skipped_admin)} admin-only operation(s) skipped " + warn(f"{len(skipped_admin):,} admin-only operation(s) skipped " f"(relaunch with --admin to include them).") success("Optimization complete.") diff --git a/src/sifty/cli/commands/organize.py b/src/sifty/cli/commands/organize.py index 8834198..d2abacb 100644 --- a/src/sifty/cli/commands/organize.py +++ b/src/sifty/cli/commands/organize.py @@ -46,25 +46,25 @@ def _run(path: Path, scheme: str, *, apply: bool, yes: bool) -> None: success("Nothing to organize - all files are already sorted.") return - table = Table(title=f"Organize '{path}' by {scheme} ({len(moves)} files)") + table = Table(title=f"Organize '{path}' by {scheme} ({len(moves):,} files)") table.add_column("File") table.add_column("→ Folder", style="cyan") for m in moves[:50]: table.add_row(m.src.name, m.dest.parent.name) console.print(table) if len(moves) > 50: - console.print(f"[dim]…and {len(moves) - 50} more.[/dim]") + console.print(f"[dim]…and {len(moves) - 50:,} more.[/dim]") if not apply: console.print("[dim]Dry-run - nothing moved. Re-run with 'organize apply' to perform.[/dim]") return - if not confirm(f"Move {len(moves)} files into subfolders?", assume_yes=yes): + if not confirm(f"Move {len(moves):,} files into subfolders?", assume_yes=yes): warn("Cancelled.") return done = organize.apply_moves(moves) - success(f"Organized {done} files. Undo with [cyan]sifty organize undo[/cyan].") + success(f"Organized {done:,} files. Undo with [cyan]sifty organize undo[/cyan].") @app.command("undo") @@ -76,10 +76,10 @@ def undo_cmd( if not pairs: warn("Nothing to undo - no organize session recorded.") return - if not confirm(f"Move {len(pairs)} file(s) back to their original locations?", assume_yes=yes): + if not confirm(f"Move {len(pairs):,} file(s) back to their original locations?", assume_yes=yes): warn("Cancelled.") return restored, failed = organize.undo_last() - success(f"Restored {restored} file(s).") + success(f"Restored {restored:,} file(s).") if failed: - warn(f"{failed} file(s) could not be restored (moved or replaced since).") + warn(f"{failed:,} file(s) could not be restored (moved or replaced since).") diff --git a/src/sifty/cli/commands/profile.py b/src/sifty/cli/commands/profile.py index af9b4e7..4cf4ff0 100644 --- a/src/sifty/cli/commands/profile.py +++ b/src/sifty/cli/commands/profile.py @@ -45,7 +45,7 @@ def add_cmd( error(f"Unknown categories: {', '.join(unknown)}. Valid: {', '.join(sorted(valid))}") raise typer.Exit(1) profiles.save(Profile(name, category)) - success(f"Saved profile '{name}' ({len(category)} categories).") + success(f"Saved profile '{name}' ({len(category):,} categories).") @app.command("remove") diff --git a/src/sifty/cli/commands/purge.py b/src/sifty/cli/commands/purge.py index 8b40014..276fb2d 100644 --- a/src/sifty/cli/commands/purge.py +++ b/src/sifty/cli/commands/purge.py @@ -45,7 +45,7 @@ def scan_cmd( table.add_row(a.pattern, human_size(a.size_bytes), str(a.path)) total += a.size_bytes table.add_section() - table.add_row("", f"[bold]{human_size(total)}[/bold]", f"[dim]{len(artifacts)} directories[/dim]") + table.add_row("", f"[bold]{human_size(total)}[/bold]", f"[dim]{len(artifacts):,} directories[/dim]") console.print(table) console.print("\nRun [cyan]sifty purge clean PATH --apply[/cyan] to remove them.") @@ -71,7 +71,7 @@ def clean_cmd( total = sum(a.size_bytes for a in artifacts) console.print( - f"Found [bold]{len(artifacts)}[/bold] artifact directories " + f"Found [bold]{len(artifacts):,}[/bold] artifact directories " f"totalling [bold]{human_size(total)}[/bold]." ) if not apply: @@ -79,7 +79,7 @@ def clean_cmd( return if not confirm( - f"Move {len(artifacts)} artifact directories ({human_size(total)}) to the Recycle Bin?", + f"Move {len(artifacts):,} artifact directories ({human_size(total)}) to the Recycle Bin?", assume_yes=yes, ): warn("Cancelled.") @@ -87,9 +87,9 @@ def clean_cmd( result = purge.purge_artifacts([a.path for a in artifacts], dry_run=False) history.record_clean("purge", str(path), result.bytes_freed, result.items, result.trashed) - success(f"Sent {result.items} directories ({human_size(result.bytes_freed)}) to the Recycle Bin.") + success(f"Sent {result.items:,} directories ({human_size(result.bytes_freed)}) to the Recycle Bin.") if result.skipped: - warn(f"{len(result.skipped)} skipped (in use or protected).") + warn(f"{len(result.skipped):,} skipped (in use or protected).") class _null: diff --git a/src/sifty/cli/commands/startup.py b/src/sifty/cli/commands/startup.py index a574aa9..2406bf8 100644 --- a/src/sifty/cli/commands/startup.py +++ b/src/sifty/cli/commands/startup.py @@ -22,7 +22,7 @@ def list_cmd() -> None: for e in entries ]) return - table = Table(title=f"Startup programs ({len(entries)})") + table = Table(title=f"Startup programs ({len(entries):,})") table.add_column("Name") table.add_column("State") table.add_column("Origin", style="dim") diff --git a/src/sifty/cli/commands/updates.py b/src/sifty/cli/commands/updates.py index 890190d..487eeb8 100644 --- a/src/sifty/cli/commands/updates.py +++ b/src/sifty/cli/commands/updates.py @@ -38,7 +38,7 @@ def check_cmd() -> None: success("Everything is up to date.") return - table = Table(title=f"Available updates ({len(upgrades)})") + table = Table(title=f"Available updates ({len(upgrades):,})") table.add_column("Name") table.add_column("Id", style="dim") table.add_column("Current", justify="right")