inup 1.4.1 → 1.4.2

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/README.md CHANGED
@@ -4,46 +4,17 @@
4
4
  [![Downloads](https://img.shields.io/npm/dm/inup?style=for-the-badge&color=646CFF&logoColor=white)](https://www.npmjs.com/package/inup)
5
5
  [![Total downloads](https://img.shields.io/npm/dt/inup?style=for-the-badge&color=informational)](https://www.npmjs.com/package/inup)
6
6
 
7
- A powerful interactive CLI tool for upgrading dependencies with ease. **Auto-detects and works with npm, yarn, pnpm, and bun**. Inspired by `yarn upgrade-interactive`, this tool makes dependency management a breeze for any project. Perfect for monorepos, workspaces, and batch upgrades ❤️
7
+ Interactive upgrade for your dependencies. Works with npm, yarn, pnpm, and bun.
8
8
 
9
9
  ![Interactive Upgrade Demo](docs/demo/interactive-upgrade.gif)
10
10
 
11
- ## What it does
12
-
13
- Ever found yourself staring at a wall of outdated packages, wondering which ones to upgrade? This tool helps you:
14
-
15
- - **Scans your entire project** - finds all package.json files in your workspace
16
- - **Auto-detects your package manager** - works seamlessly with npm, yarn, pnpm, or bun
17
- - **Checks for updates** - compares your current versions against the latest available
18
- - **Lets you pick what to upgrade** - interactive interface to select exactly what you want
19
- - **Does the heavy lifting** - updates your package.json files and runs the appropriate install command
20
-
21
- ## Why choose inup?
22
-
23
- If you miss the convenience of `yarn upgrade-interactive` but want it to work with **any package manager**, this tool is perfect for you!
24
-
25
- - **🚀 Fast & Efficient** - Batch upgrade multiple packages at once
26
- - **🔒 Safe Updates** - Choose between minor updates or major version jumps
27
- - **🏢 Monorepo Friendly** - Works seamlessly with workspaces
28
- - **📦 Registry Aware** - Checks npm registry for latest versions
29
- - **🎯 Selective Upgrades** - Pick exactly which packages to upgrade
30
- - **⚡ Zero Config** - Works out of the box with sensible defaults
31
-
32
- ## Installation
33
-
34
- ### With npx (no installation needed)
11
+ ## Install
35
12
 
36
13
  ```bash
37
14
  npx inup
38
15
  ```
39
16
 
40
- ### Install globally with pnpm
41
-
42
- ```bash
43
- pnpm add -g inup
44
- ```
45
-
46
- ### Alternative: npm
17
+ Or install globally:
47
18
 
48
19
  ```bash
49
20
  npm install -g inup
@@ -51,101 +22,46 @@ npm install -g inup
51
22
 
52
23
  ## Usage
53
24
 
54
- Just run it in your project directory:
55
-
56
25
  ```bash
57
- inup
26
+ npx inup
58
27
  ```
59
28
 
60
- The tool will scan your entire workspace (including monorepos), find outdated packages, and let you choose which ones to upgrade interactively.
61
-
62
- ### Interactive Features
29
+ That's it. The tool scans your project, finds outdated packages, and lets you pick what to upgrade.
63
30
 
64
- - **Search**: Press `/` to search for a specific package by name
65
- - **Navigate**: Use arrow keys to move between packages
66
- - **Select Version**: Use `Left` and `Right` arrow keys to cycle through available versions (default, minor, patch, major)
67
- - **Select All Minor**: Press `m` to select all minor updates
68
- - **Package Info**: Press `i` to view detailed information about the selected package
69
- - **Exit Search**: Press `Esc` to exit search mode
31
+ ## Features
70
32
 
71
- ### Command line options
33
+ - Auto-detects package manager (npm, yarn, pnpm, bun)
34
+ - Works with monorepos and workspaces
35
+ - Batch upgrades with keyboard shortcuts
36
+ - Search packages with `/`
37
+ - Multiple themes (press `t`)
38
+ - Package info modal (press `i`)
72
39
 
73
- - `-d, --dir <directory>`: Run in a specific directory (default: current directory)
74
- - `-e, --exclude <patterns>`: Skip directories matching these regex patterns (comma-separated)
75
- - `-p, --peer`: Include peer dependencies in upgrade process (default: false)
76
- - `-o, --optional`: Include optional dependencies in upgrade process (default: false)
77
- - `--package-manager <name>`: Manually specify package manager (npm, yarn, pnpm, bun) - overrides auto-detection
40
+ ## Keyboard Shortcuts
78
41
 
79
- **Note:** By default, the tool only processes `dependencies` and `devDependencies`. Both `peerDependencies` and `optionalDependencies` are excluded by default and must be explicitly included with their respective flags.
42
+ - `↑/↓` - Navigate packages
43
+ - `←/→` - Select version (current, patch, minor, major)
44
+ - `Space` - Toggle selection
45
+ - `m` - Select all minor updates
46
+ - `l` - Select all latest updates
47
+ - `u` - Unselect all
48
+ - `/` - Search packages
49
+ - `t` - Change theme
50
+ - `i` - View package info
51
+ - `Enter` - Confirm and upgrade
80
52
 
81
- Examples:
53
+ ## Options
82
54
 
83
55
  ```bash
84
- # Basic usage - scans only dependencies and devDependencies
85
- inup
86
-
87
- # Include peer dependencies in the upgrade process
88
- inup --peer
89
-
90
- # Include optional dependencies
91
- inup --optional
56
+ inup [options]
92
57
 
93
- # Include both peer and optional dependencies
94
- inup --peer --optional
95
-
96
- # Skip example and test directories
97
- inup --exclude "example,test"
98
-
99
- # Skip specific paths with regex
100
- inup -e "example/.*,.*\.test\..*"
101
-
102
- # Run in a different directory
103
- inup --dir ../my-other-project
104
-
105
- # Combine multiple options
106
- inup --dir ./packages --peer --exclude "test,dist"
107
-
108
- # Force a specific package manager
109
- inup --package-manager npm
58
+ -d, --dir <path> Run in specific directory
59
+ -e, --exclude <patterns> Skip directories (comma-separated regex)
60
+ -p, --peer Include peer dependencies
61
+ -o, --optional Include optional dependencies
62
+ --package-manager <name> Force package manager (npm, yarn, pnpm, bun)
110
63
  ```
111
64
 
112
- ### How it works
113
-
114
- 1. **Detects your package manager** - Auto-detects from lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb) or package.json
115
- 2. **Scans your project** - Finds all package.json files recursively (respects exclude patterns)
116
- 3. **Collects dependencies** - Gathers dependencies based on your options (dependencies, devDependencies, and optionally peerDependencies/optionalDependencies)
117
- 4. **Checks for updates** - Queries npm registry for latest versions
118
- 5. **Shows you options** - Interactive UI lets you pick what to upgrade (minor updates or latest versions)
119
- 6. **Updates safely** - Modifies package.json files and runs the appropriate install command (`npm install`, `yarn install`, `pnpm install`, or `bun install`)
120
-
121
- ### Package Manager Detection
122
-
123
- inup automatically detects which package manager you're using by:
124
-
125
- 1. **Checking package.json** - Looks for the `packageManager` field
126
- 2. **Checking lock files** - Scans for:
127
- - `pnpm-lock.yaml` → pnpm
128
- - `bun.lockb` → bun
129
- - `yarn.lock` → yarn
130
- - `package-lock.json` → npm
131
- 3. **Fallback to npm** - If nothing is detected, defaults to npm with a warning
132
-
133
- You can override auto-detection using the `--package-manager` flag.
134
-
135
- ### FAQ
136
-
137
- **Q: How does inup detect my package manager?**
138
- A: It checks your `package.json` `packageManager` field first, then looks for lock files. You can manually override with `--package-manager`.
139
-
140
- **Q: What if I have multiple lock files?**
141
- A: inup will use the most recently modified lock file and show a warning. Consider cleaning up unused lock files.
142
-
143
- **Q: Can I force a specific package manager?**
144
- A: Yes! Use `--package-manager npm` (or yarn, pnpm, bun) to override auto-detection.
145
-
146
- **Q: What if the detected package manager isn't installed?**
147
- A: inup will still update your package.json files but skip the install step. It will show you the manual install command to run.
148
-
149
65
  ## License
150
66
 
151
67
  MIT
package/dist/cli.js CHANGED
File without changes
@@ -43,6 +43,8 @@ const semver = __importStar(require("semver"));
43
43
  const keypress = require('keypress');
44
44
  const ui_1 = require("./ui");
45
45
  const services_1 = require("./services");
46
+ const themes_1 = require("./ui/themes");
47
+ const themes_colors_1 = require("./ui/themes-colors");
46
48
  class InteractiveUI {
47
49
  constructor(packageManager) {
48
50
  this.renderer = new ui_1.UIRenderer();
@@ -189,37 +191,37 @@ class InteractiveUI {
189
191
  const filteredStates = stateManager.getFilteredStates(states);
190
192
  switch (action.type) {
191
193
  case 'navigate_up':
192
- if (!uiState.showInfoModal) {
194
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
193
195
  stateManager.navigateUp(filteredStates.length);
194
196
  }
195
197
  break;
196
198
  case 'navigate_down':
197
- if (!uiState.showInfoModal) {
199
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
198
200
  stateManager.navigateDown(filteredStates.length);
199
201
  }
200
202
  break;
201
203
  case 'select_left':
202
- if (!uiState.showInfoModal) {
204
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
203
205
  stateManager.updateSelection(filteredStates, 'left');
204
206
  }
205
207
  break;
206
208
  case 'select_right':
207
- if (!uiState.showInfoModal) {
209
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
208
210
  stateManager.updateSelection(filteredStates, 'right');
209
211
  }
210
212
  break;
211
213
  case 'bulk_select_minor':
212
- if (!uiState.showInfoModal) {
214
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
213
215
  stateManager.bulkSelectMinor(filteredStates);
214
216
  }
215
217
  break;
216
218
  case 'bulk_select_latest':
217
- if (!uiState.showInfoModal) {
219
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
218
220
  stateManager.bulkSelectLatest(filteredStates);
219
221
  }
220
222
  break;
221
223
  case 'bulk_unselect_all':
222
- if (!uiState.showInfoModal) {
224
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
223
225
  stateManager.bulkUnselectAll(filteredStates);
224
226
  }
225
227
  break;
@@ -275,6 +277,30 @@ class InteractiveUI {
275
277
  stateManager.setInitialRender(true);
276
278
  }
277
279
  break;
280
+ case 'toggle_theme_modal':
281
+ stateManager.toggleThemeModal();
282
+ break;
283
+ case 'theme_navigate_up': {
284
+ const themeManager = stateManager.getThemeManager();
285
+ const currentIndex = themes_1.themeNames.indexOf(themeManager.getPreviewTheme());
286
+ if (currentIndex > 0) {
287
+ const themeNames = Object.keys(themes_1.themes);
288
+ stateManager.previewTheme(themeNames[currentIndex - 1]);
289
+ }
290
+ break;
291
+ }
292
+ case 'theme_navigate_down': {
293
+ const themeManager = stateManager.getThemeManager();
294
+ const currentIndex = themes_1.themeNames.indexOf(themeManager.getPreviewTheme());
295
+ if (currentIndex < themes_1.themeNames.length - 1) {
296
+ const themeNames = Object.keys(themes_1.themes);
297
+ stateManager.previewTheme(themeNames[currentIndex + 1]);
298
+ }
299
+ break;
300
+ }
301
+ case 'theme_confirm':
302
+ stateManager.confirmTheme();
303
+ break;
278
304
  case 'cancel':
279
305
  handleCancel();
280
306
  return;
@@ -284,6 +310,8 @@ class InteractiveUI {
284
310
  }
285
311
  };
286
312
  const handleConfirm = (selectedStates) => {
313
+ // Reset terminal colors
314
+ process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
287
315
  ui_1.CursorUtils.show();
288
316
  // Clean up listeners
289
317
  if (process.stdin.setRawMode) {
@@ -295,6 +323,8 @@ class InteractiveUI {
295
323
  resolve(selectedStates);
296
324
  };
297
325
  const handleCancel = () => {
326
+ // Reset terminal colors
327
+ process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
298
328
  ui_1.CursorUtils.show();
299
329
  // Clean up listeners
300
330
  if (process.stdin.setRawMode) {
@@ -309,6 +339,9 @@ class InteractiveUI {
309
339
  const renderInterface = () => {
310
340
  const uiState = stateManager.getUIState();
311
341
  const filteredStates = stateManager.getFilteredStates(states);
342
+ // Apply terminal background color
343
+ const bgCode = (0, themes_colors_1.getTerminalBgColorCode)();
344
+ process.stdout.write(bgCode);
312
345
  if (uiState.forceFullRender) {
313
346
  console.clear();
314
347
  ui_1.CursorUtils.hide();
@@ -316,8 +349,27 @@ class InteractiveUI {
316
349
  else {
317
350
  ui_1.CursorUtils.moveToHome();
318
351
  }
319
- // If modal is open, render only the modal with header/footer
320
- if (uiState.showInfoModal && uiState.infoModalRow >= 0 && uiState.infoModalRow < filteredStates.length) {
352
+ // If theme modal is open, render only the theme selector
353
+ if (uiState.showThemeModal) {
354
+ const terminalWidth = process.stdout.columns || 80;
355
+ const terminalHeight = this.getTerminalHeight();
356
+ const themeManager = stateManager.getThemeManager();
357
+ // Render header
358
+ const headerLines = [];
359
+ headerLines.push(' ' + chalk_1.default.bold.magenta('🚀 inup'));
360
+ headerLines.push('');
361
+ headerLines.push(' ' +
362
+ chalk_1.default.bold.white('T ') +
363
+ chalk_1.default.gray('/ Esc Exit theme selector'));
364
+ headerLines.push('');
365
+ headerLines.forEach((line) => console.log(line));
366
+ const modalLines = this.renderer.renderThemeSelectorModal(themeManager.getCurrentTheme(), themeManager.getPreviewTheme(), terminalWidth, terminalHeight);
367
+ modalLines.forEach((line) => console.log(line));
368
+ // Clear any remaining lines from previous render
369
+ ui_1.CursorUtils.clearToEndOfScreen();
370
+ stateManager.markRendered([]);
371
+ }
372
+ else if (uiState.showInfoModal && uiState.infoModalRow >= 0 && uiState.infoModalRow < filteredStates.length) {
321
373
  const selectedState = filteredStates[uiState.infoModalRow];
322
374
  const terminalWidth = process.stdout.columns || 80;
323
375
  const terminalHeight = this.getTerminalHeight();
@@ -346,10 +398,11 @@ class InteractiveUI {
346
398
  }
347
399
  else {
348
400
  // Normal list view (flat rendering - no grouping)
401
+ const terminalWidth = process.stdout.columns || 80;
349
402
  const lines = this.renderer.renderInterface(filteredStates, uiState.currentRow, uiState.scrollOffset, uiState.maxVisibleItems, uiState.forceFullRender, [], // No renderable items - use flat rendering
350
403
  dependencyTypeLabel, // Show which dependency type we're upgrading
351
404
  this.packageManager, // Pass package manager info for header
352
- uiState.filterMode, uiState.filterQuery, states.length);
405
+ uiState.filterMode, uiState.filterQuery, states.length, terminalWidth);
353
406
  // Print all lines
354
407
  lines.forEach((line) => console.log(line));
355
408
  // Clear any remaining lines from previous render
@@ -386,6 +439,8 @@ class InteractiveUI {
386
439
  renderInterface();
387
440
  }
388
441
  catch (error) {
442
+ // Reset terminal colors
443
+ process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
389
444
  // Fallback to simple interface if raw mode fails
390
445
  console.log(chalk_1.default.yellow('Raw mode not available, using fallback interface...'));
391
446
  resolve(states);
package/dist/ui/index.js CHANGED
@@ -1,17 +1,21 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ConfirmationInputHandler = exports.InputHandler = exports.UIRenderer = exports.FilterManager = exports.ModalManager = exports.NavigationManager = exports.StateManager = exports.CursorUtils = exports.VersionUtils = void 0;
4
- var utils_1 = require("./utils");
5
- Object.defineProperty(exports, "VersionUtils", { enumerable: true, get: function () { return utils_1.VersionUtils; } });
6
- Object.defineProperty(exports, "CursorUtils", { enumerable: true, get: function () { return utils_1.CursorUtils; } });
7
- var state_1 = require("./state");
8
- Object.defineProperty(exports, "StateManager", { enumerable: true, get: function () { return state_1.StateManager; } });
9
- Object.defineProperty(exports, "NavigationManager", { enumerable: true, get: function () { return state_1.NavigationManager; } });
10
- Object.defineProperty(exports, "ModalManager", { enumerable: true, get: function () { return state_1.ModalManager; } });
11
- Object.defineProperty(exports, "FilterManager", { enumerable: true, get: function () { return state_1.FilterManager; } });
12
- var index_1 = require("./renderer/index");
13
- Object.defineProperty(exports, "UIRenderer", { enumerable: true, get: function () { return index_1.UIRenderer; } });
14
- var input_handler_1 = require("./input-handler");
15
- Object.defineProperty(exports, "InputHandler", { enumerable: true, get: function () { return input_handler_1.InputHandler; } });
16
- Object.defineProperty(exports, "ConfirmationInputHandler", { enumerable: true, get: function () { return input_handler_1.ConfirmationInputHandler; } });
17
+ __exportStar(require("./utils"), exports);
18
+ __exportStar(require("./state"), exports);
19
+ __exportStar(require("./renderer"), exports);
20
+ __exportStar(require("./input-handler"), exports);
17
21
  //# sourceMappingURL=index.js.map
@@ -19,6 +19,28 @@ class InputHandler {
19
19
  process.exit(0);
20
20
  }
21
21
  const uiState = this.stateManager.getUIState();
22
+ // Handle theme modal input
23
+ if (uiState.showThemeModal) {
24
+ if (key) {
25
+ switch (key.name) {
26
+ case 'escape':
27
+ this.onAction({ type: 'toggle_theme_modal' });
28
+ return;
29
+ case 'return':
30
+ this.onAction({ type: 'theme_confirm' });
31
+ return;
32
+ case 'up':
33
+ this.onAction({ type: 'theme_navigate_up' });
34
+ return;
35
+ case 'down':
36
+ this.onAction({ type: 'theme_navigate_down' });
37
+ return;
38
+ default:
39
+ return;
40
+ }
41
+ }
42
+ return;
43
+ }
22
44
  // Check for '/' character to enter filter mode (only in normal mode, not in modal or already in filter)
23
45
  if (str === '/' && !uiState.showInfoModal && !uiState.filterMode) {
24
46
  this.onAction({ type: 'enter_filter_mode' });
@@ -113,6 +135,10 @@ class InputHandler {
113
135
  case 'I':
114
136
  this.onAction({ type: 'toggle_info_modal' });
115
137
  break;
138
+ case 't':
139
+ case 'T':
140
+ this.onAction({ type: 'toggle_theme_modal' });
141
+ break;
116
142
  case 'escape':
117
143
  // Check if modal is open - if so, close it; otherwise cancel
118
144
  if (uiState.showInfoModal) {
@@ -40,6 +40,7 @@ exports.UIRenderer = void 0;
40
40
  const PackageList = __importStar(require("./package-list"));
41
41
  const Confirmation = __importStar(require("./confirmation"));
42
42
  const Modal = __importStar(require("./modal"));
43
+ const ThemeSelector = __importStar(require("./theme-selector"));
43
44
  /**
44
45
  * Main UI renderer class that composes all rendering parts
45
46
  */
@@ -53,8 +54,8 @@ class UIRenderer {
53
54
  renderSpacer() {
54
55
  return PackageList.renderSpacer();
55
56
  }
56
- renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forceFullRender, renderableItems, dependencyTypeLabel, packageManager, filterMode, filterQuery, totalPackagesBeforeFilter) {
57
- return PackageList.renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forceFullRender, renderableItems, dependencyTypeLabel, packageManager, filterMode, filterQuery, totalPackagesBeforeFilter);
57
+ renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forceFullRender, renderableItems, dependencyTypeLabel, packageManager, filterMode, filterQuery, totalPackagesBeforeFilter, terminalWidth = 80) {
58
+ return PackageList.renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forceFullRender, renderableItems, dependencyTypeLabel, packageManager, filterMode, filterQuery, totalPackagesBeforeFilter, terminalWidth);
58
59
  }
59
60
  renderPackagesTable(packages) {
60
61
  return PackageList.renderPackagesTable(packages);
@@ -68,10 +69,14 @@ class UIRenderer {
68
69
  renderPackageInfoModal(state, terminalWidth = 80, terminalHeight = 24) {
69
70
  return Modal.renderPackageInfoModal(state, terminalWidth, terminalHeight);
70
71
  }
72
+ renderThemeSelectorModal(currentTheme, previewTheme, terminalWidth = 80, terminalHeight = 24) {
73
+ return ThemeSelector.renderThemeSelectorModal(currentTheme, previewTheme, terminalWidth, terminalHeight);
74
+ }
71
75
  }
72
76
  exports.UIRenderer = UIRenderer;
73
77
  // Re-export all functions for direct use if needed
74
78
  __exportStar(require("./package-list"), exports);
75
79
  __exportStar(require("./confirmation"), exports);
76
80
  __exportStar(require("./modal"), exports);
81
+ __exportStar(require("./theme-selector"), exports);
77
82
  //# sourceMappingURL=index.js.map