sifty 0.6.0__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.
- sifty-0.6.0/LICENSE +21 -0
- sifty-0.6.0/PKG-INFO +254 -0
- sifty-0.6.0/README.md +211 -0
- sifty-0.6.0/pyproject.toml +82 -0
- sifty-0.6.0/setup.cfg +4 -0
- sifty-0.6.0/src/sifty/__init__.py +3 -0
- sifty-0.6.0/src/sifty/__main__.py +6 -0
- sifty-0.6.0/src/sifty/ai/__init__.py +1 -0
- sifty-0.6.0/src/sifty/ai/advisor.py +71 -0
- sifty-0.6.0/src/sifty/ai/agent.py +227 -0
- sifty-0.6.0/src/sifty/ai/client.py +176 -0
- sifty-0.6.0/src/sifty/ai/context.py +92 -0
- sifty-0.6.0/src/sifty/ai/tools.py +546 -0
- sifty-0.6.0/src/sifty/cli/__init__.py +1 -0
- sifty-0.6.0/src/sifty/cli/app.py +475 -0
- sifty-0.6.0/src/sifty/cli/commands/__init__.py +1 -0
- sifty-0.6.0/src/sifty/cli/commands/ai_group.py +62 -0
- sifty-0.6.0/src/sifty/cli/commands/apps.py +190 -0
- sifty-0.6.0/src/sifty/cli/commands/cleanup.py +181 -0
- sifty-0.6.0/src/sifty/cli/commands/config_cmd.py +133 -0
- sifty-0.6.0/src/sifty/cli/commands/disk.py +124 -0
- sifty-0.6.0/src/sifty/cli/commands/junk.py +87 -0
- sifty-0.6.0/src/sifty/cli/commands/optimize.py +92 -0
- sifty-0.6.0/src/sifty/cli/commands/organize.py +85 -0
- sifty-0.6.0/src/sifty/cli/commands/profile.py +58 -0
- sifty-0.6.0/src/sifty/cli/commands/purge.py +97 -0
- sifty-0.6.0/src/sifty/cli/commands/schedule.py +66 -0
- sifty-0.6.0/src/sifty/cli/commands/services.py +64 -0
- sifty-0.6.0/src/sifty/cli/commands/startup.py +57 -0
- sifty-0.6.0/src/sifty/cli/commands/updates.py +75 -0
- sifty-0.6.0/src/sifty/cli/commands/watch.py +58 -0
- sifty-0.6.0/src/sifty/cli/output.py +26 -0
- sifty-0.6.0/src/sifty/console.py +49 -0
- sifty-0.6.0/src/sifty/core/__init__.py +4 -0
- sifty-0.6.0/src/sifty/core/apps.py +113 -0
- sifty-0.6.0/src/sifty/core/checkup.py +156 -0
- sifty-0.6.0/src/sifty/core/cleanup.py +141 -0
- sifty-0.6.0/src/sifty/core/disk.py +117 -0
- sifty-0.6.0/src/sifty/core/history.py +154 -0
- sifty-0.6.0/src/sifty/core/junk.py +395 -0
- sifty-0.6.0/src/sifty/core/leftovers.py +222 -0
- sifty-0.6.0/src/sifty/core/models.py +114 -0
- sifty-0.6.0/src/sifty/core/monitor.py +113 -0
- sifty-0.6.0/src/sifty/core/optimize.py +225 -0
- sifty-0.6.0/src/sifty/core/organize.py +138 -0
- sifty-0.6.0/src/sifty/core/profiles.py +66 -0
- sifty-0.6.0/src/sifty/core/purge.py +132 -0
- sifty-0.6.0/src/sifty/core/registry_scan.py +129 -0
- sifty-0.6.0/src/sifty/core/safety.py +152 -0
- sifty-0.6.0/src/sifty/core/schedule.py +78 -0
- sifty-0.6.0/src/sifty/core/selfupdate.py +77 -0
- sifty-0.6.0/src/sifty/core/services.py +70 -0
- sifty-0.6.0/src/sifty/core/startup.py +111 -0
- sifty-0.6.0/src/sifty/core/undo.py +28 -0
- sifty-0.6.0/src/sifty/core/updates.py +65 -0
- sifty-0.6.0/src/sifty/core/vcs.py +163 -0
- sifty-0.6.0/src/sifty/core/watch.py +22 -0
- sifty-0.6.0/src/sifty/infra/__init__.py +1 -0
- sifty-0.6.0/src/sifty/infra/config.py +165 -0
- sifty-0.6.0/src/sifty/infra/logging.py +98 -0
- sifty-0.6.0/src/sifty/tui/__init__.py +1 -0
- sifty-0.6.0/src/sifty/tui/app.py +143 -0
- sifty-0.6.0/src/sifty/tui/commands.py +44 -0
- sifty-0.6.0/src/sifty/tui/modals.py +32 -0
- sifty-0.6.0/src/sifty/tui/screens/__init__.py +1 -0
- sifty-0.6.0/src/sifty/tui/screens/path_picker.py +72 -0
- sifty-0.6.0/src/sifty/tui/state.py +44 -0
- sifty-0.6.0/src/sifty/tui/styles.tcss +264 -0
- sifty-0.6.0/src/sifty/tui/views/__init__.py +64 -0
- sifty-0.6.0/src/sifty/tui/views/ai.py +354 -0
- sifty-0.6.0/src/sifty/tui/views/apps.py +300 -0
- sifty-0.6.0/src/sifty/tui/views/base.py +16 -0
- sifty-0.6.0/src/sifty/tui/views/cleanup.py +215 -0
- sifty-0.6.0/src/sifty/tui/views/disk.py +119 -0
- sifty-0.6.0/src/sifty/tui/views/group.py +107 -0
- sifty-0.6.0/src/sifty/tui/views/home.py +202 -0
- sifty-0.6.0/src/sifty/tui/views/junk.py +141 -0
- sifty-0.6.0/src/sifty/tui/views/monitor.py +115 -0
- sifty-0.6.0/src/sifty/tui/views/optimize.py +111 -0
- sifty-0.6.0/src/sifty/tui/views/purge.py +183 -0
- sifty-0.6.0/src/sifty/tui/views/reports.py +100 -0
- sifty-0.6.0/src/sifty/tui/views/services.py +116 -0
- sifty-0.6.0/src/sifty/tui/views/startup.py +104 -0
- sifty-0.6.0/src/sifty/tui/views/updates.py +125 -0
- sifty-0.6.0/src/sifty/tui/widgets.py +28 -0
- sifty-0.6.0/src/sifty/windows/__init__.py +5 -0
- sifty-0.6.0/src/sifty/windows/admin.py +95 -0
- sifty-0.6.0/src/sifty/windows/hyperv.py +67 -0
- sifty-0.6.0/src/sifty/windows/notify.py +26 -0
- sifty-0.6.0/src/sifty/windows/recyclebin.py +66 -0
- sifty-0.6.0/src/sifty/windows/registry.py +88 -0
- sifty-0.6.0/src/sifty/windows/scheduler.py +59 -0
- sifty-0.6.0/src/sifty/windows/services_api.py +68 -0
- sifty-0.6.0/src/sifty/windows/winget.py +46 -0
- sifty-0.6.0/src/sifty.egg-info/PKG-INFO +254 -0
- sifty-0.6.0/src/sifty.egg-info/SOURCES.txt +125 -0
- sifty-0.6.0/src/sifty.egg-info/dependency_links.txt +1 -0
- sifty-0.6.0/src/sifty.egg-info/entry_points.txt +2 -0
- sifty-0.6.0/src/sifty.egg-info/requires.txt +18 -0
- sifty-0.6.0/src/sifty.egg-info/top_level.txt +1 -0
- sifty-0.6.0/tests/test_admin.py +95 -0
- sifty-0.6.0/tests/test_agent.py +233 -0
- sifty-0.6.0/tests/test_ai_context.py +125 -0
- sifty-0.6.0/tests/test_checkup.py +54 -0
- sifty-0.6.0/tests/test_cleanup.py +75 -0
- sifty-0.6.0/tests/test_cli_json.py +46 -0
- sifty-0.6.0/tests/test_config.py +42 -0
- sifty-0.6.0/tests/test_disk.py +60 -0
- sifty-0.6.0/tests/test_history.py +66 -0
- sifty-0.6.0/tests/test_junk.py +106 -0
- sifty-0.6.0/tests/test_leftovers.py +92 -0
- sifty-0.6.0/tests/test_logsetup.py +67 -0
- sifty-0.6.0/tests/test_optimize.py +62 -0
- sifty-0.6.0/tests/test_organize.py +81 -0
- sifty-0.6.0/tests/test_path_picker.py +72 -0
- sifty-0.6.0/tests/test_profiles.py +43 -0
- sifty-0.6.0/tests/test_purge.py +94 -0
- sifty-0.6.0/tests/test_registry_scan.py +126 -0
- sifty-0.6.0/tests/test_safety.py +99 -0
- sifty-0.6.0/tests/test_schedule.py +68 -0
- sifty-0.6.0/tests/test_services.py +36 -0
- sifty-0.6.0/tests/test_startup.py +68 -0
- sifty-0.6.0/tests/test_tools.py +115 -0
- sifty-0.6.0/tests/test_tui.py +541 -0
- sifty-0.6.0/tests/test_updates.py +31 -0
- sifty-0.6.0/tests/test_vcs.py +59 -0
- sifty-0.6.0/tests/test_watch.py +56 -0
sifty-0.6.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Amine Zouaoui
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
sifty-0.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sifty
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Sifty — an AI-assisted Windows maintenance CLI/TUI: sift junk, analyze disks, manage apps, updates and files. Recycle Bin only, dry-run by default.
|
|
5
|
+
Author: Amine Zouaoui
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Vortrix5/sifty
|
|
8
|
+
Project-URL: Repository, https://github.com/Vortrix5/sifty
|
|
9
|
+
Project-URL: Issues, https://github.com/Vortrix5/sifty/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/Vortrix5/sifty/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: windows,maintenance,cleaner,junk,disk-usage,duplicates,uninstaller,winget,tui,textual,ollama
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: System :: Systems Administration
|
|
23
|
+
Classifier: Topic :: Utilities
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: typer>=0.12
|
|
28
|
+
Requires-Dist: rich>=13.7
|
|
29
|
+
Requires-Dist: psutil>=5.9
|
|
30
|
+
Requires-Dist: send2trash>=1.8
|
|
31
|
+
Requires-Dist: pywin32>=306; sys_platform == "win32"
|
|
32
|
+
Requires-Dist: winshell>=0.6; sys_platform == "win32"
|
|
33
|
+
Requires-Dist: windows-toasts>=1.1; sys_platform == "win32"
|
|
34
|
+
Requires-Dist: httpx>=0.27
|
|
35
|
+
Requires-Dist: textual>=0.60
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-mock>=3.12; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
40
|
+
Requires-Dist: textual-dev>=1.5; extra == "dev"
|
|
41
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# Sifty
|
|
45
|
+
|
|
46
|
+
> An AI-assisted Windows maintenance CLI + TUI that **sifts the junk from the keep**.
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+

|
|
50
|
+

|
|
51
|
+

|
|
52
|
+
|
|
53
|
+
Clean junk, analyze disks, find duplicates, manage apps and startup programs,
|
|
54
|
+
apply updates, prune dev artifacts and git worktrees, and organize files — from
|
|
55
|
+
a scriptable CLI or a full-screen terminal UI. The optional AI assistant runs
|
|
56
|
+
**locally** via [Ollama]: nothing leaves your machine, and it only ever sees
|
|
57
|
+
file *metadata* (names, sizes, paths), never file contents.
|
|
58
|
+
|
|
59
|
+
<!-- TODO: add a demo GIF of `sifty tui` here — it sells the project better
|
|
60
|
+
than anything below. `textual run --dev` + any screen recorder works. -->
|
|
61
|
+
|
|
62
|
+
## Safety first
|
|
63
|
+
|
|
64
|
+
Sifty deletes files and changes system state, so it is built to be hard to misuse:
|
|
65
|
+
|
|
66
|
+
- **Dry-run by default** — every destructive command previews what it would do.
|
|
67
|
+
Real changes need an explicit `--apply`.
|
|
68
|
+
- **Recycle Bin, never permanent delete** — all removals go through one
|
|
69
|
+
`trash()` function backed by Send2Trash. `sifty undo` restores the last clean.
|
|
70
|
+
- **Protected paths** — `C:\Windows`, `Program Files`, `ProgramData`, the drive
|
|
71
|
+
root and your profile root are refused even with `--apply --yes`.
|
|
72
|
+
- **Audit log** — every applied deletion is recorded in `%APPDATA%\sifty\audit.log`.
|
|
73
|
+
- **The AI never deletes anything** — it is advisory; high-risk tool calls
|
|
74
|
+
always require your approval.
|
|
75
|
+
|
|
76
|
+
## How it compares
|
|
77
|
+
|
|
78
|
+
| Feature | Sifty | CCleaner | Revo Uninstaller | WinDirStat |
|
|
79
|
+
| --- | --- | --- | --- | --- |
|
|
80
|
+
| Junk / cache cleaning | ✅ 11+ categories | ✅ | ➖ | ❌ |
|
|
81
|
+
| Disk usage analysis | ✅ top-N + volumes | ➖ | ❌ | ✅ treemap |
|
|
82
|
+
| Duplicate finder | ✅ SHA-256, NTFS-aware | ✅ (paid) | ❌ | ❌ |
|
|
83
|
+
| App uninstall + leftover scan | ✅ winget + leftovers | ✅ | ✅ + leftovers | ❌ |
|
|
84
|
+
| App updates | ✅ via winget | ✅ (paid) | ❌ | ❌ |
|
|
85
|
+
| Startup manager | ✅ reversible | ✅ | ✅ | ❌ |
|
|
86
|
+
| Dev artifact purge (node_modules, …) | ✅ | ❌ | ❌ | ❌ |
|
|
87
|
+
| Git worktree / WSL2 VHD cleanup | ✅ | ❌ | ❌ | ❌ |
|
|
88
|
+
| Local AI assistant | ✅ Ollama | ❌ | ❌ | ❌ |
|
|
89
|
+
| Scriptable (JSON output) | ✅ | ❌ | ❌ | ❌ |
|
|
90
|
+
| Recycle Bin + undo for everything | ✅ | ➖ | ➖ | n/a |
|
|
91
|
+
| Price | Free, MIT | Freemium | Freemium | Free |
|
|
92
|
+
|
|
93
|
+
Sifty is built **developer-first**: everything is scriptable, the engine is a
|
|
94
|
+
reusable Python library, and it cleans the things developer machines actually
|
|
95
|
+
accumulate (build artifacts, orphaned worktrees, bloated WSL2 disks).
|
|
96
|
+
|
|
97
|
+
## Install
|
|
98
|
+
|
|
99
|
+
```powershell
|
|
100
|
+
# from source (recommended while pre-PyPI)
|
|
101
|
+
git clone https://github.com/Vortrix5/sifty && cd sifty
|
|
102
|
+
pipx install --editable . # or: pip install .
|
|
103
|
+
|
|
104
|
+
sifty doctor # check admin rights, winget, Ollama
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
For development:
|
|
108
|
+
|
|
109
|
+
```powershell
|
|
110
|
+
python -m venv .venv
|
|
111
|
+
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
|
|
112
|
+
.\.venv\Scripts\python.exe -m pytest -q
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Usage
|
|
116
|
+
|
|
117
|
+
```powershell
|
|
118
|
+
sifty checkup # one read-only scan of everything: junk, updates,
|
|
119
|
+
# orphans, stale files, disk space, startup
|
|
120
|
+
sifty tui # the full-screen interactive app
|
|
121
|
+
|
|
122
|
+
# Junk
|
|
123
|
+
sifty junk scan # show reclaimable space per category
|
|
124
|
+
sifty junk clean # preview removal (dry-run)
|
|
125
|
+
sifty junk clean --apply # send junk to the Recycle Bin (asks first)
|
|
126
|
+
|
|
127
|
+
# Disk
|
|
128
|
+
sifty disk volumes # used/free/total per volume
|
|
129
|
+
sifty disk analyze C:\Users # biggest folders/files under a path
|
|
130
|
+
sifty disk duplicates D:\ # find duplicate files and wasted space
|
|
131
|
+
|
|
132
|
+
# Apps & updates
|
|
133
|
+
sifty apps list --by-size # installed apps, largest first
|
|
134
|
+
sifty apps orphans # broken uninstall entries in the registry
|
|
135
|
+
sifty apps uninstall "App" # uninstall via winget (preview, then --apply)
|
|
136
|
+
sifty apps leftovers "App" # what the uninstaller left behind (then --apply)
|
|
137
|
+
sifty update check # available updates (winget)
|
|
138
|
+
sifty update apply # upgrade everything (asks first)
|
|
139
|
+
|
|
140
|
+
# Developer cleanup
|
|
141
|
+
sifty purge clean # node_modules, dist, __pycache__, target, …
|
|
142
|
+
sifty cleanup duplicates D:\Photos # de-duplicate (keeps one copy each)
|
|
143
|
+
sifty cleanup large C:\Users\you # biggest files under a path
|
|
144
|
+
sifty cleanup stale --days 180 # old items in Downloads
|
|
145
|
+
|
|
146
|
+
# Startup & services
|
|
147
|
+
sifty startup list # startup programs (enabled/disabled)
|
|
148
|
+
sifty startup disable "Spotify" # reversible (sifty startup enable …)
|
|
149
|
+
sifty services list # curated optional services + state
|
|
150
|
+
sifty --admin services disable DiagTrack # toggle one (needs admin)
|
|
151
|
+
|
|
152
|
+
# History & undo
|
|
153
|
+
sifty history # what was cleaned + total space reclaimed
|
|
154
|
+
sifty undo # restore the most recent clean from the Recycle Bin
|
|
155
|
+
|
|
156
|
+
# Organize files
|
|
157
|
+
sifty organize preview C:\Users\you\Downloads --by type
|
|
158
|
+
sifty organize apply C:\Users\you\Downloads --by date
|
|
159
|
+
sifty organize undo # put the last organize's files back
|
|
160
|
+
|
|
161
|
+
# Configuration
|
|
162
|
+
sifty config # all settings + which ones you've overridden
|
|
163
|
+
sifty config set ai.model "llama3.2:3b"
|
|
164
|
+
sifty config edit # open config.toml in your editor
|
|
165
|
+
|
|
166
|
+
# AI (requires Ollama running)
|
|
167
|
+
sifty ai status
|
|
168
|
+
sifty ai ask "what can I safely delete on my C drive?" --path C:\
|
|
169
|
+
|
|
170
|
+
# Scripting — JSON output on read-only commands (auto-enabled when piped)
|
|
171
|
+
sifty --json checkup
|
|
172
|
+
sifty --json disk volumes
|
|
173
|
+
sifty --json apps list --by-size
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Some operations (Windows temp, update cache, certain uninstalls) need an
|
|
177
|
+
**Administrator** terminal — `sifty doctor` tells you if you're elevated, and
|
|
178
|
+
`sifty --admin <cmd>` relaunches elevated via UAC.
|
|
179
|
+
|
|
180
|
+
## The TUI
|
|
181
|
+
|
|
182
|
+
`sifty tui` opens a full-screen app with a seven-section sidebar — Home,
|
|
183
|
+
Clean, Disk, Apps, Monitor, Reports, AI:
|
|
184
|
+
|
|
185
|
+
- **Home** — volume gauges and a **Run checkup** button that scans everything
|
|
186
|
+
at once; findings come with buttons that fix them right there (clean junk,
|
|
187
|
+
clean stale downloads, apply updates — each behind a confirm).
|
|
188
|
+
- **Clean** — Junk / Purge / Optimize / Smart cleanup under one roof (tabs).
|
|
189
|
+
- **Apps** — Installed / Updates / Startup / Services, with fuzzy filter,
|
|
190
|
+
sorting, bulk uninstall, and an automatic leftover scan after uninstalling.
|
|
191
|
+
- **AI** — an agentic chat: tool runs it proposes show **Run/Skip buttons
|
|
192
|
+
inline in the conversation**, and scan results carry follow-up action
|
|
193
|
+
buttons.
|
|
194
|
+
|
|
195
|
+
Press **Ctrl+P** for the command palette (jump to any screen), **F2** to
|
|
196
|
+
elevate, **Space** to mark rows for bulk actions. The **Reports** screen shows
|
|
197
|
+
space reclaimed over time with an **Undo last clean** button.
|
|
198
|
+
|
|
199
|
+
## AI setup (optional)
|
|
200
|
+
|
|
201
|
+
1. Install [Ollama] and start it.
|
|
202
|
+
2. Pull the configured model: `ollama pull qwen2.5:3b`.
|
|
203
|
+
3. `sifty ai status` should report "running".
|
|
204
|
+
|
|
205
|
+
Configure in `%APPDATA%\sifty\config.toml`:
|
|
206
|
+
|
|
207
|
+
```toml
|
|
208
|
+
[ai]
|
|
209
|
+
host = "http://localhost:11434"
|
|
210
|
+
model = "qwen2.5:3b"
|
|
211
|
+
|
|
212
|
+
[safety]
|
|
213
|
+
extra_protected_paths = ["D:\\Important"]
|
|
214
|
+
|
|
215
|
+
[junk]
|
|
216
|
+
include_downloads_installers = false
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Architecture
|
|
220
|
+
|
|
221
|
+
Layered — thin frontends over a reusable engine, OS specifics quarantined:
|
|
222
|
+
|
|
223
|
+
```text
|
|
224
|
+
src/sifty/
|
|
225
|
+
├── cli/ # Typer entry point + one thin command module per group
|
|
226
|
+
├── tui/ # Textual full-screen app (views call core, not cli)
|
|
227
|
+
├── core/ # the engine: junk, disk, apps, updates, cleanup,
|
|
228
|
+
│ │ # startup, services, organize, checkup, history, …
|
|
229
|
+
│ └── safety.py # ★ protected paths, dry-run guard, trash(), audit log
|
|
230
|
+
├── windows/ # OS primitives: winget, registry, UAC, Recycle Bin, DISM
|
|
231
|
+
├── ai/ # Ollama client, advisor prompts, agentic tool loop
|
|
232
|
+
└── infra/ # TOML config + rotating diagnostics log
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Frontends depend on `core`; `core` depends on `windows`/`infra`; nothing
|
|
236
|
+
imports upward. A GUI could call the same engine functions (`junk.scan`,
|
|
237
|
+
`disk.find_duplicates`, `checkup.run_checkup`) without a rewrite. See
|
|
238
|
+
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the design rationale.
|
|
239
|
+
|
|
240
|
+
## Tests
|
|
241
|
+
|
|
242
|
+
```powershell
|
|
243
|
+
.\.venv\Scripts\python.exe -m pytest -q # 160+ tests, ~20 s
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The safety guardrails are the most heavily tested code in the repo; the Windows
|
|
247
|
+
environment is mocked so the suite also runs on CI. See
|
|
248
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) to get involved.
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
[MIT](LICENSE) © Amine Zouaoui
|
|
253
|
+
|
|
254
|
+
[Ollama]: https://ollama.com
|
sifty-0.6.0/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Sifty
|
|
2
|
+
|
|
3
|
+
> An AI-assisted Windows maintenance CLI + TUI that **sifts the junk from the keep**.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
Clean junk, analyze disks, find duplicates, manage apps and startup programs,
|
|
11
|
+
apply updates, prune dev artifacts and git worktrees, and organize files — from
|
|
12
|
+
a scriptable CLI or a full-screen terminal UI. The optional AI assistant runs
|
|
13
|
+
**locally** via [Ollama]: nothing leaves your machine, and it only ever sees
|
|
14
|
+
file *metadata* (names, sizes, paths), never file contents.
|
|
15
|
+
|
|
16
|
+
<!-- TODO: add a demo GIF of `sifty tui` here — it sells the project better
|
|
17
|
+
than anything below. `textual run --dev` + any screen recorder works. -->
|
|
18
|
+
|
|
19
|
+
## Safety first
|
|
20
|
+
|
|
21
|
+
Sifty deletes files and changes system state, so it is built to be hard to misuse:
|
|
22
|
+
|
|
23
|
+
- **Dry-run by default** — every destructive command previews what it would do.
|
|
24
|
+
Real changes need an explicit `--apply`.
|
|
25
|
+
- **Recycle Bin, never permanent delete** — all removals go through one
|
|
26
|
+
`trash()` function backed by Send2Trash. `sifty undo` restores the last clean.
|
|
27
|
+
- **Protected paths** — `C:\Windows`, `Program Files`, `ProgramData`, the drive
|
|
28
|
+
root and your profile root are refused even with `--apply --yes`.
|
|
29
|
+
- **Audit log** — every applied deletion is recorded in `%APPDATA%\sifty\audit.log`.
|
|
30
|
+
- **The AI never deletes anything** — it is advisory; high-risk tool calls
|
|
31
|
+
always require your approval.
|
|
32
|
+
|
|
33
|
+
## How it compares
|
|
34
|
+
|
|
35
|
+
| Feature | Sifty | CCleaner | Revo Uninstaller | WinDirStat |
|
|
36
|
+
| --- | --- | --- | --- | --- |
|
|
37
|
+
| Junk / cache cleaning | ✅ 11+ categories | ✅ | ➖ | ❌ |
|
|
38
|
+
| Disk usage analysis | ✅ top-N + volumes | ➖ | ❌ | ✅ treemap |
|
|
39
|
+
| Duplicate finder | ✅ SHA-256, NTFS-aware | ✅ (paid) | ❌ | ❌ |
|
|
40
|
+
| App uninstall + leftover scan | ✅ winget + leftovers | ✅ | ✅ + leftovers | ❌ |
|
|
41
|
+
| App updates | ✅ via winget | ✅ (paid) | ❌ | ❌ |
|
|
42
|
+
| Startup manager | ✅ reversible | ✅ | ✅ | ❌ |
|
|
43
|
+
| Dev artifact purge (node_modules, …) | ✅ | ❌ | ❌ | ❌ |
|
|
44
|
+
| Git worktree / WSL2 VHD cleanup | ✅ | ❌ | ❌ | ❌ |
|
|
45
|
+
| Local AI assistant | ✅ Ollama | ❌ | ❌ | ❌ |
|
|
46
|
+
| Scriptable (JSON output) | ✅ | ❌ | ❌ | ❌ |
|
|
47
|
+
| Recycle Bin + undo for everything | ✅ | ➖ | ➖ | n/a |
|
|
48
|
+
| Price | Free, MIT | Freemium | Freemium | Free |
|
|
49
|
+
|
|
50
|
+
Sifty is built **developer-first**: everything is scriptable, the engine is a
|
|
51
|
+
reusable Python library, and it cleans the things developer machines actually
|
|
52
|
+
accumulate (build artifacts, orphaned worktrees, bloated WSL2 disks).
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
```powershell
|
|
57
|
+
# from source (recommended while pre-PyPI)
|
|
58
|
+
git clone https://github.com/Vortrix5/sifty && cd sifty
|
|
59
|
+
pipx install --editable . # or: pip install .
|
|
60
|
+
|
|
61
|
+
sifty doctor # check admin rights, winget, Ollama
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
For development:
|
|
65
|
+
|
|
66
|
+
```powershell
|
|
67
|
+
python -m venv .venv
|
|
68
|
+
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
|
|
69
|
+
.\.venv\Scripts\python.exe -m pytest -q
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Usage
|
|
73
|
+
|
|
74
|
+
```powershell
|
|
75
|
+
sifty checkup # one read-only scan of everything: junk, updates,
|
|
76
|
+
# orphans, stale files, disk space, startup
|
|
77
|
+
sifty tui # the full-screen interactive app
|
|
78
|
+
|
|
79
|
+
# Junk
|
|
80
|
+
sifty junk scan # show reclaimable space per category
|
|
81
|
+
sifty junk clean # preview removal (dry-run)
|
|
82
|
+
sifty junk clean --apply # send junk to the Recycle Bin (asks first)
|
|
83
|
+
|
|
84
|
+
# Disk
|
|
85
|
+
sifty disk volumes # used/free/total per volume
|
|
86
|
+
sifty disk analyze C:\Users # biggest folders/files under a path
|
|
87
|
+
sifty disk duplicates D:\ # find duplicate files and wasted space
|
|
88
|
+
|
|
89
|
+
# Apps & updates
|
|
90
|
+
sifty apps list --by-size # installed apps, largest first
|
|
91
|
+
sifty apps orphans # broken uninstall entries in the registry
|
|
92
|
+
sifty apps uninstall "App" # uninstall via winget (preview, then --apply)
|
|
93
|
+
sifty apps leftovers "App" # what the uninstaller left behind (then --apply)
|
|
94
|
+
sifty update check # available updates (winget)
|
|
95
|
+
sifty update apply # upgrade everything (asks first)
|
|
96
|
+
|
|
97
|
+
# Developer cleanup
|
|
98
|
+
sifty purge clean # node_modules, dist, __pycache__, target, …
|
|
99
|
+
sifty cleanup duplicates D:\Photos # de-duplicate (keeps one copy each)
|
|
100
|
+
sifty cleanup large C:\Users\you # biggest files under a path
|
|
101
|
+
sifty cleanup stale --days 180 # old items in Downloads
|
|
102
|
+
|
|
103
|
+
# Startup & services
|
|
104
|
+
sifty startup list # startup programs (enabled/disabled)
|
|
105
|
+
sifty startup disable "Spotify" # reversible (sifty startup enable …)
|
|
106
|
+
sifty services list # curated optional services + state
|
|
107
|
+
sifty --admin services disable DiagTrack # toggle one (needs admin)
|
|
108
|
+
|
|
109
|
+
# History & undo
|
|
110
|
+
sifty history # what was cleaned + total space reclaimed
|
|
111
|
+
sifty undo # restore the most recent clean from the Recycle Bin
|
|
112
|
+
|
|
113
|
+
# Organize files
|
|
114
|
+
sifty organize preview C:\Users\you\Downloads --by type
|
|
115
|
+
sifty organize apply C:\Users\you\Downloads --by date
|
|
116
|
+
sifty organize undo # put the last organize's files back
|
|
117
|
+
|
|
118
|
+
# Configuration
|
|
119
|
+
sifty config # all settings + which ones you've overridden
|
|
120
|
+
sifty config set ai.model "llama3.2:3b"
|
|
121
|
+
sifty config edit # open config.toml in your editor
|
|
122
|
+
|
|
123
|
+
# AI (requires Ollama running)
|
|
124
|
+
sifty ai status
|
|
125
|
+
sifty ai ask "what can I safely delete on my C drive?" --path C:\
|
|
126
|
+
|
|
127
|
+
# Scripting — JSON output on read-only commands (auto-enabled when piped)
|
|
128
|
+
sifty --json checkup
|
|
129
|
+
sifty --json disk volumes
|
|
130
|
+
sifty --json apps list --by-size
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Some operations (Windows temp, update cache, certain uninstalls) need an
|
|
134
|
+
**Administrator** terminal — `sifty doctor` tells you if you're elevated, and
|
|
135
|
+
`sifty --admin <cmd>` relaunches elevated via UAC.
|
|
136
|
+
|
|
137
|
+
## The TUI
|
|
138
|
+
|
|
139
|
+
`sifty tui` opens a full-screen app with a seven-section sidebar — Home,
|
|
140
|
+
Clean, Disk, Apps, Monitor, Reports, AI:
|
|
141
|
+
|
|
142
|
+
- **Home** — volume gauges and a **Run checkup** button that scans everything
|
|
143
|
+
at once; findings come with buttons that fix them right there (clean junk,
|
|
144
|
+
clean stale downloads, apply updates — each behind a confirm).
|
|
145
|
+
- **Clean** — Junk / Purge / Optimize / Smart cleanup under one roof (tabs).
|
|
146
|
+
- **Apps** — Installed / Updates / Startup / Services, with fuzzy filter,
|
|
147
|
+
sorting, bulk uninstall, and an automatic leftover scan after uninstalling.
|
|
148
|
+
- **AI** — an agentic chat: tool runs it proposes show **Run/Skip buttons
|
|
149
|
+
inline in the conversation**, and scan results carry follow-up action
|
|
150
|
+
buttons.
|
|
151
|
+
|
|
152
|
+
Press **Ctrl+P** for the command palette (jump to any screen), **F2** to
|
|
153
|
+
elevate, **Space** to mark rows for bulk actions. The **Reports** screen shows
|
|
154
|
+
space reclaimed over time with an **Undo last clean** button.
|
|
155
|
+
|
|
156
|
+
## AI setup (optional)
|
|
157
|
+
|
|
158
|
+
1. Install [Ollama] and start it.
|
|
159
|
+
2. Pull the configured model: `ollama pull qwen2.5:3b`.
|
|
160
|
+
3. `sifty ai status` should report "running".
|
|
161
|
+
|
|
162
|
+
Configure in `%APPDATA%\sifty\config.toml`:
|
|
163
|
+
|
|
164
|
+
```toml
|
|
165
|
+
[ai]
|
|
166
|
+
host = "http://localhost:11434"
|
|
167
|
+
model = "qwen2.5:3b"
|
|
168
|
+
|
|
169
|
+
[safety]
|
|
170
|
+
extra_protected_paths = ["D:\\Important"]
|
|
171
|
+
|
|
172
|
+
[junk]
|
|
173
|
+
include_downloads_installers = false
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Architecture
|
|
177
|
+
|
|
178
|
+
Layered — thin frontends over a reusable engine, OS specifics quarantined:
|
|
179
|
+
|
|
180
|
+
```text
|
|
181
|
+
src/sifty/
|
|
182
|
+
├── cli/ # Typer entry point + one thin command module per group
|
|
183
|
+
├── tui/ # Textual full-screen app (views call core, not cli)
|
|
184
|
+
├── core/ # the engine: junk, disk, apps, updates, cleanup,
|
|
185
|
+
│ │ # startup, services, organize, checkup, history, …
|
|
186
|
+
│ └── safety.py # ★ protected paths, dry-run guard, trash(), audit log
|
|
187
|
+
├── windows/ # OS primitives: winget, registry, UAC, Recycle Bin, DISM
|
|
188
|
+
├── ai/ # Ollama client, advisor prompts, agentic tool loop
|
|
189
|
+
└── infra/ # TOML config + rotating diagnostics log
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Frontends depend on `core`; `core` depends on `windows`/`infra`; nothing
|
|
193
|
+
imports upward. A GUI could call the same engine functions (`junk.scan`,
|
|
194
|
+
`disk.find_duplicates`, `checkup.run_checkup`) without a rewrite. See
|
|
195
|
+
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the design rationale.
|
|
196
|
+
|
|
197
|
+
## Tests
|
|
198
|
+
|
|
199
|
+
```powershell
|
|
200
|
+
.\.venv\Scripts\python.exe -m pytest -q # 160+ tests, ~20 s
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The safety guardrails are the most heavily tested code in the repo; the Windows
|
|
204
|
+
environment is mocked so the suite also runs on CI. See
|
|
205
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) to get involved.
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
[MIT](LICENSE) © Amine Zouaoui
|
|
210
|
+
|
|
211
|
+
[Ollama]: https://ollama.com
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sifty"
|
|
7
|
+
version = "0.6.0"
|
|
8
|
+
description = "Sifty — an AI-assisted Windows maintenance CLI/TUI: sift junk, analyze disks, manage apps, updates and files. Recycle Bin only, dry-run by default."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
authors = [{ name = "Amine Zouaoui" }]
|
|
12
|
+
license = { text = "MIT" }
|
|
13
|
+
keywords = [
|
|
14
|
+
"windows", "maintenance", "cleaner", "junk", "disk-usage", "duplicates",
|
|
15
|
+
"uninstaller", "winget", "tui", "textual", "ollama",
|
|
16
|
+
]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 4 - Beta",
|
|
19
|
+
"Environment :: Console",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Intended Audience :: End Users/Desktop",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Operating System :: Microsoft :: Windows",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"Programming Language :: Python :: 3.13",
|
|
28
|
+
"Topic :: System :: Systems Administration",
|
|
29
|
+
"Topic :: Utilities",
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"typer>=0.12",
|
|
33
|
+
"rich>=13.7",
|
|
34
|
+
"psutil>=5.9",
|
|
35
|
+
"send2trash>=1.8",
|
|
36
|
+
"pywin32>=306; sys_platform == 'win32'",
|
|
37
|
+
"winshell>=0.6; sys_platform == 'win32'",
|
|
38
|
+
"windows-toasts>=1.1; sys_platform == 'win32'",
|
|
39
|
+
"httpx>=0.27",
|
|
40
|
+
"textual>=0.60",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://github.com/Vortrix5/sifty"
|
|
45
|
+
Repository = "https://github.com/Vortrix5/sifty"
|
|
46
|
+
Issues = "https://github.com/Vortrix5/sifty/issues"
|
|
47
|
+
Changelog = "https://github.com/Vortrix5/sifty/blob/main/CHANGELOG.md"
|
|
48
|
+
|
|
49
|
+
[project.optional-dependencies]
|
|
50
|
+
dev = [
|
|
51
|
+
"pytest>=8.0",
|
|
52
|
+
"pytest-mock>=3.12",
|
|
53
|
+
"pytest-asyncio>=0.23",
|
|
54
|
+
"textual-dev>=1.5",
|
|
55
|
+
"ruff>=0.4",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[project.scripts]
|
|
59
|
+
sifty = "sifty.cli.app:entrypoint"
|
|
60
|
+
|
|
61
|
+
[tool.setuptools.packages.find]
|
|
62
|
+
where = ["src"]
|
|
63
|
+
|
|
64
|
+
[tool.setuptools.package-data]
|
|
65
|
+
sifty = ["tui/*.tcss"]
|
|
66
|
+
|
|
67
|
+
[tool.pytest.ini_options]
|
|
68
|
+
pythonpath = ["src"]
|
|
69
|
+
testpaths = ["tests"]
|
|
70
|
+
asyncio_mode = "auto"
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
line-length = 120
|
|
74
|
+
target-version = "py311"
|
|
75
|
+
src = ["src", "tests"]
|
|
76
|
+
|
|
77
|
+
[tool.ruff.lint]
|
|
78
|
+
select = ["E", "F", "W", "I", "UP", "B"]
|
|
79
|
+
ignore = [
|
|
80
|
+
"E501", # line length is advisory; Rich markup strings run long
|
|
81
|
+
"B008", # `typer.Option(...)` in defaults is Typer's standard idiom
|
|
82
|
+
]
|
sifty-0.6.0/setup.cfg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Local AI layer (Ollama) — advises, never acts on its own."""
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""AI advisory prompts.
|
|
2
|
+
|
|
3
|
+
The advisor only ever receives *metadata* — names, sizes, paths, extensions,
|
|
4
|
+
counts — never file contents. It explains and recommends; it never deletes.
|
|
5
|
+
The calling command does the acting, with the usual dry-run/confirm safeguards.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from .client import OllamaClient, OllamaUnavailable
|
|
11
|
+
|
|
12
|
+
SYSTEM_PROMPT = (
|
|
13
|
+
"You are Sifty, a careful Windows maintenance assistant embedded in a CLI/TUI "
|
|
14
|
+
"tool. You are given only file/app metadata, never file contents. Be concise, "
|
|
15
|
+
"practical, and cautious; when unsure whether something is safe to remove, say so. "
|
|
16
|
+
"Format answers in Markdown.\n\n"
|
|
17
|
+
"To remove an installed program, ALWAYS recommend a proper uninstall — Sifty's own "
|
|
18
|
+
"`apps` command (which uses winget under the hood), `winget uninstall`, or Windows "
|
|
19
|
+
"Settings > Apps. NEVER tell the user to manually delete a program's folder under "
|
|
20
|
+
"C:\\Program Files, C:\\Program Files (x86), or to hand-edit files in C:\\Windows, "
|
|
21
|
+
"ProgramData, or their personal documents — Sifty refuses those paths anyway, and "
|
|
22
|
+
"manual deletion leaves the registry and the system in a broken state. Do not "
|
|
23
|
+
"suggest `DISM` or `sfc /scannow` unless the user explicitly reports system file "
|
|
24
|
+
"corruption; they are not part of uninstalling an app.\n\n"
|
|
25
|
+
"Sifty deletes safely (to the Recycle Bin, dry-run by default), so point users at "
|
|
26
|
+
"Sifty's commands rather than destructive manual steps."
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Back-compat alias for internal callers.
|
|
30
|
+
_SYSTEM = SYSTEM_PROMPT
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _safe(client: OllamaClient, user_prompt: str) -> str | None:
|
|
34
|
+
"""Run a prompt, returning None if the AI is unavailable."""
|
|
35
|
+
if not client.is_available():
|
|
36
|
+
return None
|
|
37
|
+
try:
|
|
38
|
+
return client.chat(_SYSTEM, user_prompt)
|
|
39
|
+
except OllamaUnavailable:
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def explain_item(client: OllamaClient, name: str, path: str, size_human: str) -> str | None:
|
|
44
|
+
"""Explain what an item is and whether it's safe to remove."""
|
|
45
|
+
return _safe(
|
|
46
|
+
client,
|
|
47
|
+
f"What is this Windows item, and is it generally safe to delete?\n"
|
|
48
|
+
f"Name: {name}\nPath: {path}\nSize: {size_human}\n"
|
|
49
|
+
f"Answer in 2-3 sentences.",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def summarize_disk(client: OllamaClient, items: list[tuple[str, str]], question: str) -> str | None:
|
|
54
|
+
"""Answer a natural-language question about the biggest disk items."""
|
|
55
|
+
listing = "\n".join(f"- {name}: {size}" for name, size in items)
|
|
56
|
+
return _safe(
|
|
57
|
+
client,
|
|
58
|
+
f"Here are the largest items in a directory:\n{listing}\n\n"
|
|
59
|
+
f"User question: {question}\n"
|
|
60
|
+
f"Give a brief, practical answer and flag anything risky to delete.",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def suggest_organization(client: OllamaClient, sample_names: list[str]) -> str | None:
|
|
65
|
+
"""Propose a folder scheme for a messy directory from sample filenames."""
|
|
66
|
+
listing = "\n".join(f"- {n}" for n in sample_names[:40])
|
|
67
|
+
return _safe(
|
|
68
|
+
client,
|
|
69
|
+
f"These are sample filenames from a cluttered folder:\n{listing}\n\n"
|
|
70
|
+
f"Suggest a simple folder structure to organize them. Be concise.",
|
|
71
|
+
)
|