devcleaner-cli 1.0.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.
@@ -0,0 +1,223 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ *.lcov
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ cover/
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+ db.sqlite3-journal
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ # For a library or package, you might want to ignore these files since the code is
88
+ # intended to run in multiple environments; otherwise, check them in:
89
+ # .python-version
90
+
91
+ # pipenv
92
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
94
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
95
+ # install all needed dependencies.
96
+ # Pipfile.lock
97
+
98
+ # uv
99
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
100
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
101
+ # commonly ignored for libraries.
102
+ # uv.lock
103
+
104
+ # poetry
105
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
107
+ # commonly ignored for libraries.
108
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109
+ # poetry.lock
110
+ # poetry.toml
111
+
112
+ # pdm
113
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
114
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
115
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
116
+ # pdm.lock
117
+ # pdm.toml
118
+ .pdm-python
119
+ .pdm-build/
120
+
121
+ # pixi
122
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
123
+ # pixi.lock
124
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
125
+ # in the .venv directory. It is recommended not to include this directory in version control.
126
+ .pixi/*
127
+ !.pixi/config.toml
128
+
129
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
130
+ __pypackages__/
131
+
132
+ # Celery stuff
133
+ celerybeat-schedule*
134
+ celerybeat.pid
135
+
136
+ # Redis
137
+ *.rdb
138
+ *.aof
139
+ *.pid
140
+
141
+ # RabbitMQ
142
+ mnesia/
143
+ rabbitmq/
144
+ rabbitmq-data/
145
+
146
+ # ActiveMQ
147
+ activemq-data/
148
+
149
+ # SageMath parsed files
150
+ *.sage.py
151
+
152
+ # Environments
153
+ .env
154
+ .envrc
155
+ .venv
156
+ env/
157
+ venv/
158
+ ENV/
159
+ env.bak/
160
+ venv.bak/
161
+
162
+ # Spyder project settings
163
+ .spyderproject
164
+ .spyproject
165
+
166
+ # Rope project settings
167
+ .ropeproject
168
+
169
+ # mkdocs/Zensical documentation
170
+ /site
171
+
172
+ # mypy
173
+ .mypy_cache/
174
+ .dmypy.json
175
+ dmypy.json
176
+
177
+ # Pyre type checker
178
+ .pyre/
179
+
180
+ # pytype static type analyzer
181
+ .pytype/
182
+
183
+ # Cython debug symbols
184
+ cython_debug/
185
+
186
+ # PyCharm
187
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
188
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
189
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
190
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
191
+ # .idea/
192
+
193
+ # Abstra
194
+ # Abstra is an AI-powered process automation framework.
195
+ # Ignore directories containing user credentials, local state, and settings.
196
+ # Learn more at https://abstra.io/docs
197
+ .abstra/
198
+
199
+ # Visual Studio Code
200
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore that
201
+ # can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
202
+ # and can be added to the global gitignore or merged into this file. However, if you prefer, you
203
+ # could uncomment the following to ignore the entire vscode folder
204
+ # .vscode/
205
+ # Temporary file for partial code execution
206
+ tempCodeRunnerFile.py
207
+
208
+ # Ruff stuff:
209
+ .ruff_cache/
210
+
211
+ # PyPI configuration file
212
+ .pypirc
213
+
214
+ # Marimo
215
+ marimo/_static/
216
+ marimo/_lsp/
217
+ __marimo__/
218
+
219
+ # Streamlit
220
+ .streamlit/secrets.toml
221
+
222
+ # ide
223
+ .idea
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 adonesbalica
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.
@@ -0,0 +1,468 @@
1
+ Metadata-Version: 2.5
2
+ Name: devcleaner-cli
3
+ Version: 1.0.0
4
+ Summary: Remove generated directories such as node_modules, .next, and dist from every project in a workspace.
5
+ Project-URL: Homepage, https://github.com/adonesbalica/dev-cleaner
6
+ Project-URL: Repository, https://github.com/adonesbalica/dev-cleaner
7
+ Project-URL: Issues, https://github.com/adonesbalica/dev-cleaner/issues
8
+ Author-email: Adones Balica <adonesbalica@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: cleanup,cli,developer-tools,disk-space,node-modules,wsl
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Build Tools
21
+ Classifier: Topic :: System :: Filesystems
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.12
24
+ Provides-Extra: dev
25
+ Requires-Dist: build>=1.2; extra == 'dev'
26
+ Requires-Dist: ruff>=0.17; extra == 'dev'
27
+ Requires-Dist: twine>=5; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # dev-cleaner
31
+
32
+ A lightweight, cross-platform CLI tool to clean unnecessary directories from development projects.
33
+
34
+ `dev-cleaner` helps developers keep their workspaces clean by automatically detecting projects and removing generated or dependency directories such as `node_modules`, `.next`, and `dist`.
35
+
36
+ ## Table of contents
37
+
38
+ - [Features](#features)
39
+ - [Supported environments](#supported-environments)
40
+ - [Requirements](#requirements)
41
+ - [Installation](#installation)
42
+ - [Tutorial](#tutorial)
43
+ - [Usage](#usage)
44
+ - [Development](#development)
45
+ - [Project structure](#project-structure)
46
+ - [Architecture](#architecture)
47
+ - [Safety](#safety)
48
+ - [Troubleshooting](#troubleshooting)
49
+ - [License](#license)
50
+
51
+ ## Features
52
+
53
+ - **Cross-platform:** runs natively on Windows, Linux, and inside WSL.
54
+ - **Automatic backend selection:** the right filesystem implementation is picked from the workspace path.
55
+ - **Windows → WSL support:** clean Linux filesystems from Windows without leaving the terminal.
56
+ - **Configurable targets:** defaults to `node_modules`, `.next`, and `dist`, and accepts custom targets.
57
+ - **Safe by default:** asks for confirmation, supports `--dry-run`, skips symlinks and junctions, and refuses to scan a filesystem root.
58
+ - **Per-operation reporting:** failures are reported per project instead of aborting the whole run.
59
+ - **Live progress:** a spinner and elapsed timer show that a long cleanup is still running.
60
+ - **Installable:** published on PyPI as `devcleaner-cli` and exposes the `dev-cleaner` command.
61
+ - **No dependencies:** the CLI uses only the Python standard library.
62
+
63
+ ## Supported environments
64
+
65
+ | Where you run it | Workspace path | Backend |
66
+ |---|---|---|
67
+ | Windows | `C:\Users\me\workspace` | `native` (Windows filesystem) |
68
+ | Windows | `/home/me/workspace` | `wsl` (default distribution) |
69
+ | Windows | `//wsl.localhost/Ubuntu/home/me/workspace` | `wsl` (distribution taken from the path) |
70
+ | Linux | `/home/me/workspace` | `native` (Linux filesystem) |
71
+ | Inside WSL | `/home/me/workspace` or `/mnt/c/...` | `native` (Linux filesystem) |
72
+
73
+ The backend is detected automatically. Use `--backend` only to override the detection.
74
+
75
+ ## Requirements
76
+
77
+ - Python 3.12 or higher.
78
+ - WSL 2 with a Linux distribution such as Ubuntu (only when cleaning a Linux filesystem from Windows).
79
+
80
+ No third-party packages are required.
81
+
82
+ ## Installation
83
+
84
+ The package is published on PyPI as [`devcleaner-cli`](https://pypi.org/project/devcleaner-cli/) and installs the `dev-cleaner` command.
85
+
86
+ **pipx (recommended for CLI tools):**
87
+
88
+ ```bash
89
+ pipx install devcleaner-cli
90
+ ```
91
+
92
+ **uv:**
93
+
94
+ ```bash
95
+ uv tool install devcleaner-cli
96
+ ```
97
+
98
+ **pip:**
99
+
100
+ ```bash
101
+ python -m pip install --user devcleaner-cli
102
+ ```
103
+
104
+ On Windows, install pipx with `py -m pip install --user pipx` and run `py -m pipx ensurepath`, then reopen the terminal.
105
+
106
+ **From source:**
107
+
108
+ ```bash
109
+ git clone https://github.com/adonesbalica/dev-cleaner.git
110
+ cd dev-cleaner
111
+ pipx install .
112
+ ```
113
+
114
+ After installing, `dev-cleaner` works from any directory:
115
+
116
+ ```bash
117
+ dev-cleaner --version
118
+ ```
119
+
120
+ If the command is not found, reopen the terminal so the updated `PATH` is loaded, or run `python -m dev_cleaner`. The package has no runtime dependencies.
121
+
122
+ ## Tutorial
123
+
124
+ This walkthrough creates a throwaway workspace, so nothing real is deleted. It takes about two minutes.
125
+
126
+ ### 1. Create a practice workspace
127
+
128
+ **Windows (PowerShell):**
129
+
130
+ ```powershell
131
+ $demo = Join-Path $env:TEMP "dev-cleaner-demo"
132
+ New-Item -ItemType Directory -Force "$demo\app-a\node_modules\react" | Out-Null
133
+ New-Item -ItemType Directory -Force "$demo\app-a\dist" | Out-Null
134
+ New-Item -ItemType Directory -Force "$demo\app-b\.next" | Out-Null
135
+ New-Item -ItemType Directory -Force "$demo\app-c\src" | Out-Null
136
+ ```
137
+
138
+ **Linux or WSL:**
139
+
140
+ ```bash
141
+ demo="$(mktemp -d)"
142
+ mkdir -p "$demo/app-a/node_modules/react" "$demo/app-a/dist"
143
+ mkdir -p "$demo/app-b/.next" "$demo/app-c/src"
144
+ ```
145
+
146
+ You now have three projects: `app-a` and `app-b` contain generated directories, while `app-c` contains only source code.
147
+
148
+ ### 2. Preview the cleanup with a dry run
149
+
150
+ **Windows:**
151
+
152
+ ```powershell
153
+ dev-cleaner -w $demo -n
154
+ ```
155
+
156
+ **Linux or WSL:**
157
+
158
+ ```bash
159
+ dev-cleaner -w "$demo" -n
160
+ ```
161
+
162
+ Expected output:
163
+
164
+ ```text
165
+ dev-cleaner 1.0.0 | native | <workspace>
166
+
167
+ would remove app-a/node_modules
168
+ would remove app-a/dist
169
+ would remove app-b/.next
170
+
171
+ 3 matched (3 projects) [dry run]
172
+ ```
173
+
174
+ The first line shows the tool version, the selected backend, and the workspace you passed. Nothing has been deleted; the `[dry run]` marker confirms it. The order of the lines depends on the filesystem; the counts are what matter.
175
+
176
+ ### 3. Run the cleanup for real
177
+
178
+ Drop `-n` and add `-y` to skip the confirmation prompt:
179
+
180
+ ```bash
181
+ dev-cleaner -w "$demo" -y
182
+ ```
183
+
184
+ Expected output:
185
+
186
+ ```text
187
+ dev-cleaner 1.0.0 | native | <workspace>
188
+
189
+ removed app-a/node_modules
190
+ removed app-a/dist
191
+ removed app-b/.next
192
+
193
+ 3 removed (3 projects)
194
+ ```
195
+
196
+ On a real terminal, a single-line spinner and timer appear while the directories are removed, so a slow cleanup never looks frozen:
197
+
198
+ ```text
199
+ | cleaning app-a/node_modules (1/3) 0:04
200
+ ```
201
+
202
+ The line is erased when the run finishes, and the summary appends the total time when it took at least one second (for example `3 removed (3 projects) in 0:04`). When the output is piped or redirected, the spinner is skipped and only the final lines are written, which keeps the output easy to parse.
203
+
204
+ Without `-y`, the tool asks first:
205
+
206
+ ```text
207
+ Remove node_modules, .next, dist from every project? [y/N]
208
+ ```
209
+
210
+ Press `y` and Enter to continue, or Enter to cancel. The default is always **No**.
211
+
212
+ ### 4. Verify the result
213
+
214
+ **Windows:**
215
+
216
+ ```powershell
217
+ Get-ChildItem -Directory -Recurse $demo | Select-Object -ExpandProperty FullName
218
+ ```
219
+
220
+ **Linux or WSL:**
221
+
222
+ ```bash
223
+ find "$demo" -type d
224
+ ```
225
+
226
+ Only `app-a`, `app-b`, and `app-c` (plus `app-c/src`) should remain. The generated directories are gone.
227
+
228
+ ### 5. Remove the practice workspace
229
+
230
+ **Windows:**
231
+
232
+ ```powershell
233
+ Remove-Item $demo -Recurse -Force
234
+ ```
235
+
236
+ **Linux or WSL:**
237
+
238
+ ```bash
239
+ rm -rf "$demo"
240
+ ```
241
+
242
+ ### Tutorial: clean a WSL workspace from Windows
243
+
244
+ Use the Linux path of the workspace. The tool detects that it is not a Windows path and switches to the WSL backend automatically.
245
+
246
+ ```powershell
247
+ # See which distributions are available
248
+ wsl -l -q
249
+
250
+ # Preview the cleanup
251
+ dev-cleaner -w /home/me/workspace -n
252
+
253
+ # Use a specific distribution if the default is not the right one
254
+ dev-cleaner -w /home/me/workspace -d Ubuntu -n
255
+
256
+ # Run it
257
+ dev-cleaner -w /home/me/workspace -y
258
+ ```
259
+
260
+ The header shows which backend and distribution were selected:
261
+
262
+ ```text
263
+ dev-cleaner 1.0.0 | wsl:Ubuntu | /home/me/workspace
264
+ ```
265
+
266
+ You can also pass a Windows UNC path such as `//wsl.localhost/Ubuntu/home/me/workspace`; the distribution is read from the path.
267
+
268
+ ### Tutorial: use custom targets
269
+
270
+ Passing `-t` **replaces** the default target list, so list every directory you want to remove:
271
+
272
+ ```bash
273
+ dev-cleaner -w /home/me/workspace -t node_modules -t .venv -t target -n
274
+ ```
275
+
276
+ This removes only `node_modules`, `.venv`, and `target`; it does not also remove `.next` or `dist`.
277
+
278
+ ### Tutorial: use it in a script
279
+
280
+ Use `-y` so the command never waits for input, and check the exit code:
281
+
282
+ **Bash:**
283
+
284
+ ```bash
285
+ dev-cleaner -w /home/me/workspace -y
286
+ if [ $? -ne 0 ]; then
287
+ echo "cleanup failed" >&2
288
+ fi
289
+ ```
290
+
291
+ **PowerShell:**
292
+
293
+ ```powershell
294
+ dev-cleaner -w C:/Users/me/workspace -y
295
+ if ($LASTEXITCODE -ne 0) {
296
+ Write-Error "cleanup failed"
297
+ }
298
+ ```
299
+
300
+ ## Usage
301
+
302
+ ```bash
303
+ dev-cleaner -w <workspace> [options]
304
+ ```
305
+
306
+ ### Options
307
+
308
+ | Option | Description |
309
+ |---|---|
310
+ | `-w`, `--workspace` | Workspace directory to scan. Required. |
311
+ | `-t`, `--target` | Directory to remove. Repeatable; replaces the defaults. Defaults to `node_modules`, `.next`, `dist`. |
312
+ | `-b`, `--backend` | Force `native` or `wsl`. Auto-detected by default. |
313
+ | `-d`, `--distribution` | WSL distribution to use. Defaults to the WSL default distribution, or `Ubuntu`. |
314
+ | `-n`, `--dry-run` | Show what would be removed without deleting anything. |
315
+ | `-y`, `--yes` | Do not ask for confirmation. |
316
+ | `--version` | Show the version and exit. |
317
+
318
+ ### Progress indicator
319
+
320
+ While scanning or deleting, the CLI shows one animated line with the directory being removed and an elapsed timer:
321
+
322
+ ```text
323
+ / cleaning app-a/node_modules (2/7) 0:12
324
+ ```
325
+
326
+ - The spinner uses plain ASCII frames (`|`, `/`, `-`, `\`), so it works in any terminal.
327
+ - The status updates before **each directory** is removed, so the name changes even when a single project takes a long time.
328
+ - The timer uses `m:ss`, switching to `h:mm:ss` after one hour.
329
+ - The line is cleared before the per-directory results are printed.
330
+ - The summary appends `in m:ss` when the run took at least one second.
331
+ - The spinner is **TTY-only**. Piped or redirected output never contains the animation, so logs and scripts stay clean.
332
+
333
+ ### Exit codes
334
+
335
+ | Code | Meaning |
336
+ |---|---|
337
+ | `0` | Success, including "nothing to remove" and a cancelled prompt. |
338
+ | `1` | Error: invalid workspace, invalid target, failed removal, or WSL unavailable. |
339
+ | `2` | Invalid command-line arguments. |
340
+ | `130` | Interrupted with Ctrl+C. |
341
+
342
+ ### How it works
343
+
344
+ 1. Detects the backend from the workspace path (unless `--backend` is given).
345
+ 2. Maps the workspace to a scan path and, for WSL, to the equivalent Linux path.
346
+ 3. Lists the direct children of the workspace as projects.
347
+ 4. Checks each project for the configured target directories.
348
+ 5. Removes matching directories using the selected backend, reporting every operation.
349
+
350
+ Only direct children of the workspace are treated as projects, and only direct children of each project are removed. Symlinked projects and targets, as well as Windows directory junctions, are skipped.
351
+
352
+ ## Development
353
+
354
+ Clone the repository and create a virtual environment:
355
+
356
+ ```bash
357
+ git clone https://github.com/adonesbalica/dev-cleaner.git
358
+ cd dev-cleaner
359
+ python -m venv .venv
360
+ ```
361
+
362
+ Activate it:
363
+
364
+ **Windows (PowerShell):**
365
+
366
+ ```powershell
367
+ .venv\Scripts\Activate.ps1
368
+ ```
369
+
370
+ **Linux / WSL:**
371
+
372
+ ```bash
373
+ source .venv/bin/activate
374
+ ```
375
+
376
+ Install the package in editable mode with the development tools:
377
+
378
+ ```bash
379
+ python -m pip install -e ".[dev]"
380
+ ```
381
+
382
+ Run the CLI without the console script:
383
+
384
+ ```bash
385
+ python -m dev_cleaner --help
386
+ ```
387
+
388
+ Run the checks and build the distribution:
389
+
390
+ ```bash
391
+ ruff check src
392
+ ruff format --check src
393
+ python -m build
394
+ ```
395
+
396
+ The build writes `dist/devcleaner_cli-<version>-py3-none-any.whl` and a source archive. See [RELEASING.md](https://github.com/adonesbalica/dev-cleaner/blob/main/RELEASING.md) for the publish steps.
397
+
398
+ ## Project structure
399
+
400
+ ```text
401
+ dev-cleaner/
402
+ ├── src/
403
+ │ └── dev_cleaner/
404
+ │ ├── __init__.py
405
+ │ ├── __main__.py
406
+ │ ├── main.py
407
+ │ ├── core/
408
+ │ │ ├── __init__.py
409
+ │ │ └── cleaner.py
410
+ │ ├── cleaners/
411
+ │ │ ├── __init__.py
412
+ │ │ ├── base.py
413
+ │ │ ├── native.py
414
+ │ │ └── wsl.py
415
+ │ └── cli/
416
+ │ ├── __init__.py
417
+ │ ├── interface.py
418
+ │ └── parser.py
419
+ ├── pyproject.toml
420
+ ├── README.md
421
+ ├── RELEASING.md
422
+ ├── LICENSE
423
+ └── .gitignore
424
+ ```
425
+
426
+ ## Architecture
427
+
428
+ The project uses a strategy-based architecture to separate cleanup orchestration from filesystem operations.
429
+
430
+ - **`FileSystemCleaner`:** defines the contract for filesystem cleanup implementations.
431
+ - **`NativeCleaner`:** uses `shutil.rmtree` on the filesystem the application runs on (Windows or Linux), including retries for read-only files.
432
+ - **`WslCleaner`:** runs `wsl -d <distribution> -- rm -rf` to remove directories inside a Linux filesystem from Windows.
433
+ - **`Cleaner`:** handles workspace scanning, project detection, WSL path mapping, dry runs, and cleanup orchestration.
434
+ - **`main.py`:** detects the backend, resolves the workspace paths, and wires everything together.
435
+ - **`cli/`:** parses arguments, shows the TTY-only spinner and timer, and prints plain-text results, a summary, and the confirmation prompt. No third-party dependencies.
436
+
437
+ This design allows new filesystem cleanup implementations to be added without changing the core cleanup logic.
438
+
439
+ ## Safety
440
+
441
+ Directory removal is permanent.
442
+
443
+ Before running the application, make sure that:
444
+
445
+ - The workspace path is correct.
446
+ - The target directories are the ones you intend to remove.
447
+ - The selected backend matches your environment.
448
+
449
+ Use `--dry-run` first to review what will be removed. Symlinked projects and targets are skipped, and the tool refuses to scan a filesystem root. Only direct children of the workspace are considered, so pointing `-w` at a folder that contains projects is safer than pointing it at a single project.
450
+
451
+ ## Troubleshooting
452
+
453
+ | Problem | Cause and fix |
454
+ |---|---|
455
+ | `Error: Workspace not found: ...` | The path is wrong, or the WSL distribution is not running. Check the path and run `wsl -l -q` to see available distributions. |
456
+ | `Error: The wsl backend requires Windows with WSL installed.` | You forced `-b wsl` on Linux. Remove `-b wsl`; Linux paths already work with the native backend. |
457
+ | `Error: Refusing to scan a filesystem root: ...` | Pass the folder that contains your projects, not `/`, `C:\`, or a WSL distribution root. |
458
+ | `Error: Invalid target directory: ...` | Targets must be a single directory name. Do not use paths such as `src/dist` or `..`. |
459
+ | `failed ... [WinError 32]` or `Permission denied` | A file is open or read-only. Close editors, dev servers, and terminals using the directory, then retry. |
460
+ | Nothing is removed | Only direct children of the workspace are scanned. Point `-w` at the folder containing your project folders. |
461
+ | Paths with spaces do not work | Quote the path: `-w "C:/Users/me/My Projects"`. |
462
+ | Colors look wrong or appear as escape codes | Set `NO_COLOR=1`, or use a terminal with ANSI support. |
463
+ | No spinner or timer appears | The spinner is TTY-only. It is hidden when output is piped or redirected, and when `TERM=dumb`. Run the tool directly in a terminal to see it. |
464
+ | `dev-cleaner` is not recognized | Install it with `pipx install devcleaner-cli` or `uv tool install devcleaner-cli`, then reopen the terminal so `PATH` is updated. You can always run `python -m dev_cleaner` instead. |
465
+
466
+ ## License
467
+
468
+ This project is licensed under the MIT License.