claude-cleaner 1.0.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 David
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.
package/README.md ADDED
@@ -0,0 +1,245 @@
1
+ # Claude Cleaner
2
+
3
+ [![CI](https://github.com/ePlus-DEV/claude-cleaner/actions/workflows/ci.yml/badge.svg)](https://github.com/ePlus-DEV/claude-cleaner/actions/workflows/ci.yml)
4
+ [![Release](https://img.shields.io/github/v/release/ePlus-DEV/claude-cleaner)](https://github.com/ePlus-DEV/claude-cleaner/releases)
5
+ [![npm version](https://img.shields.io/npm/v/claude-cleaner.svg)](https://www.npmjs.com/package/claude-cleaner)
6
+ [![Go version](https://img.shields.io/github/go-mod/go-version/ePlus-DEV/claude-cleaner)](go.mod)
7
+ [![Go Report Card](https://goreportcard.com/badge/github.com/ePlus-DEV/claude-cleaner)](https://goreportcard.com/report/github.com/ePlus-DEV/claude-cleaner)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
9
+
10
+ **Claude Cleaner** is an interactive terminal UI — built with [Bubble Tea](https://github.com/charmbracelet/bubbletea) and [Lip Gloss](https://github.com/charmbracelet/lipgloss) — that inspects Claude Code project session history, displays disk usage, and safely deletes only the sessions you select.
11
+
12
+ Runs on Windows, macOS, and Linux. No runtime required when using a pre-built binary.
13
+
14
+ ![Full demo](demo/full.gif)
15
+
16
+ ## Demos
17
+
18
+ | Scenario | Preview |
19
+ | --- | --- |
20
+ | `--help` | ![Help](demo/help.gif) |
21
+ | Delete a session | ![Full flow](demo/full.gif) |
22
+ | Cancel confirmation | ![Cancel](demo/cancel.gif) |
23
+ | In-place update | ![Update](demo/update.gif) |
24
+
25
+ ## Features
26
+
27
+ - Reads project list from `~/.claude.json` — shows all projects Claude Code knows about, even those with no local session files.
28
+ - Displays **token usage** per project (from `lastTotal*` fields in `~/.claude.json`), formatted as K / M / B / T / P / E.
29
+ - Status column `●` (session files on disk) / `○` (config only, no local data).
30
+ - Windows path dedup — `d:/foo` and `D:/foo` treated as the same project; higher-token entry wins.
31
+ - Multi-select with `space`, select all with `a`, confirm with `enter`.
32
+ - Three deletion modes: session-files delete, full **purge** (via `claude project purge`), and instant **force-purge** (`x`).
33
+ - Live progress bar during deletion.
34
+ - Claude CLI integration — tries `claude project purge` first, falls back to direct removal.
35
+ - Auto update check against npm registry on startup; `u` to update in-place.
36
+ - Claude CLI presence and version shown in header.
37
+ - `r` to rescan at any time.
38
+ - `q` quits from every screen.
39
+ - Rejects paths outside the Claude `projects` directory.
40
+ - Concurrent filesystem scanning.
41
+ - Supports custom Claude configuration directories via `--claude-dir` or `CLAUDE_CONFIG_DIR`.
42
+
43
+ ## What it deletes
44
+
45
+ Only project session folders directly inside `~/.claude/projects` (or `$CLAUDE_CONFIG_DIR/projects`).
46
+
47
+ These folders contain Claude Code session and conversation history. Source code directories are never touched.
48
+
49
+ ### Deletion modes
50
+
51
+ | Mode | Key | Confirm | Scope | How |
52
+ | --- | --- | --- | --- | --- |
53
+ | Delete | `enter` | ✓ screen | selected items | tries `claude project purge -y <path>`, falls back to `os.RemoveAll` |
54
+ | Purge | `p` | ✓ screen | selected items | same as delete, confirm text emphasises full purge |
55
+ | Force-purge | `x` | ✗ | cursor item only | same deletion chain, no confirm screen |
56
+ | Delete all | `a` then `enter` | ✓ screen | all items | uses `claude project purge --all -y` (single call), then cleans remaining folders |
57
+
58
+ All modes validate that the target path is inside the Claude projects directory before deleting.
59
+
60
+ ## Install
61
+
62
+ ### Run without installing
63
+
64
+ ```bash
65
+ npx claude-cleaner
66
+ ```
67
+
68
+ ### Install globally
69
+
70
+ ```bash
71
+ npm install --global claude-cleaner
72
+ claude-cleaner
73
+ ```
74
+
75
+ > The npm package is a thin wrapper. On install it automatically downloads the correct pre-built binary for your platform from GitHub Releases. No Go required.
76
+
77
+ ### Download binary directly
78
+
79
+ Go to [Releases](https://github.com/ePlus-DEV/claude-cleaner/releases), download the archive for your platform, extract, and run.
80
+
81
+ | Platform | File |
82
+ | --- | --- |
83
+ | Linux x64 | `claude-cleaner_*_linux_amd64.tar.gz` |
84
+ | Linux ARM64 | `claude-cleaner_*_linux_arm64.tar.gz` |
85
+ | macOS x64 | `claude-cleaner_*_darwin_amd64.tar.gz` |
86
+ | macOS Apple Silicon | `claude-cleaner_*_darwin_arm64.tar.gz` |
87
+ | Windows x64 | `claude-cleaner_*_windows_amd64.zip` |
88
+ | Windows ARM64 | `claude-cleaner_*_windows_arm64.zip` |
89
+
90
+ ### Install with Go
91
+
92
+ ```bash
93
+ go install github.com/ePlus-DEV/claude-cleaner@latest
94
+ ```
95
+
96
+ ### Build from source
97
+
98
+ ```bash
99
+ git clone https://github.com/ePlus-DEV/claude-cleaner.git
100
+ cd claude-cleaner
101
+ go build -o claude-cleaner .
102
+ ./claude-cleaner
103
+ ```
104
+
105
+ ## Usage
106
+
107
+ ```bash
108
+ claude-cleaner
109
+ claude-cleaner --claude-dir "/path/to/.claude"
110
+ claude-cleaner --help
111
+ claude-cleaner --version
112
+ ```
113
+
114
+ ### Options
115
+
116
+ ```text
117
+ --claude-dir <path> Custom Claude config directory (default: ~/.claude)
118
+ --mock-update Simulate a newer version available (for testing the update flow)
119
+ -h, --help Show help
120
+ -v, --version Show version
121
+ ```
122
+
123
+ ### Key bindings
124
+
125
+ | Key | Action |
126
+ | --- | --- |
127
+ | `↑` / `↓` or `j` / `k` | Navigate list |
128
+ | `space` | Toggle selection |
129
+ | `enter` | Proceed — show delete confirm (when items selected) |
130
+ | `a` | Select all / deselect all |
131
+ | `p` | Purge selected (confirm screen, purge mode) |
132
+ | `x` | Force-purge item at cursor — no confirm |
133
+ | `r` | Rescan / refresh project list |
134
+ | `u` | Update claude-cleaner in-place (shown when update available) |
135
+ | `esc` | Go back / cancel |
136
+ | `q` / `ctrl+c` | Quit (works on every screen) |
137
+
138
+ ## Configure a custom Claude directory
139
+
140
+ Priority order: `--claude-dir` > `CLAUDE_CONFIG_DIR` > `~/.claude`
141
+
142
+ ```bash
143
+ # macOS / Linux
144
+ export CLAUDE_CONFIG_DIR="/mnt/data/claude"
145
+ claude-cleaner
146
+ ```
147
+
148
+ ```powershell
149
+ # Windows PowerShell
150
+ $env:CLAUDE_CONFIG_DIR = "D:\ClaudeData"
151
+ claude-cleaner
152
+ ```
153
+
154
+ ## Troubleshooting
155
+
156
+ **Claude directory not found** — Run Claude Code at least once so the directory is created, or point to the correct path:
157
+
158
+ ```bash
159
+ claude-cleaner --claude-dir "/correct/path/.claude"
160
+ ```
161
+
162
+ **Permission denied** — Run as the same OS user that owns the Claude config directory.
163
+
164
+ **Binary not found after `npx`** — Try reinstalling:
165
+
166
+ ```bash
167
+ npm install --global claude-cleaner
168
+ ```
169
+
170
+ **Windows: `Access is denied` when running `go run .`** — Windows locks the temp executable while it's in use. Kill any other running instances, or build once and run the binary directly:
171
+
172
+ ```powershell
173
+ go build -o claude-cleaner.exe .
174
+ .\claude-cleaner.exe
175
+ ```
176
+
177
+ ## Development
178
+
179
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for full setup, build, and release instructions.
180
+
181
+ ### Requirements
182
+
183
+ - [Go 1.22+](https://go.dev/dl/)
184
+ - [Node.js 20+](https://nodejs.org/) (only for seed data / demo GIFs)
185
+
186
+ ### Quick start
187
+
188
+ ```bash
189
+ git clone https://github.com/ePlus-DEV/claude-cleaner.git
190
+ cd claude-cleaner
191
+ go mod tidy
192
+ ```
193
+
194
+ ### Run in dev (without installing Claude)
195
+
196
+ Use the included seed script to create fake session data for testing:
197
+
198
+ ```bash
199
+ # macOS / Linux
200
+ node demo/seed.js /tmp/claude-demo
201
+ go run . --claude-dir /tmp/claude-demo
202
+ ```
203
+
204
+ ```powershell
205
+ # Windows
206
+ node demo/seed.js $env:TEMP\claude-demo
207
+ go run . --claude-dir $env:TEMP\claude-demo
208
+ ```
209
+
210
+ This creates 5 fake project sessions of various sizes — enough to test all TUI flows (navigate, select, delete, cancel) without touching any real Claude data.
211
+
212
+ ### Common commands
213
+
214
+ ```bash
215
+ go mod tidy # install / tidy dependencies
216
+ go build -o claude-cleaner . # build binary
217
+ go run . # run without building
218
+ go test -v ./... # run tests
219
+ go run . --version # smoke test
220
+ ```
221
+
222
+ ## CI / CD
223
+
224
+ | Workflow | Trigger | What it does |
225
+ | --- | --- | --- |
226
+ | [ci.yml](.github/workflows/ci.yml) | push / PR | Go tests on 1.22, 1.23, 1.24 × Windows, macOS, Linux |
227
+ | [release.yml](.github/workflows/release.yml) | push `v*` tag | GoReleaser builds binaries → GitHub Release → npm publish |
228
+ | [demo.yml](.github/workflows/demo.yml) | push to main (Go / tape files) | Regenerates demo GIFs via VHS |
229
+
230
+ ### Publishing a release
231
+
232
+ ```bash
233
+ npm version patch # or minor / major
234
+ git push --follow-tags
235
+ ```
236
+
237
+ `npm version` automatically syncs the version to `main.go` and creates a git tag. Pushing the tag triggers GoReleaser and npm publish.
238
+
239
+ ## Contributing
240
+
241
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
242
+
243
+ ## License
244
+
245
+ [MIT](LICENSE) © ePlus.DEV
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "claude-cleaner",
3
+ "version": "1.0.0",
4
+ "description": "Safely inspect and delete selected Claude Code project session history from an interactive cross-platform TUI.",
5
+ "bin": {
6
+ "claude-cleaner": "scripts/run.js"
7
+ },
8
+ "scripts": {
9
+ "postinstall": "node scripts/install.js",
10
+ "version": "node scripts/sync-version.js && git add main.go"
11
+ },
12
+ "files": [
13
+ "scripts",
14
+ "README.md",
15
+ "LICENSE"
16
+ ],
17
+ "keywords": [
18
+ "claude",
19
+ "claude-code",
20
+ "cleaner",
21
+ "cleanup",
22
+ "session",
23
+ "session-cleaner",
24
+ "history",
25
+ "cli",
26
+ "cross-platform"
27
+ ],
28
+ "author": "David",
29
+ "license": "MIT",
30
+ "engines": {
31
+ "node": ">=20"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/ePlus-DEV/claude-cleaner.git"
36
+ },
37
+ "bugs": {
38
+ "url": "https://github.com/ePlus-DEV/claude-cleaner/issues"
39
+ },
40
+ "homepage": "https://github.com/ePlus-DEV/claude-cleaner#readme",
41
+ "publishConfig": {
42
+ "access": "public",
43
+ "registry": "https://registry.npmjs.org/"
44
+ }
45
+ }
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { spawnSync } = require("node:child_process");
5
+ const fs = require("node:fs");
6
+ const https = require("node:https");
7
+ const os = require("node:os");
8
+ const path = require("node:path");
9
+
10
+ const pkg = require("../package.json");
11
+
12
+ const PLATFORMS = { linux: "linux", darwin: "darwin", win32: "windows" };
13
+ const ARCHS = { x64: "amd64", arm64: "arm64" };
14
+
15
+ const platform = PLATFORMS[process.platform];
16
+ const arch = ARCHS[process.arch];
17
+
18
+ if (!platform || !arch) {
19
+ console.warn(`claude-cleaner: unsupported platform ${process.platform}/${process.arch}, skipping binary download.`);
20
+ process.exit(0);
21
+ }
22
+
23
+ const isWindows = platform === "windows";
24
+ const binaryName = isWindows ? "claude-cleaner.exe" : "claude-cleaner";
25
+ const ext = isWindows ? ".zip" : ".tar.gz";
26
+ const archive = `claude-cleaner_${pkg.version}_${platform}_${arch}${ext}`;
27
+ const url = `https://github.com/ePlus-DEV/claude-cleaner/releases/download/v${pkg.version}/${archive}`;
28
+
29
+ const binDir = path.join(__dirname, "..", "bin");
30
+ const binaryPath = path.join(binDir, binaryName);
31
+
32
+ if (fs.existsSync(binaryPath)) process.exit(0);
33
+
34
+ fs.mkdirSync(binDir, { recursive: true });
35
+
36
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "csc-"));
37
+ const archivePath = path.join(tmpDir, archive);
38
+
39
+ console.log(`Downloading claude-cleaner v${pkg.version} (${platform}/${arch})…`);
40
+
41
+ download(url, archivePath)
42
+ .then(() => {
43
+ extract(archivePath, tmpDir);
44
+ const src = path.join(tmpDir, binaryName);
45
+ fs.copyFileSync(src, binaryPath);
46
+ if (!isWindows) fs.chmodSync(binaryPath, 0o755);
47
+ fs.rmSync(tmpDir, { recursive: true, force: true });
48
+ console.log("claude-cleaner: ready.");
49
+ })
50
+ .catch((err) => {
51
+ fs.rmSync(tmpDir, { recursive: true, force: true });
52
+ console.warn(`claude-cleaner: download failed — ${err.message}`);
53
+ console.warn(`Manual install: ${url}`);
54
+ process.exit(0); // never block npm install
55
+ });
56
+
57
+ function download(url, dest) {
58
+ return new Promise((resolve, reject) => {
59
+ const file = fs.createWriteStream(dest);
60
+ const get = (u) =>
61
+ https
62
+ .get(u, { headers: { "User-Agent": "node" } }, (res) => {
63
+ if (res.statusCode === 301 || res.statusCode === 302) return get(res.headers.location);
64
+ if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}`));
65
+ res.pipe(file);
66
+ file.on("finish", () => file.close(resolve));
67
+ file.on("error", reject);
68
+ })
69
+ .on("error", reject);
70
+ get(url);
71
+ });
72
+ }
73
+
74
+ function extract(archivePath, destDir) {
75
+ let result;
76
+ if (isWindows) {
77
+ result = spawnSync("powershell", [
78
+ "-NoProfile", "-Command",
79
+ `Expand-Archive -Path "${archivePath}" -DestinationPath "${destDir}" -Force`,
80
+ ]);
81
+ } else {
82
+ result = spawnSync("tar", ["-xzf", archivePath, "-C", destDir], { stdio: "pipe" });
83
+ }
84
+ if (result.status !== 0) throw new Error("extraction failed");
85
+ }
package/scripts/run.js ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { spawnSync } = require("node:child_process");
5
+ const fs = require("node:fs");
6
+ const path = require("node:path");
7
+
8
+ const isWindows = process.platform === "win32";
9
+ const binaryName = isWindows ? "claude-cleaner.exe" : "claude-cleaner";
10
+ const binaryPath = path.join(__dirname, "..", "bin", binaryName);
11
+
12
+ if (!fs.existsSync(binaryPath)) {
13
+ console.error("claude-cleaner: binary not found. Reinstall:");
14
+ console.error(" npm install -g claude-cleaner");
15
+ process.exit(1);
16
+ }
17
+
18
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
19
+ stdio: "inherit",
20
+ windowsHide: false,
21
+ });
22
+
23
+ process.exit(result.status ?? 1);
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+
7
+ const pkg = require("../package.json");
8
+ const mainGoPath = path.join(__dirname, "..", "main.go");
9
+
10
+ let src = fs.readFileSync(mainGoPath, "utf8");
11
+ src = src.replace(/var version = ".*?"/, `var version = "${pkg.version}"`);
12
+ fs.writeFileSync(mainGoPath, src);
13
+
14
+ console.log(`version synced → ${pkg.version}`);