oh-my-node-modules 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/AGENTS.md +267 -0
- package/README.md +89 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1674 -0
- package/dist/index.d.ts +562 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +882 -0
- package/package.json +68 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# AGENTS.md - oh-my-node-modules
|
|
2
|
+
|
|
3
|
+
Architecture overview and development guide for AI assistants working on this codebase.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
**oh-my-node-modules** is a TUI CLI tool for visualizing and cleaning up node_modules directories. It combines:
|
|
8
|
+
- **Ink**: React-based terminal UI framework
|
|
9
|
+
- **@clack/prompts**: Interactive prompts for CLI mode
|
|
10
|
+
- **TypeScript**: Type-safe development
|
|
11
|
+
|
|
12
|
+
## Project Structure
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
src/
|
|
16
|
+
├── types.ts # Core type definitions (interfaces, types, constants)
|
|
17
|
+
├── utils.ts # Pure utility functions (formatting, sorting, filtering)
|
|
18
|
+
├── scanner.ts # Discovery and analysis logic
|
|
19
|
+
├── deletion.ts # Safe deletion operations
|
|
20
|
+
├── components/
|
|
21
|
+
│ └── index.tsx # Ink UI components (Header, List, Footer, etc.)
|
|
22
|
+
├── app.tsx # Main application component with state management
|
|
23
|
+
├── cli.tsx # CLI entry point and argument parsing
|
|
24
|
+
└── index.ts # Public API exports
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Key Concepts
|
|
28
|
+
|
|
29
|
+
### Data Flow
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
Scanner → NodeModulesInfo[] → State → Components → Render
|
|
33
|
+
↓
|
|
34
|
+
Utils (sort/filter)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
1. **Scanner** discovers node_modules and creates `NodeModulesInfo` objects
|
|
38
|
+
2. **State** (React hooks) holds the current application state
|
|
39
|
+
3. **Utils** provide pure functions for sorting, filtering, formatting
|
|
40
|
+
4. **Components** render the UI based on state
|
|
41
|
+
5. **User Input** updates state, triggering re-render
|
|
42
|
+
|
|
43
|
+
### Core Types
|
|
44
|
+
|
|
45
|
+
**NodeModulesInfo**: Central data structure representing a node_modules directory
|
|
46
|
+
```typescript
|
|
47
|
+
interface NodeModulesInfo {
|
|
48
|
+
path: string; // Absolute path
|
|
49
|
+
projectPath: string; // Parent project path
|
|
50
|
+
projectName: string; // From package.json or directory name
|
|
51
|
+
sizeBytes: number; // Total size
|
|
52
|
+
sizeFormatted: string; // Human readable
|
|
53
|
+
packageCount: number; // Top-level packages
|
|
54
|
+
totalPackageCount: number; // All packages (nested)
|
|
55
|
+
lastModified: Date;
|
|
56
|
+
lastModifiedFormatted: string;
|
|
57
|
+
selected: boolean; // For deletion
|
|
58
|
+
isFavorite: boolean; // Never suggest deleting
|
|
59
|
+
ageCategory: AgeCategory; // 'fresh' | 'recent' | 'old' | 'stale'
|
|
60
|
+
sizeCategory: SizeCategory; // 'small' | 'medium' | 'large' | 'huge'
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### State Management
|
|
65
|
+
|
|
66
|
+
The app uses React hooks for state management:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
const [state, setState] = useState<AppState>({
|
|
70
|
+
nodeModules: [], // All discovered items
|
|
71
|
+
selectedIndex: 0, // Current focus
|
|
72
|
+
sortBy: 'size-desc', // Current sort
|
|
73
|
+
filterQuery: '', // Search filter
|
|
74
|
+
isScanning: false,
|
|
75
|
+
isDeleting: false,
|
|
76
|
+
scanProgress: 0,
|
|
77
|
+
sessionBytesReclaimed: 0,
|
|
78
|
+
showHelp: false,
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
State updates are **immutable** - always create new objects/arrays.
|
|
83
|
+
|
|
84
|
+
### Keyboard Handling
|
|
85
|
+
|
|
86
|
+
Input is handled via Ink's `useInput` hook:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
useInput((input, key) => {
|
|
90
|
+
if (key.upArrow) navigateUp();
|
|
91
|
+
if (input === 'd') promptDelete();
|
|
92
|
+
// ... etc
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Key Design**: Input handlers check UI state first (help, confirm dialogs) to ensure proper modal behavior.
|
|
97
|
+
|
|
98
|
+
## Common Tasks
|
|
99
|
+
|
|
100
|
+
### Adding a New Sort Option
|
|
101
|
+
|
|
102
|
+
1. Add to `SortOption` type in `types.ts`
|
|
103
|
+
2. Add sort logic in `sortNodeModules()` in `utils.ts`
|
|
104
|
+
3. Add label in `getSortLabel()` in `components/index.tsx`
|
|
105
|
+
|
|
106
|
+
### Adding a New Filter
|
|
107
|
+
|
|
108
|
+
1. Create filter function in `utils.ts`
|
|
109
|
+
2. Add keyboard shortcut in `app.tsx` `useInput`
|
|
110
|
+
3. Update help text in `Help` component
|
|
111
|
+
|
|
112
|
+
### Adding a New Keyboard Shortcut
|
|
113
|
+
|
|
114
|
+
1. Add handler in `app.tsx` `useInput`
|
|
115
|
+
2. Update `Footer` component to show shortcut
|
|
116
|
+
3. Update `Help` component with documentation
|
|
117
|
+
|
|
118
|
+
### Modifying the Scanner
|
|
119
|
+
|
|
120
|
+
Scanner is in `scanner.ts`. Key functions:
|
|
121
|
+
- `scanForNodeModules()`: Main entry point
|
|
122
|
+
- `analyzeNodeModules()`: Detailed analysis of single node_modules
|
|
123
|
+
- `calculateDirectorySize()`: Recursive size calculation
|
|
124
|
+
|
|
125
|
+
Scanner is **async** and reports progress via callback.
|
|
126
|
+
|
|
127
|
+
### Modifying Deletion Logic
|
|
128
|
+
|
|
129
|
+
Deletion is in `deletion.ts`. Key functions:
|
|
130
|
+
- `deleteSelectedNodeModules()`: Main entry point
|
|
131
|
+
- `deleteNodeModules()`: Single deletion with safety checks
|
|
132
|
+
- `verifyNodeModules()`: Validates before deletion
|
|
133
|
+
|
|
134
|
+
Safety checks:
|
|
135
|
+
1. Path ends with 'node_modules'
|
|
136
|
+
2. Directory exists
|
|
137
|
+
3. Not in use (if check enabled)
|
|
138
|
+
4. Looks like valid node_modules
|
|
139
|
+
|
|
140
|
+
## Architecture Patterns
|
|
141
|
+
|
|
142
|
+
### Pure Functions
|
|
143
|
+
|
|
144
|
+
Utility functions in `utils.ts` are pure (no side effects):
|
|
145
|
+
```typescript
|
|
146
|
+
// Good: returns new array, doesn't mutate
|
|
147
|
+
export function sortNodeModules(items: NodeModulesInfo[], sortBy: SortOption): NodeModulesInfo[] {
|
|
148
|
+
return [...items].sort(/* ... */);
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Immutable Updates
|
|
153
|
+
|
|
154
|
+
State updates always create new objects:
|
|
155
|
+
```typescript
|
|
156
|
+
setState(prev => ({
|
|
157
|
+
...prev,
|
|
158
|
+
nodeModules: prev.nodeModules.map(item =>
|
|
159
|
+
item.path === targetPath ? { ...item, selected: true } : item
|
|
160
|
+
),
|
|
161
|
+
}));
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Async Operations
|
|
165
|
+
|
|
166
|
+
Long-running operations (scan, delete) use async/await:
|
|
167
|
+
```typescript
|
|
168
|
+
const result = await scanForNodeModules(options, onProgress);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Progress callbacks keep UI responsive.
|
|
172
|
+
|
|
173
|
+
### Error Handling
|
|
174
|
+
|
|
175
|
+
Errors are caught and displayed in the UI:
|
|
176
|
+
```typescript
|
|
177
|
+
try {
|
|
178
|
+
await operation();
|
|
179
|
+
} catch (error) {
|
|
180
|
+
setErrorMessage(error instanceof Error ? error.message : 'Unknown error');
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Performance Considerations
|
|
185
|
+
|
|
186
|
+
1. **Virtual Scrolling**: List component only renders visible items
|
|
187
|
+
2. **Memoization**: `useMemo` for expensive calculations (statistics, sorting)
|
|
188
|
+
3. **Debouncing**: Progress updates batched to avoid re-render storms
|
|
189
|
+
4. **Lazy Loading**: Scanner yields control periodically
|
|
190
|
+
|
|
191
|
+
## Testing
|
|
192
|
+
|
|
193
|
+
Tests use Vitest. Run with:
|
|
194
|
+
```bash
|
|
195
|
+
npm test
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Test pure functions in `utils.ts` directly. For components, use Ink's testing utilities.
|
|
199
|
+
|
|
200
|
+
## Code Style
|
|
201
|
+
|
|
202
|
+
- **TypeScript strict mode**: No `any`, proper null checks
|
|
203
|
+
- **Named exports**: Prefer `export function` over default exports
|
|
204
|
+
- **JSDoc comments**: Explain "why" not just "what"
|
|
205
|
+
- **File extensions**: Use `.js` in imports (ESM requirement)
|
|
206
|
+
|
|
207
|
+
## Build & Publish
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Build
|
|
211
|
+
npm run build
|
|
212
|
+
|
|
213
|
+
# Test
|
|
214
|
+
npm run test:run
|
|
215
|
+
|
|
216
|
+
# Type check
|
|
217
|
+
npm run typecheck
|
|
218
|
+
|
|
219
|
+
# Publish
|
|
220
|
+
npm run prepublishOnly
|
|
221
|
+
npm publish
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Dependencies
|
|
225
|
+
|
|
226
|
+
**Runtime:**
|
|
227
|
+
- `ink`: React for terminals
|
|
228
|
+
- `@clack/prompts`: Interactive prompts
|
|
229
|
+
- `zod`: Runtime validation
|
|
230
|
+
- `react`: Peer dependency
|
|
231
|
+
|
|
232
|
+
**Development:**
|
|
233
|
+
- `typescript`: Type checking
|
|
234
|
+
- `bunchee`: Building
|
|
235
|
+
- `vitest`: Testing
|
|
236
|
+
- `@types/*`: Type definitions
|
|
237
|
+
|
|
238
|
+
## CLI Modes
|
|
239
|
+
|
|
240
|
+
The app supports three modes:
|
|
241
|
+
|
|
242
|
+
1. **Interactive TUI** (default): Full Ink-based UI with keyboard navigation
|
|
243
|
+
2. **Quick Scan** (`--scan`): Non-interactive summary report
|
|
244
|
+
3. **Auto Delete** (`--auto`): Non-interactive batch deletion
|
|
245
|
+
|
|
246
|
+
Mode is determined by CLI arguments in `cli.tsx`.
|
|
247
|
+
|
|
248
|
+
## Safety Features
|
|
249
|
+
|
|
250
|
+
1. **Path verification**: Must end with 'node_modules'
|
|
251
|
+
2. **In-use detection**: Checks for lock files
|
|
252
|
+
3. **Confirmation**: Required unless `--yes`
|
|
253
|
+
4. **Dry run**: `--dry-run` simulates without deleting
|
|
254
|
+
5. **Favorites**: Projects in `~/.onmfavorites` are protected
|
|
255
|
+
|
|
256
|
+
## Cross-Platform Support
|
|
257
|
+
|
|
258
|
+
- Uses Node.js `fs.promises` for file operations
|
|
259
|
+
- Uses `path.join` for path manipulation
|
|
260
|
+
- Avoids platform-specific features
|
|
261
|
+
- Works on macOS, Linux, Windows (WSL)
|
|
262
|
+
|
|
263
|
+
## Questions?
|
|
264
|
+
|
|
265
|
+
- Check `README.md` for user documentation
|
|
266
|
+
- Check this file for architecture questions
|
|
267
|
+
- Look at existing code for patterns
|
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# oh-my-node-modules
|
|
2
|
+
|
|
3
|
+
Visualize, analyze, and clean up node_modules directories to reclaim disk space.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install globally
|
|
9
|
+
npm install -g oh-my-node-modules
|
|
10
|
+
|
|
11
|
+
# Or use with npx
|
|
12
|
+
npx oh-my-node-modules
|
|
13
|
+
|
|
14
|
+
# Start interactive TUI
|
|
15
|
+
onm
|
|
16
|
+
|
|
17
|
+
# Quick scan report
|
|
18
|
+
onm --scan
|
|
19
|
+
|
|
20
|
+
# Delete all >1GB node_modules
|
|
21
|
+
onm --auto --min-size 1gb --yes
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- **Interactive TUI**: Full terminal UI with keyboard navigation
|
|
27
|
+
- **Size Visualization**: Color-coded sizes (red >1GB, yellow >500MB)
|
|
28
|
+
- **Smart Selection**: Multi-select, select all, invert, select by size
|
|
29
|
+
- **Safe Deletion**: Confirmation prompts, dry-run mode, in-use detection
|
|
30
|
+
- **Filtering**: Search and filter projects by name or path
|
|
31
|
+
- **Progress Tracking**: Visual feedback during scan and delete operations
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
### Interactive Mode (Default)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
onm # Start in current directory
|
|
39
|
+
onm ~/projects # Scan specific directory
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Keyboard shortcuts:
|
|
43
|
+
- `↑/↓` - Navigate
|
|
44
|
+
- `Space` - Toggle selection
|
|
45
|
+
- `d` - Delete selected
|
|
46
|
+
- `a` - Select all
|
|
47
|
+
- `s` - Change sort
|
|
48
|
+
- `f` - Filter
|
|
49
|
+
- `q` - Quit
|
|
50
|
+
- `?` - Help
|
|
51
|
+
|
|
52
|
+
### CLI Mode
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Quick scan and report
|
|
56
|
+
onm --scan
|
|
57
|
+
|
|
58
|
+
# JSON output
|
|
59
|
+
onm --scan --json
|
|
60
|
+
|
|
61
|
+
# Auto-delete with filters
|
|
62
|
+
onm --auto --min-size 500mb --yes
|
|
63
|
+
onm --auto --dry-run # Preview only
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Development
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Install dependencies
|
|
70
|
+
npm install
|
|
71
|
+
|
|
72
|
+
# Build
|
|
73
|
+
npm run build
|
|
74
|
+
|
|
75
|
+
# Test
|
|
76
|
+
npm test
|
|
77
|
+
|
|
78
|
+
# Type check
|
|
79
|
+
npm run typecheck
|
|
80
|
+
|
|
81
|
+
# Dev mode (watch)
|
|
82
|
+
npm run dev
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
See [AGENTS.md](./AGENTS.md) for architecture documentation.
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
MIT
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|