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 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,3 @@
1
+
2
+ export { };
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sources":[],"sourcesContent":[],"names":[],"mappings":""}