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 +22 -0
- package/README.md +121 -0
- package/dist/fs-utils.d.ts +5 -0
- package/dist/fs-utils.d.ts.map +1 -0
- package/dist/fs-utils.js +50 -0
- package/dist/fs-utils.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +595 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +10 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +42 -0
- package/dist/logger.js.map +1 -0
- package/dist/scanner.d.ts +7 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +35 -0
- package/dist/scanner.js.map +1 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
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"}
|
package/dist/fs-utils.js
ADDED
|
@@ -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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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":";AACA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG7C,iFAAiF;AACjF,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtC,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AAExD,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;GAWX,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CACpB,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC9C,CAAC;IACzB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,iFAAiF;AACjF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;AAC9E,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACrF,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;IAC5B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,+BAA+B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACtF,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AACxD,MAAM,IAAI,GAAW,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,YAAY,CAAC,CAAC;AAC3D,MAAM,SAAS,GAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;AACtE,MAAM,SAAS,GAAM,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/F,MAAM,IAAI,GAAW,EAAE,CAAC,OAAO,EAAE,CAAC;AAClC,MAAM,IAAI,GAAW,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,GAAG,CAAC;AACnD,MAAM,WAAW,GAAI,CAAC,CAAC;AAEvB,iFAAiF;AACjF,SAAS,GAAG,CAAC,CAAS;IACpB,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS,EAAE,MAAc;IACzC,OAAO,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IACjB,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;IAClC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACnC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;QAC3B,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;QAChC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;QAChC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;QAChC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IACxE,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IACxE,IAAI,KAAK,IAAI,KAAK;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAC9D,OAAO,GAAG,KAAK,IAAI,CAAC;AACtB,CAAC;AAED,qEAAqE;AACrE,SAAS,eAAe,CAAC,GAAW;IAClC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;IAC/D,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACxD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC1D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AACjD,CAAC;AAED,qEAAqE;AACrE,SAAS,cAAc,CAAC,GAAW;IACjC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACnD,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,MAAM,GAAG,GAAG,UAAU,CAAC;IACvB,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACnC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC;QACzB,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC;QAC9B,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC;QAC/B,OAAO,CAAC,CAAE,OAAO,IAAI,CAAC;IACxB,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,SAAS,YAAY,CAAC,KAAiB,EAAE,OAAgB;IACvD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC3B,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;YACvD,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBAAE,OAAO,KAAK,CAAC;QAC5D,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,OAAO,CAAC,QAAQ,GAAG,CAAC,IAAI,KAAK,GAAG,OAAO,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QACnE,IAAI,OAAO,CAAC,QAAQ,GAAG,QAAQ,IAAI,KAAK,GAAG,OAAO,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC1E,IAAI,OAAO,CAAC,WAAW,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;YAChD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,WAAW;gBAAE,OAAO,KAAK,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,SAAS,CAAC,KAAiB,EAAE,IAAe;IACnD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC9B,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,WAAW,CAAC,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACjE,KAAK,UAAU,CAAC,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChE,KAAK,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACrD,OAAO,CAAC,CAAC,CAAC;gBACR,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU;oBAAE,OAAO,CAAC,CAAC,CAAC;gBAClE,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU;oBAAE,OAAO,CAAC,CAAC;gBACjE,OAAO,CAAC,CAAC;YACX,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,CAAU;IACjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;IAC3C,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAClE,IAAI,CAAC,CAAC,QAAQ,GAAG,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzE,IAAI,CAAC,CAAC,WAAW,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IACpF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,UAAU,CAAC,CAAU;IAC5B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,GAAG,QAAQ,IAAI,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;AACpF,CAAC;AAED,iFAAiF;AACjF,SAAS,WAAW,CAAC,MAAoB;IACvC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,UAAU,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC/E,KAAK,UAAU,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,2BAA2B,EAAE,CAAC;QACtG,KAAK,UAAU,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,+BAA+B,EAAE,CAAC;IACzG,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,MAAc;IACzC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAChD,WAAW,CAAC,MAAM,CAAC;QACnB,OAAO,CAAC,MAAM,CAAC;QACf,QAAQ,CAAC,MAAM,CAAC;KACjB,CAAC,CAAC;IACH,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,GAAG,KAAK,KAAK,OAAO,KAAK,OAAO,EAAE,CAAC;IACtD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AACjE,CAAC;AAED,gFAAgF;AAChF,KAAK,UAAU,sBAAsB,CACnC,KAAe,EACf,UAAiD;IAEjD,MAAM,OAAO,GAA6B,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAClE,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE;QAC9E,IAAI,CAAC,GAAG,MAAM,CAAC;QACf,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YACxB,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;YAC5C,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YACjC,CAAC,IAAI,WAAW,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAiB,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;AAC/D,CAAC;AAED,iFAAiF;AACjF,KAAK,UAAU,OAAO,CAAC,IAAY;IACjC,MAAM,WAAW,GAAG,GAAG,CAAC;QACtB,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;YAClD,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;YAC/D,QAAQ,EAAE,GAAG;SACd;KACF,CAAC,CAAC,KAAK,EAAE,CAAC;IACX,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE;QACtD,WAAW,CAAC,IAAI,GAAG,cAAc,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACtC,WAAW,CAAC,OAAO,CAAC,mBAAmB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,KAAK,CAAC,GAAG,CAAC,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;IACxG,MAAM,CAAC,IAAI,CAAC,mBAAmB,KAAK,CAAC,MAAM,aAAa,MAAM,IAAI,CAAC,CAAC;IACpE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;IAEpD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAElC,MAAM,UAAU,GAAG,GAAG,CAAC;QACrB,IAAI,EAAE,gBAAgB,KAAK,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;YAC5D,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;YAC/D,QAAQ,EAAE,GAAG;SACd;KACF,CAAC,CAAC,KAAK,EAAE,CAAC;IACX,MAAM,KAAK,GAAG,MAAM,sBAAsB,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAChE,UAAU,CAAC,IAAI,GAAG,kCAAkC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,EAAE,CAAC;IACpF,CAAC,CAAC,CAAC;IACH,UAAU,CAAC,OAAO,CAAC,gCAAgC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,CAAC;IAC7F,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,YAAY,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAE/F,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iFAAiF;AACjF,KAAK,UAAU,aAAa,CAAC,OAAgB;IAC3C,MAAM,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAE/B,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC;YACnC,CAAC,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;YACrC,CAAC,CAAC,OAAO,CAAC,QAAQ,GAAG,QAAQ;gBAC3B,CAAC,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;gBACrC,CAAC,CAAC,IAAI,CAAC;QACX,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,GAAG,CAAC;YACrC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,GAAG,UAAU,CAAC,GAAG;YACrD,CAAC,CAAC,IAAI,CAAC;QAET,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;YAC1B,OAAO,EAAE,SAAS;YAClB,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,cAAc,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;gBACxG,EAAE,IAAI,EAAE,cAAc,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;gBAChG,EAAE,IAAI,EAAE,cAAc,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,mCAAmC,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;gBACxH,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,OAAO,EAAE;gBAChD,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE;aAClC;SACF,CAAC,CAAC;QAEH,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,OAAO,CAAC;QACtC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;YAAC,SAAS;QAAC,CAAC;QAE9E,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,GAAG,MAAM,KAAK,CAAC;gBACzB,OAAO,EAAE,8DAA8D;gBACvE,OAAO,EAAE,OAAO,CAAC,IAAI;aACtB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,EAAE,OAAO,EAAE,kDAAkD,EAAE,CAAC,CAAC;YACzF,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;gBAChB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;gBAAC,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;YACpD,CAAC;iBAAM,CAAC;gBACN,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;gBACpC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,2BAA2B,GAAG,6BAA6B,CAAC,CAAC,CAAC;oBACpF,MAAM,CAAC,IAAI,CAAC,+BAA+B,GAAG,GAAG,CAAC,CAAC;gBACrD,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;oBAAC,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;gBACzE,CAAC;YACH,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,EAAE,OAAO,EAAE,oDAAoD,EAAE,CAAC,CAAC;YAC3F,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;gBAChB,OAAO,CAAC,WAAW,GAAG,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;gBACnC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;oBACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,0BAA0B,GAAG,yBAAyB,CAAC,CAAC,CAAC;oBAC/E,MAAM,CAAC,IAAI,CAAC,8BAA8B,GAAG,GAAG,CAAC,CAAC;gBACpD,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC;gBAC/B,CAAC;YACH,CAAC;YACD,SAAS;QACX,CAAC;IACH,CAAC;AACH,CAAC;AAMD,MAAM,WAAW,GAA8B;IAC7C,QAAQ,EAAE,gBAAgB;IAC1B,WAAW,EAAE,QAAQ;IACrB,UAAU,EAAE,QAAQ;IACpB,MAAM,EAAE,UAAU;CACnB,CAAC;AAEF,IAAI,WAAW,GAAG,KAAK,CAAC,CAAC,4CAA4C;AAErE,KAAK,UAAU,UAAU,CACvB,YAAwB,EACxB,cAAuB,EACvB,WAAsB;IAEtB,IAAI,KAAK,GAAG,YAAY,CAAC;IACzB,IAAI,OAAO,GAAG,cAAc,CAAC;IAC7B,IAAI,IAAI,GAAG,WAAW,CAAC;IAEvB,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;QAC5C,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC;YACrC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC;YAChF,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC;QAEvC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;YAC1B,OAAO,EAAE,cAAc,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;YACjF,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,kBAAkB,EAAE,KAAK,EAAE,QAAQ,EAAE;gBAChE,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE;gBAC3I,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;gBAC1F,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,KAAK,EAAE,QAAQ,EAAE;gBAChE,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE;aAClD;SACF,CAAC,CAAC;QAEH,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YACtE,IAAI,EAAE;gBAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAChC,SAAS;QACX,CAAC;QAED,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;YACvC,SAAS;QACX,CAAC;QAED,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,IAAI,GAAG,MAAM,MAAM,CAAY;gBAC7B,OAAO,EAAE,SAAS;gBAClB,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,2BAA2B,EAAE,KAAK,EAAE,QAAQ,EAAE;oBACtD,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,WAAW,EAAE;oBACnD,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,UAAU,EAAE;oBACnD,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE;iBACpC;aACF,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,IAAI,WAAW,EAAE,CAAC;gBAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,mCAAmC,CAAC,CAAC,CAAC;gBAC/D,SAAS;YACX,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;YACxC,WAAW,GAAG,IAAI,CAAC;YACnB,IAAI,CAAC;gBAAC,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;YAAC,CAAC;oBAAS,CAAC;gBAAC,WAAW,GAAG,KAAK,CAAC;YAAC,CAAC;YACrE,SAAS;QACX,CAAC;QAED,WAAW;QACX,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAClD,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,KAAK,UAAU,WAAW,CAAC,QAAoB,EAAE,SAAmB;IAClE,OAAO,CAAC,GAAG,CACT,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI;QACrC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,KAAK;QACjC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,KAAK;QACnC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,IAAI,CAChC,CAAC;IAEF,OAAO,QAAQ,CAAC;QACd,OAAO,EAAE,uEAAuE;QAChF,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;YAC3D,IAAI,EAAE,UAAU;YAChB,KAAK,EAAE,MAAM;YACb,QAAQ;YACR,OAAO,EAAE,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;SACpC,CAAC,CAAC;QACH,QAAQ,EAAE,EAAE;KACb,CAAC,CAAC;AACL,CAAC;AAED,iFAAiF;AACjF,KAAK,UAAU,WAAW,CAAC,QAAkB,EAAE,KAAiB;IAC9D,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CACpC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC,CAChF,CAAC;IAEF,OAAO,MAAM,CAAC;QACZ,OAAO,EACL,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW;YACzC,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QACxF,OAAO,EAAE;YACP,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,wBAAwB,EAAE,KAAK,EAAE,SAAS,EAAE;YACvE,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,KAAK,EAAE,QAAQ,EAAE;YAChE,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE;SACnD;KACF,CAAC,CAAC;AACL,CAAC;AAED,iFAAiF;AACjF,KAAK,UAAU,gBAAgB,CAAC,YAAwB;IACtD,IAAI,KAAK,GAAG,YAAY,CAAC;IACzB,IAAI,OAAO,GAAG,EAAE,GAAG,eAAe,EAAE,CAAC;IACrC,IAAI,IAAI,GAAc,QAAQ,CAAC;IAC/B,IAAI,SAAS,GAAa,EAAE,CAAC;IAC7B,IAAI,QAAQ,GAAe,EAAE,CAAC;IAG9B,IAAI,KAAK,GAAU,SAAS,CAAC;IAC7B,IAAI,QAAQ,GAAa,EAAE,CAAC;IAE5B,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;YACtD,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,EAAE,CAAC;YAEtC,oCAAoC;YACpC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;YACrB,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;YACzB,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACnB,QAAQ,GAAG,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;YACzD,SAAS,GAAG,EAAE,CAAC,CAAC,uDAAuD;YACvE,KAAK,GAAG,UAAU,CAAC;YACnB,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;YACzB,QAAQ,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YAClD,SAAS,GAAG,EAAE,CAAC;YACf,KAAK,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC;YACvD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAClD,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAC;YAE1C,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACxB,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;gBAC5F,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChE,MAAM,CAAC,IAAI,CAAC,WAAW,SAAS,CAAC,MAAM,oBAAoB,CAAC,CAAC;gBAC7D,KAAK,GAAG,UAAU,CAAC;gBACnB,SAAS;YACX,CAAC;YAED,wCAAwC;YACxC,SAAS,GAAG,EAAE,CAAC;YACf,KAAK,GAAG,SAAS,CAAC;YAClB,SAAS;QACX,CAAC;IACH,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,KAAK,UAAU,OAAO,CACpB,MAAgB,EAChB,OAA4B;IAE5B,MAAM,OAAO,GAAG,GAAG,CAAC;QAClB,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;YACtB,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;YAC/D,QAAQ,EAAE,GAAG;SACd;KACF,CAAC,CAAC;IACH,MAAM,SAAS,GAAiB,EAAE,CAAC;IACnC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,KAAK,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1B,MAAM,QAAQ,GAAG,OAAO,CAAC;QAEzB,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC;QAC3F,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEzB,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAC/C,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,CAC3G,CAAC;gBACF,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;YAC7E,CAAC;YACD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACtC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,UAAU,KAAK,CAAC,CAAC,CAAC;YAC7F,MAAM,MAAM,GAAe,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;YACjE,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACvB,MAAM,CAAC,IAAI,CAAC,cAAc,MAAM,MAAM,UAAU,MAAM,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACtC,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC;YACzE,MAAM,MAAM,GAAe,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;YACzE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpB,MAAM,CAAC,KAAK,CAAC,cAAc,MAAM,MAAM,UAAU,QAAQ,KAAK,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC;YAC1B,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,YAAY,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,kBAAkB;YACnF,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACH,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YACrD,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACzF,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACzE,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AAC/B,CAAC;AAED,iFAAiF;AACjF,SAAS,YAAY,CAAC,MAAc;IAClC,MAAM,CAAC,IAAI,CAAC,oBAAoB,MAAM,oBAAoB,CAAC,CAAC;IAC5D,MAAM,CAAC,SAAS,EAAE,CAAC;IACnB,MAAM,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,oBAAoB,MAAM,eAAe,CAAC,CAAC,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AACD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;AACrD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;AAEpD,iFAAiF;AACjF,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,SAAS,EAAE,CAAC;IACnB,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC7B,MAAM,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC;IACnC,MAAM,CAAC,IAAI,CAAC,eAAe,SAAS,EAAE,CAAC,CAAC;IACxC,MAAM,CAAC,IAAI,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC;IACtC,MAAM,CAAC,IAAI,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;IAEvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sCAAsC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9G,OAAO,CAAC,GAAG,CACT,KAAK,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE;QACpD,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CACrE,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEjE,6CAA6C;IAC7C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,GAAG,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;YAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,GAAG,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC,CAAC;QAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,0CAA0C,CAAC,CAAC,CAAC;QACtE,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,kCAAkC,CAAC,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;IAEzD,qBAAqB;IACrB,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CACpC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC,CAChF,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC;QAC9B,OAAO,EACL,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,QAAQ,CAAC,MAAM,eAAe;YACpF,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,WAAW,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG;QACxE,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,gFAAgF;IAChF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAE/D,oDAAoD;IACpD,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CACjC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,CAC9D,CAAC;IACF,MAAM,UAAU,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAElE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,EAAE,CAAC,CAAC;IAC5E,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,oCAAoC,CAAC,EAAE,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,MAAM,UAAU,CAAC,EAAE,CAAC,CAAC;IACrF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,MAAM,SAAS,CAAC,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,kBAAkB,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;IACnF,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,0CAA0C,CAAC,IAAI,CAAC,CAAC;IAE7E,MAAM,CAAC,IAAI,CAAC,YAAY,SAAS,CAAC,MAAM,cAAc,MAAM,CAAC,MAAM,cAAc,UAAU,QAAQ,CAAC,CAAC;IACrG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC3B,MAAM,CAAC,SAAS,EAAE,CAAC;AACrB,CAAC;AAED,IAAI,EAAE;KACH,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;KAC1B,KAAK,CAAC,KAAK,EAAE,GAAY,EAAE,EAAE;IAC5B,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QAC3D,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC1C,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,GAAG,GAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAC9D,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,EAAE,CAAC,CAAC;IAClC,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC;IAChC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -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"}
|
package/dist/scanner.js
ADDED
|
@@ -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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
|
+
}
|