nm-wipe 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,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Boopathy Ganesh K
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
13
+ all 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
21
+ THE SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # nm-wipe
2
+
3
+ Interactive `node_modules` cleaner CLI for macOS and Linux.
4
+
5
+ `nm-wipe` scans a directory tree for `node_modules` folders, lets you interactively filter and select them, and then deletes them (or simulates deletion in dry‑run mode). It’s designed to safely reclaim disk space from old projects.
6
+
7
+ > **Warning**
8
+ > This tool deletes directories. Always start with `--dry-run` until you’re comfortable with what it will remove.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install -g nm-wipe
14
+ # or
15
+ pnpm add -g nm-wipe
16
+ # or
17
+ yarn global add nm-wipe
18
+ ```
19
+
20
+ After installation you’ll have an `nm-wipe` binary on your PATH.
21
+
22
+ ## Usage
23
+
24
+ ```bash
25
+ nm-wipe [root] [--dry-run]
26
+ ```
27
+
28
+ - **`root`** (optional): directory to scan.
29
+ - Defaults to your desktop: `~/Desktop`.
30
+ - **`--dry-run`**: simulate deletions without removing anything.
31
+ - **`--help` / `-h`**: show help.
32
+ - **`--version` / `-v`**: show version.
33
+
34
+ ### Examples
35
+
36
+ ```bash
37
+ # Safely preview what would be deleted under ~/Desktop
38
+ nm-wipe --dry-run
39
+
40
+ # Scan a specific projects folder (recommended: first run with --dry-run)
41
+ nm-wipe ~/dev --dry-run
42
+
43
+ # Actually delete selected node_modules under ~/dev
44
+ nm-wipe ~/dev
45
+ ```
46
+
47
+ ## Interactive flow
48
+
49
+ 1. **Scan**: `nm-wipe` scans `root` (default `~/Desktop`) up to a configurable depth for `node_modules` folders.
50
+ 2. **Filter & sort**:
51
+ - Filter by:
52
+ - **Path segment** (e.g. `Axon`, `core`, `cenizaslabs-ai`).
53
+ - **Size** (e.g. `>500M`, `<1G`, `>2G`).
54
+ - **Age** (last modified) (e.g. `30d`, `6m`, `1y`).
55
+ - Sort by:
56
+ - Writable first (default).
57
+ - Size (largest / smallest first).
58
+ - Path A→Z.
59
+ 3. **Select**:
60
+ - Use the checkbox UI to select which `node_modules` folders to delete.
61
+ - Read‑only or no‑access directories are shown but disabled.
62
+ 4. **Confirm**:
63
+ - `nm-wipe` shows how many folders are selected and an approximate total size to be freed.
64
+ - You must confirm before anything is deleted.
65
+ 5. **Wipe**:
66
+ - Deletions run one by one with a progress spinner.
67
+ - Failures are reported and can be retried.
68
+
69
+ ## Environment variables
70
+
71
+ - **`WIPEIT_DEPTH`**
72
+ Maximum directory depth to scan from the root (default `8`, hard‑capped at `50`).
73
+
74
+ ```bash
75
+ WIPEIT_DEPTH=12 nm-wipe ~/dev --dry-run
76
+ ```
77
+
78
+ ## Safety characteristics
79
+
80
+ - Never follows symlinks.
81
+ - Never recurses into `node_modules` contents (only removes the directory itself).
82
+ - Uses filesystem permission checks to show whether a directory is writable, read‑only, or not accessible.
83
+ - Uses `du -sh` to estimate sizes; timeouts and permission errors degrade gracefully without crashing the CLI.
84
+
85
+ ## Development
86
+
87
+ This repo uses TypeScript and ships compiled JavaScript in `dist/`.
88
+
89
+ Prerequisites:
90
+
91
+ - Node.js **18+**
92
+
93
+ Install dependencies (recommended: `bun`, but `npm`/`pnpm` also work):
94
+
95
+ ```bash
96
+ bun install
97
+ ```
98
+
99
+ Build and stamp the CLI:
100
+
101
+ ```bash
102
+ bun run build
103
+ bun run postbuild
104
+ ```
105
+
106
+ Run in dev mode (TS directly with tsx):
107
+
108
+ ```bash
109
+ bun run dev
110
+ ```
111
+
112
+ Run the built CLI locally:
113
+
114
+ ```bash
115
+ node dist/index.js --dry-run
116
+ ```
117
+
118
+ ## License
119
+
120
+ MIT © Boopathy Ganesh K
121
+
@@ -0,0 +1,5 @@
1
+ import type { AccessStatus } from './types.js';
2
+ export declare function getSize(dirPath: string): Promise<string>;
3
+ export declare function checkAccess(dirPath: string): Promise<AccessStatus>;
4
+ export declare function getMtime(dirPath: string): Promise<number>;
5
+ //# sourceMappingURL=fs-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-utils.d.ts","sourceRoot":"","sources":["../src/fs-utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAoB/C,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9D;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAYxE;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO/D"}
@@ -0,0 +1,50 @@
1
+ import fs from 'fs';
2
+ import { spawn } from 'child_process';
3
+ /** Run `du -sh <path>` safely using spawn (no shell, no injection risk). */
4
+ function duSize(dirPath) {
5
+ return new Promise((resolve) => {
6
+ const chunks = [];
7
+ const proc = spawn('du', ['-sh', dirPath], { stdio: ['ignore', 'pipe', 'ignore'] });
8
+ proc.stdout.on('data', (chunk) => chunks.push(chunk));
9
+ proc.on('close', () => {
10
+ const out = Buffer.concat(chunks).toString('utf8');
11
+ resolve(out.split('\t')[0]?.trim() ?? '?');
12
+ });
13
+ proc.on('error', () => resolve('?'));
14
+ // Kill if takes too long
15
+ setTimeout(() => { proc.kill(); resolve('?'); }, 8_000).unref();
16
+ });
17
+ }
18
+ export async function getSize(dirPath) {
19
+ try {
20
+ return await duSize(dirPath);
21
+ }
22
+ catch {
23
+ return '?';
24
+ }
25
+ }
26
+ export async function checkAccess(dirPath) {
27
+ try {
28
+ await fs.promises.access(dirPath, fs.constants.W_OK);
29
+ return 'writable';
30
+ }
31
+ catch {
32
+ try {
33
+ await fs.promises.access(dirPath, fs.constants.R_OK);
34
+ return 'readonly';
35
+ }
36
+ catch {
37
+ return 'noaccess';
38
+ }
39
+ }
40
+ }
41
+ export async function getMtime(dirPath) {
42
+ try {
43
+ const stat = await fs.promises.stat(dirPath);
44
+ return stat.mtimeMs;
45
+ }
46
+ catch {
47
+ return 0;
48
+ }
49
+ }
50
+ //# sourceMappingURL=fs-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-utils.js","sourceRoot":"","sources":["../src/fs-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAGtC,4EAA4E;AAC5E,SAAS,MAAM,CAAC,OAAe;IAC7B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEpF,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9D,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACpB,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAErC,yBAAyB;QACzB,UAAU,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAe;IAC3C,IAAI,CAAC;QACH,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAe;IAC/C,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrD,OAAO,UAAU,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,UAAU,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAe;IAC5C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,595 @@
1
+ #!/usr/bin/env node
2
+ import { checkbox, confirm, input, select } from '@inquirer/prompts';
3
+ import chalk from 'chalk';
4
+ import ora from 'ora';
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import os from 'os';
8
+ import { logger, LOG_FILE } from './logger.js';
9
+ import { scan } from './scanner.js';
10
+ import { checkAccess, getSize, getMtime } from './fs-utils.js';
11
+ import { DEFAULT_FILTERS } from './types.js';
12
+ // ── CLI args ──────────────────────────────────────────────────────────────────
13
+ const rawArgs = process.argv.slice(2);
14
+ const DRY_RUN = rawArgs.includes('--dry-run');
15
+ const pathArg = rawArgs.find((a) => !a.startsWith('-'));
16
+ if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
17
+ console.log(`
18
+ wipeit — interactive node_modules cleaner
19
+
20
+ Usage:
21
+ wipeit [path] [--dry-run]
22
+
23
+ Options:
24
+ path Root directory to scan (default: ~/Desktop)
25
+ --dry-run Preview what would be deleted without removing anything
26
+ --help Show this help
27
+ --version Show version
28
+ `);
29
+ process.exit(0);
30
+ }
31
+ if (rawArgs.includes('--version') || rawArgs.includes('-v')) {
32
+ const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
33
+ console.log(pkg.version);
34
+ process.exit(0);
35
+ }
36
+ // ── Config ────────────────────────────────────────────────────────────────────
37
+ const KNOWN_FLAGS = new Set(['--dry-run', '--help', '-h', '--version', '-v']);
38
+ const unknownFlags = rawArgs.filter((a) => a.startsWith('-') && !KNOWN_FLAGS.has(a));
39
+ if (unknownFlags.length > 0) {
40
+ console.error(chalk.yellow(` Warning: unknown flag(s): ${unknownFlags.join(', ')}`));
41
+ console.error(chalk.dim(` Run \`wipeit --help\` to see valid options.\n`));
42
+ }
43
+ const DEFAULT_ROOT = path.join(os.homedir(), 'Desktop');
44
+ const ROOT = path.resolve(pathArg ?? DEFAULT_ROOT);
45
+ const _rawDepth = parseInt(process.env['WIPEIT_DEPTH'] ?? '8', 10);
46
+ const MAX_DEPTH = Number.isFinite(_rawDepth) && _rawDepth > 0 ? Math.min(_rawDepth, 50) : 8;
47
+ const HOME = os.homedir();
48
+ const COLS = process.stdout.columns ?? 100;
49
+ const CONCURRENCY = 8;
50
+ // ── Pure helpers ──────────────────────────────────────────────────────────────
51
+ function rel(p) {
52
+ return p.replace(HOME, '~');
53
+ }
54
+ function truncate(s, maxLen) {
55
+ return s.length <= maxLen ? s : `…${s.slice(-(maxLen - 1))}`;
56
+ }
57
+ function parseBytes(s) {
58
+ const m = s.match(/^([\d.]+)\s*([KMGT]?)B?$/i);
59
+ if (!m)
60
+ return 0;
61
+ const n = parseFloat(m[1] ?? '0');
62
+ switch ((m[2] ?? '').toUpperCase()) {
63
+ case 'K': return n * 1_024;
64
+ case 'M': return n * 1_024 ** 2;
65
+ case 'G': return n * 1_024 ** 3;
66
+ case 'T': return n * 1_024 ** 4;
67
+ default: return n;
68
+ }
69
+ }
70
+ function formatBytes(bytes) {
71
+ if (bytes >= 1_024 ** 3)
72
+ return `${(bytes / 1_024 ** 3).toFixed(1)} GB`;
73
+ if (bytes >= 1_024 ** 2)
74
+ return `${(bytes / 1_024 ** 2).toFixed(1)} MB`;
75
+ if (bytes >= 1_024)
76
+ return `${(bytes / 1_024).toFixed(1)} KB`;
77
+ return `${bytes} B`;
78
+ }
79
+ /** Returns null if input is invalid so callers can warn the user. */
80
+ function parseSizeFilter(raw) {
81
+ const m = raw.trim().match(/^([<>]?)([\d.]+)\s*([KMGT]?)B?$/i);
82
+ if (!m)
83
+ return null;
84
+ const bytes = parseBytes(`${m[2] ?? '0'}${m[3] ?? ''}`);
85
+ if (!Number.isFinite(bytes) || bytes <= 0)
86
+ return null;
87
+ if (m[1] === '<')
88
+ return { minBytes: 0, maxBytes: bytes };
89
+ return { minBytes: bytes, maxBytes: Infinity };
90
+ }
91
+ /** Returns null if input is invalid so callers can warn the user. */
92
+ function parseAgeFilter(raw) {
93
+ const m = raw.trim().match(/^>?(\d+)\s*([dmy])$/i);
94
+ if (!m)
95
+ return null;
96
+ const n = parseInt(m[1] ?? '0', 10);
97
+ if (!Number.isFinite(n) || n <= 0)
98
+ return null;
99
+ const DAY = 86_400_000;
100
+ switch ((m[2] ?? '').toLowerCase()) {
101
+ case 'd': return n * DAY;
102
+ case 'm': return n * 30 * DAY;
103
+ case 'y': return n * 365 * DAY;
104
+ default: return null;
105
+ }
106
+ }
107
+ // ── Filter / sort helpers ─────────────────────────────────────────────────────
108
+ function applyFilters(items, filters) {
109
+ return items.filter((item) => {
110
+ if (filters.path) {
111
+ const p = rel(path.dirname(item.nmPath)).toLowerCase();
112
+ if (!p.includes(filters.path.toLowerCase()))
113
+ return false;
114
+ }
115
+ const bytes = parseBytes(item.size);
116
+ if (filters.minBytes > 0 && bytes < filters.minBytes)
117
+ return false;
118
+ if (filters.maxBytes < Infinity && bytes > filters.maxBytes)
119
+ return false;
120
+ if (filters.olderThanMs > 0 && item.mtimeMs > 0) {
121
+ if (Date.now() - item.mtimeMs < filters.olderThanMs)
122
+ return false;
123
+ }
124
+ return true;
125
+ });
126
+ }
127
+ function sortItems(items, sort) {
128
+ return [...items].sort((a, b) => {
129
+ switch (sort) {
130
+ case 'size-desc': return parseBytes(b.size) - parseBytes(a.size);
131
+ case 'size-asc': return parseBytes(a.size) - parseBytes(b.size);
132
+ case 'path': return a.nmPath.localeCompare(b.nmPath);
133
+ default: {
134
+ if (a.access === 'writable' && b.access !== 'writable')
135
+ return -1;
136
+ if (a.access !== 'writable' && b.access === 'writable')
137
+ return 1;
138
+ return 0;
139
+ }
140
+ }
141
+ });
142
+ }
143
+ function describeFilters(f) {
144
+ const parts = [];
145
+ if (f.path)
146
+ parts.push(`path="${f.path}"`);
147
+ if (f.minBytes > 0)
148
+ parts.push(`size>${formatBytes(f.minBytes)}`);
149
+ if (f.maxBytes < Infinity)
150
+ parts.push(`size<${formatBytes(f.maxBytes)}`);
151
+ if (f.olderThanMs > 0)
152
+ parts.push(`age>${Math.round(f.olderThanMs / 86_400_000)}d`);
153
+ return parts.join(' ');
154
+ }
155
+ function hasFilters(f) {
156
+ return !!(f.path || f.minBytes > 0 || f.maxBytes < Infinity || f.olderThanMs > 0);
157
+ }
158
+ // ── UI builders ───────────────────────────────────────────────────────────────
159
+ function statusBadge(access) {
160
+ switch (access) {
161
+ case 'writable': return { badge: chalk.green('✓ writable '), disabled: false };
162
+ case 'readonly': return { badge: chalk.yellow('⚠ read-only'), disabled: 'read-only — cannot delete' };
163
+ case 'noaccess': return { badge: chalk.red('✗ no access'), disabled: 'no access — permission denied' };
164
+ }
165
+ }
166
+ async function buildScanItem(nmPath) {
167
+ const [access, size, mtimeMs] = await Promise.all([
168
+ checkAccess(nmPath),
169
+ getSize(nmPath),
170
+ getMtime(nmPath),
171
+ ]);
172
+ const { badge, disabled } = statusBadge(access);
173
+ const maxPathLen = Math.max(20, COLS - 22 - 4);
174
+ const pathCol = truncate(rel(path.dirname(nmPath)), maxPathLen);
175
+ const sizeCol = chalk.cyan(size.padStart(7));
176
+ const choiceName = `${badge} ${sizeCol} ${pathCol}`;
177
+ return { nmPath, access, size, mtimeMs, choiceName, disabled };
178
+ }
179
+ // ── Concurrency-limited item builder ─────────────────────────────────────────
180
+ async function buildItemsConcurrently(found, onProgress) {
181
+ const results = new Array(found.length);
182
+ let done = 0;
183
+ await Promise.all(Array.from({ length: Math.min(CONCURRENCY, found.length) }, async (_, worker) => {
184
+ let i = worker;
185
+ while (i < found.length) {
186
+ results[i] = await buildScanItem(found[i]);
187
+ onProgress(++done, found.length);
188
+ i += CONCURRENCY;
189
+ }
190
+ }));
191
+ return results.filter((r) => r !== undefined);
192
+ }
193
+ // ── Scan ──────────────────────────────────────────────────────────────────────
194
+ async function runScan(root) {
195
+ const scanSpinner = ora({
196
+ text: 'Scanning… 0 found', color: 'cyan', spinner: {
197
+ frames: ['✢', '✣', '✤', '✱', '✲', '✳', '✴', '✶', '✷', '✸', '✻'],
198
+ interval: 150,
199
+ }
200
+ }).start();
201
+ const scanStart = Date.now();
202
+ const found = await scan(root, MAX_DEPTH, (_p, total) => {
203
+ scanSpinner.text = `Scanning… ${chalk.cyan(total)} found`;
204
+ });
205
+ const scanMs = Date.now() - scanStart;
206
+ scanSpinner.succeed(`Scan complete — ${chalk.cyan(found.length)} found ${chalk.dim(`(${scanMs}ms)`)}`);
207
+ logger.info(`Scan complete — ${found.length} found in ${scanMs}ms`);
208
+ found.forEach((p) => logger.info(` FOUND ${p}`));
209
+ if (found.length === 0)
210
+ return [];
211
+ const chkSpinner = ora({
212
+ text: `Checking 0 / ${found.length}`, color: 'cyan', spinner: {
213
+ frames: ['✢', '✣', '✤', '✱', '✲', '✳', '✴', '✶', '✷', '✸', '✻'],
214
+ interval: 150,
215
+ }
216
+ }).start();
217
+ const items = await buildItemsConcurrently(found, (done, total) => {
218
+ chkSpinner.text = `Checking permissions & sizes… ${chalk.cyan(done)} / ${total}`;
219
+ });
220
+ chkSpinner.succeed(`Permissions & sizes checked ${chalk.dim(`(${found.length} entries)`)}`);
221
+ items.forEach((i) => logger.info(` CHECK ${i.nmPath} access=${i.access} size=${i.size}`));
222
+ return items;
223
+ }
224
+ // ── Filter submenu ────────────────────────────────────────────────────────────
225
+ async function promptFilters(current) {
226
+ const filters = { ...current };
227
+ while (true) {
228
+ const sizeDesc = filters.minBytes > 0
229
+ ? `>${formatBytes(filters.minBytes)}`
230
+ : filters.maxBytes < Infinity
231
+ ? `<${formatBytes(filters.maxBytes)}`
232
+ : null;
233
+ const ageDesc = filters.olderThanMs > 0
234
+ ? `>${Math.round(filters.olderThanMs / 86_400_000)}d`
235
+ : null;
236
+ const action = await select({
237
+ message: 'Filters',
238
+ choices: [
239
+ { name: `⌕ Path ${filters.path ? chalk.yellow(filters.path) : chalk.dim('(none)')}`, value: 'path' },
240
+ { name: `📦 Size ${sizeDesc ? chalk.yellow(sizeDesc) : chalk.dim('(none)')}`, value: 'size' },
241
+ { name: `📅 Age ${ageDesc ? chalk.yellow(ageDesc) : chalk.dim('(none — e.g. older than N months)')}`, value: 'age' },
242
+ { name: `✕ Clear all filters`, value: 'clear' },
243
+ { name: `← Back`, value: 'back' },
244
+ ],
245
+ });
246
+ if (action === 'back')
247
+ return filters;
248
+ if (action === 'clear') {
249
+ Object.assign(filters, DEFAULT_FILTERS);
250
+ continue;
251
+ }
252
+ if (action === 'path') {
253
+ filters.path = await input({
254
+ message: 'Filter by path segment (e.g. Axon · core · cenizaslabs-ai):',
255
+ default: filters.path,
256
+ });
257
+ continue;
258
+ }
259
+ if (action === 'size') {
260
+ const raw = await input({ message: 'Size (e.g. >500M >1G <100M — blank to clear):' });
261
+ if (!raw.trim()) {
262
+ filters.minBytes = 0;
263
+ filters.maxBytes = Infinity;
264
+ }
265
+ else {
266
+ const parsed = parseSizeFilter(raw);
267
+ if (!parsed) {
268
+ console.log(chalk.red(` Invalid size format: "${raw}". Use e.g. >500M, <1G, >2G`));
269
+ logger.warn(`Invalid size filter input: "${raw}"`);
270
+ }
271
+ else {
272
+ filters.minBytes = parsed.minBytes;
273
+ filters.maxBytes = parsed.maxBytes;
274
+ }
275
+ }
276
+ continue;
277
+ }
278
+ if (action === 'age') {
279
+ const raw = await input({ message: 'Older than (e.g. 30d · 6m · 1y — blank to clear):' });
280
+ if (!raw.trim()) {
281
+ filters.olderThanMs = 0;
282
+ }
283
+ else {
284
+ const parsed = parseAgeFilter(raw);
285
+ if (parsed === null) {
286
+ console.log(chalk.red(` Invalid age format: "${raw}". Use e.g. 30d, 6m, 1y`));
287
+ logger.warn(`Invalid age filter input: "${raw}"`);
288
+ }
289
+ else {
290
+ filters.olderThanMs = parsed;
291
+ }
292
+ }
293
+ continue;
294
+ }
295
+ }
296
+ }
297
+ const SORT_LABELS = {
298
+ 'access': 'writable first',
299
+ 'size-desc': 'size ↓',
300
+ 'size-asc': 'size ↑',
301
+ 'path': 'path A→Z',
302
+ };
303
+ let _isScanning = false; // HIGH 6 — guard against concurrent rescans
304
+ async function runPreMenu(initialItems, initialFilters, initialSort) {
305
+ let items = initialItems;
306
+ let filters = initialFilters;
307
+ let sort = initialSort;
308
+ while (true) {
309
+ const filtered = applyFilters(items, filters);
310
+ const filterDesc = describeFilters(filters);
311
+ const countSuffix = hasFilters(filters)
312
+ ? chalk.yellow(filterDesc) + chalk.dim(` ${filtered.length} / ${items.length}`)
313
+ : chalk.dim(`${items.length} found`);
314
+ const action = await select({
315
+ message: `wipeit · ${countSuffix}${DRY_RUN ? chalk.yellow(' [dry-run]') : ''}`,
316
+ choices: [
317
+ { name: `${chalk.green('▶')} Browse & select`, value: 'select' },
318
+ { name: `${chalk.yellow('⌕')} Filters ${hasFilters(filters) ? chalk.yellow(`[${filterDesc}]`) : chalk.dim('(none)')}`, value: 'filters' },
319
+ { name: `${chalk.magenta('⇅')} Sort ${chalk.dim(SORT_LABELS[sort])}`, value: 'sort' },
320
+ { name: `${chalk.blue('↺')} Rescan directory`, value: 'rescan' },
321
+ { name: `${chalk.red('✕')} Exit`, value: 'exit' },
322
+ ],
323
+ });
324
+ if (action === 'exit') {
325
+ const ok = await confirm({ message: 'Exit wipeit?', default: false });
326
+ if (ok)
327
+ return { next: 'exit' };
328
+ continue;
329
+ }
330
+ if (action === 'filters') {
331
+ filters = await promptFilters(filters);
332
+ continue;
333
+ }
334
+ if (action === 'sort') {
335
+ sort = await select({
336
+ message: 'Sort by',
337
+ choices: [
338
+ { name: 'Writable first (default)', value: 'access' },
339
+ { name: 'Size: largest first', value: 'size-desc' },
340
+ { name: 'Size: smallest first', value: 'size-asc' },
341
+ { name: 'Path A→Z', value: 'path' },
342
+ ],
343
+ });
344
+ continue;
345
+ }
346
+ if (action === 'rescan') {
347
+ if (_isScanning) {
348
+ console.log(chalk.yellow(' Already scanning — please wait…'));
349
+ continue;
350
+ }
351
+ logger.info('Rescan triggered by user');
352
+ _isScanning = true;
353
+ try {
354
+ items = await runScan(ROOT);
355
+ }
356
+ finally {
357
+ _isScanning = false;
358
+ }
359
+ continue;
360
+ }
361
+ // 'select'
362
+ return { next: 'select', items, filters, sort };
363
+ }
364
+ }
365
+ // ── Checkbox ──────────────────────────────────────────────────────────────────
366
+ async function runCheckbox(filtered, preselect) {
367
+ console.log('\n ' + chalk.gray('Legend:') + ' ' +
368
+ chalk.green('✓ writable') + ' ' +
369
+ chalk.yellow('⚠ read-only') + ' ' +
370
+ chalk.red('✗ no access') + '\n');
371
+ return checkbox({
372
+ message: 'Select node_modules (↑↓ navigate · space select · a all · ⏎ submit):',
373
+ choices: filtered.map(({ choiceName, nmPath, disabled }) => ({
374
+ name: choiceName,
375
+ value: nmPath,
376
+ disabled,
377
+ checked: preselect.includes(nmPath),
378
+ })),
379
+ pageSize: 15,
380
+ });
381
+ }
382
+ // ── Post-selection menu ───────────────────────────────────────────────────────
383
+ async function runPostMenu(selected, items) {
384
+ const projectedBytes = selected.reduce((sum, p) => sum + parseBytes(items.find((i) => i.nmPath === p)?.size ?? '0'), 0);
385
+ return select({
386
+ message: `${chalk.bold(selected.length)} selected` +
387
+ (projectedBytes > 0 ? ` · ~${chalk.cyan(formatBytes(projectedBytes))} to free` : ''),
388
+ choices: [
389
+ { name: `${chalk.green('✓')} Proceed with deletion`, value: 'proceed' },
390
+ { name: `${chalk.cyan('⇄')} Invert selection`, value: 'invert' },
391
+ { name: `${chalk.gray('←')} Back`, value: 'back' },
392
+ ],
393
+ });
394
+ }
395
+ // ── Selection state machine ───────────────────────────────────────────────────
396
+ async function runSelectionLoop(initialItems) {
397
+ let items = initialItems;
398
+ let filters = { ...DEFAULT_FILTERS };
399
+ let sort = 'access';
400
+ let preselect = [];
401
+ let filtered = [];
402
+ let stage = 'premenu';
403
+ let selected = [];
404
+ while (true) {
405
+ if (stage === 'premenu') {
406
+ const result = await runPreMenu(items, filters, sort);
407
+ if (result.next === 'exit')
408
+ return [];
409
+ // Update state from pre-menu result
410
+ items = result.items;
411
+ filters = result.filters;
412
+ sort = result.sort;
413
+ filtered = sortItems(applyFilters(items, filters), sort);
414
+ preselect = []; // fresh selection when entering checkbox from pre-menu
415
+ stage = 'checkbox';
416
+ continue;
417
+ }
418
+ if (stage === 'checkbox') {
419
+ selected = await runCheckbox(filtered, preselect);
420
+ preselect = [];
421
+ stage = selected.length === 0 ? 'premenu' : 'postmenu';
422
+ continue;
423
+ }
424
+ if (stage === 'postmenu') {
425
+ const action = await runPostMenu(selected, items);
426
+ if (action === 'proceed')
427
+ return selected;
428
+ if (action === 'invert') {
429
+ const writableInView = filtered.filter((i) => i.access === 'writable').map((i) => i.nmPath);
430
+ preselect = writableInView.filter((p) => !selected.includes(p));
431
+ logger.info(`Invert: ${preselect.length} items preselected`);
432
+ stage = 'checkbox';
433
+ continue;
434
+ }
435
+ // 'back' → home screen, clear preselect
436
+ preselect = [];
437
+ stage = 'premenu';
438
+ continue;
439
+ }
440
+ }
441
+ }
442
+ // ── Wipe (with retry on failure) ──────────────────────────────────────────────
443
+ async function runWipe(toWipe, sizeMap) {
444
+ const spinner = ora({
445
+ color: 'cyan', spinner: {
446
+ frames: ['✢', '✣', '✤', '✱', '✲', '✳', '✴', '✶', '✷', '✸', '✻'],
447
+ interval: 150,
448
+ }
449
+ });
450
+ const succeeded = [];
451
+ const failed = [];
452
+ for (const nmPath of toWipe) {
453
+ const label = rel(nmPath);
454
+ const isDryRun = DRY_RUN;
455
+ spinner.start(isDryRun ? chalk.dim(`[dry-run] ${label}`) : chalk.gray(`Wiping ${label}`));
456
+ const start = Date.now();
457
+ try {
458
+ if (!isDryRun) {
459
+ const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error('Timed out after 30s — path may be on a frozen mount')), 30_000).unref());
460
+ await Promise.race([fs.promises.rm(nmPath, { recursive: true }), timeout]);
461
+ }
462
+ const durationMs = Date.now() - start;
463
+ const prefix = isDryRun ? chalk.yellow('[dry-run] ') : '';
464
+ spinner.succeed(prefix + chalk.green('Deleted ') + label + chalk.dim(` (${durationMs}ms)`));
465
+ const result = { nmPath, success: true, durationMs };
466
+ succeeded.push(result);
467
+ logger.info(` DELETED ${nmPath} (${durationMs}ms)${isDryRun ? ' [dry-run]' : ''}`);
468
+ }
469
+ catch (err) {
470
+ const durationMs = Date.now() - start;
471
+ const error = err instanceof Error ? err.message : String(err);
472
+ spinner.fail(chalk.red('Failed ') + label + chalk.gray(` (${error})`));
473
+ const result = { nmPath, success: false, durationMs, error };
474
+ failed.push(result);
475
+ logger.error(` FAILED ${nmPath} (${durationMs}ms) ${error}`);
476
+ }
477
+ }
478
+ // Offer retry for failures — deduplicate paths to prevent double-deletion
479
+ if (failed.length > 0 && !DRY_RUN) {
480
+ console.log('');
481
+ const retry = await confirm({
482
+ message: `${failed.length} deletion${failed.length > 1 ? 's' : ''} failed — retry?`,
483
+ default: true,
484
+ });
485
+ if (retry) {
486
+ const seen = new Set(succeeded.map((r) => r.nmPath));
487
+ const retryPaths = [...new Set(failed.map((r) => r.nmPath))].filter((p) => !seen.has(p));
488
+ const { succeeded: rs, failed: rf } = await runWipe(retryPaths, sizeMap);
489
+ return { succeeded: [...succeeded, ...rs], failed: rf };
490
+ }
491
+ }
492
+ return { succeeded, failed };
493
+ }
494
+ // ── Signal handlers ───────────────────────────────────────────────────────────
495
+ function handleSignal(signal) {
496
+ logger.warn(`Process received ${signal} — exiting cleanly`);
497
+ logger.separator();
498
+ logger.close().finally(() => {
499
+ console.log(chalk.yellow(`\n Interrupted (${signal}). Exiting.\n`));
500
+ process.exit(1);
501
+ });
502
+ }
503
+ process.on('SIGTERM', () => handleSignal('SIGTERM'));
504
+ process.on('SIGINT', () => handleSignal('SIGINT'));
505
+ // ── Main ──────────────────────────────────────────────────────────────────────
506
+ async function main() {
507
+ logger.separator();
508
+ logger.info(`Session start`);
509
+ logger.info(`Scan root : ${ROOT}`);
510
+ logger.info(`Max depth : ${MAX_DEPTH}`);
511
+ logger.info(`Dry run : ${DRY_RUN}`);
512
+ logger.info(`Log file : ${LOG_FILE}`);
513
+ console.log(chalk.bold(`\n wipeit — node_modules cleaner${DRY_RUN ? chalk.yellow(' [dry-run]') : ''}\n`));
514
+ console.log(` ${chalk.gray('Root')} ${chalk.white(rel(ROOT))}` +
515
+ (!pathArg ? chalk.dim(' (default · pass a path to override)') : ''));
516
+ console.log(` ${chalk.gray('Log')} ${chalk.dim(LOG_FILE)}\n`);
517
+ // CRITICAL 2 — Validate ROOT before scanning
518
+ try {
519
+ const stat = await fs.promises.stat(ROOT);
520
+ if (!stat.isDirectory()) {
521
+ console.error(chalk.red(` Error: "${rel(ROOT)}" is not a directory.\n`));
522
+ process.exit(1);
523
+ }
524
+ }
525
+ catch {
526
+ console.error(chalk.red(` Error: "${rel(ROOT)}" does not exist or is not accessible.\n`));
527
+ process.exit(1);
528
+ }
529
+ const items = await runScan(ROOT);
530
+ if (items.length === 0) {
531
+ logger.warn('No node_modules found. Exiting.');
532
+ console.log(chalk.yellow('\n No node_modules directories found.\n'));
533
+ return;
534
+ }
535
+ const selected = await runSelectionLoop(items);
536
+ if (selected.length === 0) {
537
+ logger.warn('Nothing selected. Exiting.');
538
+ console.log(chalk.yellow('\n Nothing selected. Exiting.\n'));
539
+ return;
540
+ }
541
+ selected.forEach((p) => logger.info(` SELECTED ${p}`));
542
+ // Final confirmation
543
+ const projectedBytes = selected.reduce((sum, p) => sum + parseBytes(items.find((i) => i.nmPath === p)?.size ?? '0'), 0);
544
+ console.log('');
545
+ const confirmed = await confirm({
546
+ message: `${DRY_RUN ? chalk.yellow('[dry-run] ') : ''}Delete ${selected.length} node_modules` +
547
+ (projectedBytes > 0 ? ` (~${formatBytes(projectedBytes)})` : '') + '?',
548
+ default: false,
549
+ });
550
+ if (!confirmed) {
551
+ logger.warn('User aborted at confirmation.');
552
+ console.log(chalk.yellow('\n Aborted.\n'));
553
+ return;
554
+ }
555
+ logger.info('Confirmed. Starting wipe...');
556
+ console.log('');
557
+ // Snapshot sizes at confirmation time — insulates report from any future rescan
558
+ const sizeMap = new Map(items.map((i) => [i.nmPath, i.size]));
559
+ const { succeeded, failed } = await runWipe(selected, sizeMap);
560
+ // Space report uses the snapshot, not a live lookup
561
+ const freedBytes = succeeded.reduce((sum, r) => sum + parseBytes(sizeMap.get(r.nmPath) ?? '0'), 0);
562
+ const freedLabel = freedBytes > 0 ? formatBytes(freedBytes) : '?';
563
+ console.log('');
564
+ console.log(` ${chalk.bold('┌─ Report ───────────────────────────────')}`);
565
+ if (DRY_RUN) {
566
+ console.log(` ${chalk.bold('│')} ${chalk.yellow('dry-run — nothing actually deleted')}`);
567
+ }
568
+ console.log(` ${chalk.bold('│')} ${chalk.green(`✓ ${succeeded.length} deleted`)}`);
569
+ if (failed.length > 0) {
570
+ console.log(` ${chalk.bold('│')} ${chalk.red(`✗ ${failed.length} failed`)}`);
571
+ }
572
+ console.log(` ${chalk.bold('│')} ${chalk.cyan(`Space freed : ~${freedLabel}`)}`);
573
+ console.log(` ${chalk.bold('└───────────────────────────────────────')}\n`);
574
+ logger.info(`Report — ${succeeded.length} deleted · ${failed.length} failed · ~${freedLabel} freed`);
575
+ logger.info('Session end');
576
+ logger.separator();
577
+ }
578
+ main()
579
+ .then(() => logger.close())
580
+ .catch(async (err) => {
581
+ if (err instanceof Error && err.name === 'ExitPromptError') {
582
+ logger.warn('Session cancelled (Ctrl+C)');
583
+ await logger.close();
584
+ console.log(chalk.yellow('\n Cancelled.\n'));
585
+ process.exit(0);
586
+ }
587
+ const msg = err instanceof Error ? err.message : String(err);
588
+ const stack = err instanceof Error ? (err.stack ?? msg) : msg;
589
+ logger.error(`Unhandled: ${msg}`);
590
+ logger.error(`Stack: ${stack}`);
591
+ await logger.close();
592
+ console.error(chalk.red('\n Error:'), msg);
593
+ process.exit(1);
594
+ });
595
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export declare const LOG_FILE: string;
2
+ export declare const logger: {
3
+ info: (msg: string) => void;
4
+ warn: (msg: string) => void;
5
+ error: (msg: string) => void;
6
+ separator(): void;
7
+ /** Flush and close the stream — call before process.exit() */
8
+ close(): Promise<void>;
9
+ };
10
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,QAAQ,QAAgD,CAAC;AAoBtE,eAAO,MAAM,MAAM;gBACJ,MAAM,KAAG,IAAI;gBACb,MAAM,KAAG,IAAI;iBACb,MAAM,KAAG,IAAI;iBACb,IAAI;IAEjB,8DAA8D;aACrD,OAAO,CAAC,IAAI,CAAC;CAMvB,CAAC"}
package/dist/logger.js ADDED
@@ -0,0 +1,42 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ const LOG_DIR = path.join(os.homedir(), '.wipeit', 'logs');
5
+ const datestamp = new Date().toISOString().slice(0, 10);
6
+ export const LOG_FILE = path.join(LOG_DIR, `wipeit-${datestamp}.log`);
7
+ // Create log dir safely — degrade gracefully if not writable
8
+ let logStream = null;
9
+ try {
10
+ fs.mkdirSync(LOG_DIR, { recursive: true });
11
+ logStream = fs.createWriteStream(LOG_FILE, { flags: 'a' });
12
+ }
13
+ catch {
14
+ // Logging silently disabled if ~/.wipeit/logs is not writable
15
+ }
16
+ function write(level, msg) {
17
+ if (!logStream)
18
+ return;
19
+ try {
20
+ logStream.write(`[${new Date().toISOString()}] [${level.padEnd(5)}] ${msg}\n`);
21
+ }
22
+ catch {
23
+ // Swallow write errors — don't crash the app over logging
24
+ }
25
+ }
26
+ export const logger = {
27
+ info: (msg) => write('INFO', msg),
28
+ warn: (msg) => write('WARN', msg),
29
+ error: (msg) => write('ERROR', msg),
30
+ separator() { write('INFO', '─'.repeat(60)); },
31
+ /** Flush and close the stream — call before process.exit() */
32
+ close() {
33
+ return new Promise((resolve) => {
34
+ if (!logStream) {
35
+ resolve();
36
+ return;
37
+ }
38
+ logStream.end(resolve);
39
+ });
40
+ },
41
+ };
42
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,MAAM,OAAO,GAAK,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;AAC7D,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACxD,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,SAAS,MAAM,CAAC,CAAC;AAEtE,6DAA6D;AAC7D,IAAI,SAAS,GAA0B,IAAI,CAAC;AAC5C,IAAI,CAAC;IACH,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,SAAS,GAAG,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;AAC7D,CAAC;AAAC,MAAM,CAAC;IACP,8DAA8D;AAChE,CAAC;AAED,SAAS,KAAK,CAAC,KAAe,EAAE,GAAW;IACzC,IAAI,CAAC,SAAS;QAAE,OAAO;IACvB,IAAI,CAAC;QACH,SAAS,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACjF,CAAC;IAAC,MAAM,CAAC;QACP,0DAA0D;IAC5D,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAG,CAAC,GAAW,EAAQ,EAAE,CAAC,KAAK,CAAC,MAAM,EAAG,GAAG,CAAC;IACjD,IAAI,EAAG,CAAC,GAAW,EAAQ,EAAE,CAAC,KAAK,CAAC,MAAM,EAAG,GAAG,CAAC;IACjD,KAAK,EAAE,CAAC,GAAW,EAAQ,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC;IACjD,SAAS,KAAW,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpD,8DAA8D;IAC9D,KAAK;QACH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC,SAAS,EAAE,CAAC;gBAAC,OAAO,EAAE,CAAC;gBAAC,OAAO;YAAC,CAAC;YACtC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Async recursive scan for `node_modules` directories.
3
+ * Using fs.promises yields to the event loop between reads,
4
+ * which lets ora's spinner animation actually render.
5
+ */
6
+ export declare function scan(dir: string, maxDepth: number, onFound?: (found: string, total: number) => void, depth?: number, results?: string[]): Promise<string[]>;
7
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAsB,IAAI,CACxB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,EAChD,KAAK,SAAI,EACT,OAAO,GAAE,MAAM,EAAO,GACrB,OAAO,CAAC,MAAM,EAAE,CAAC,CA2BnB"}
@@ -0,0 +1,35 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ /**
4
+ * Async recursive scan for `node_modules` directories.
5
+ * Using fs.promises yields to the event loop between reads,
6
+ * which lets ora's spinner animation actually render.
7
+ */
8
+ export async function scan(dir, maxDepth, onFound, depth = 0, results = []) {
9
+ if (depth > maxDepth)
10
+ return results;
11
+ let entries;
12
+ try {
13
+ entries = await fs.promises.readdir(dir, { withFileTypes: true });
14
+ }
15
+ catch {
16
+ return results;
17
+ }
18
+ for (const entry of entries) {
19
+ if (entry.isSymbolicLink())
20
+ continue; // never follow symlinks — prevents path traversal
21
+ if (!entry.isDirectory())
22
+ continue;
23
+ if (entry.name === 'node_modules') {
24
+ const full = path.join(dir, entry.name);
25
+ results.push(full);
26
+ onFound?.(full, results.length);
27
+ continue; // never recurse inside node_modules
28
+ }
29
+ if (entry.name.startsWith('.'))
30
+ continue;
31
+ await scan(path.join(dir, entry.name), maxDepth, onFound, depth + 1, results);
32
+ }
33
+ return results;
34
+ }
35
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,GAAW,EACX,QAAgB,EAChB,OAAgD,EAChD,KAAK,GAAG,CAAC,EACT,UAAoB,EAAE;IAEtB,IAAI,KAAK,GAAG,QAAQ;QAAE,OAAO,OAAO,CAAC;IAErC,IAAI,OAAoB,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,cAAc,EAAE;YAAE,SAAS,CAAC,kDAAkD;QACxF,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS;QAEnC,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAChC,SAAS,CAAC,oCAAoC;QAChD,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAEzC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;IAChF,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,24 @@
1
+ export type AccessStatus = 'writable' | 'readonly' | 'noaccess';
2
+ export type SortOrder = 'access' | 'size-desc' | 'size-asc' | 'path';
3
+ export interface ScanItem {
4
+ nmPath: string;
5
+ access: AccessStatus;
6
+ size: string;
7
+ mtimeMs: number;
8
+ choiceName: string;
9
+ disabled: string | false;
10
+ }
11
+ export interface WipeResult {
12
+ nmPath: string;
13
+ success: boolean;
14
+ durationMs: number;
15
+ error?: string;
16
+ }
17
+ export interface Filters {
18
+ path: string;
19
+ minBytes: number;
20
+ maxBytes: number;
21
+ olderThanMs: number;
22
+ }
23
+ export declare const DEFAULT_FILTERS: Filters;
24
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;AAChE,MAAM,MAAM,SAAS,GAAK,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAEvE,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAM,MAAM,CAAC;IACnB,MAAM,EAAM,YAAY,CAAC;IACzB,IAAI,EAAQ,MAAM,CAAC;IACnB,OAAO,EAAK,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAI,MAAM,GAAG,KAAK,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAM,MAAM,CAAC;IACnB,OAAO,EAAK,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAM,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAS,MAAM,CAAC;IACpB,QAAQ,EAAK,MAAM,CAAC;IACpB,QAAQ,EAAK,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,eAAe,EAAE,OAK7B,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ export const DEFAULT_FILTERS = {
2
+ path: '',
3
+ minBytes: 0,
4
+ maxBytes: Infinity,
5
+ olderThanMs: 0,
6
+ };
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA0BA,MAAM,CAAC,MAAM,eAAe,GAAY;IACtC,IAAI,EAAS,EAAE;IACf,QAAQ,EAAK,CAAC;IACd,QAAQ,EAAK,QAAQ;IACrB,WAAW,EAAE,CAAC;CACf,CAAC"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "nm-wipe",
3
+ "version": "1.0.0",
4
+ "description": "Interactive node_modules cleaner CLI for macOS",
5
+ "author": "Boopathy Ganesh K <boopathyganesh95@gmail.com>",
6
+ "type": "module",
7
+ "bin": {
8
+ "nm-wipe": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "postbuild": "node scripts/postbuild.js",
13
+ "dev": "tsx src/index.ts",
14
+ "start": "node dist/index.js"
15
+ },
16
+ "engines": {
17
+ "node": ">=18.0.0"
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "keywords": [
23
+ "cli",
24
+ "cleanup",
25
+ "disk-space",
26
+ "node-modules",
27
+ "node_modules"
28
+ ],
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "@inquirer/prompts": "^7.0.0",
32
+ "chalk": "^5.0.0",
33
+ "ora": "^8.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^22.0.0",
37
+ "tsx": "^4.0.0",
38
+ "typescript": "^5.0.0"
39
+ }
40
+ }