inup 1.4.1 → 1.4.3

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
@@ -18,8 +18,6 @@ program
18
18
  .version(packageJson.version)
19
19
  .option('-d, --dir <directory>', 'specify directory to run in', process.cwd())
20
20
  .option('-e, --exclude <patterns>', 'exclude paths matching regex patterns (comma-separated)', '')
21
- .option('-p, --peer', 'include peer dependencies in upgrade process')
22
- .option('-o, --optional', 'include optional dependencies in upgrade process')
23
21
  .option('--package-manager <name>', 'manually specify package manager (npm, yarn, pnpm, bun)')
24
22
  .action(async (options) => {
25
23
  console.log(chalk_1.default.bold.blue(`🚀 `) + chalk_1.default.bold.red(`i`) + chalk_1.default.bold.yellow(`n`) + chalk_1.default.bold.blue(`u`) + chalk_1.default.bold.magenta(`p`) + `\n`);
@@ -31,10 +29,6 @@ program
31
29
  .map((p) => p.trim())
32
30
  .filter(Boolean)
33
31
  : [];
34
- // Commander.js: boolean flags are undefined if not provided, true if provided
35
- // Both flags default to false (opt-in)
36
- const includePeerDeps = options.peer === true;
37
- const includeOptionalDeps = options.optional === true;
38
32
  // Validate package manager if provided
39
33
  let packageManager;
40
34
  if (options.packageManager) {
@@ -49,8 +43,6 @@ program
49
43
  const upgrader = new index_1.UpgradeRunner({
50
44
  cwd: options.dir,
51
45
  excludePatterns,
52
- includePeerDeps,
53
- includeOptionalDeps,
54
46
  packageManager,
55
47
  });
56
48
  await upgrader.run();
@@ -1,33 +1,11 @@
1
1
  "use strict";
2
- /**
3
- * Constants for npm registry queries and configuration
4
- */
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.WORKSPACE_FILES = exports.LOCK_FILES = exports.DEFAULT_REGISTRY = exports.REQUEST_TIMEOUT = exports.CACHE_TTL = exports.MAX_CONCURRENT_REQUESTS = exports.JSDELIVR_CDN_URL = exports.NPM_REGISTRY_URL = void 0;
3
+ exports.DEFAULT_REGISTRY = exports.REQUEST_TIMEOUT = exports.CACHE_TTL = exports.MAX_CONCURRENT_REQUESTS = exports.JSDELIVR_CDN_URL = exports.NPM_REGISTRY_URL = exports.PACKAGE_NAME = void 0;
4
+ exports.PACKAGE_NAME = 'inup';
7
5
  exports.NPM_REGISTRY_URL = 'https://registry.npmjs.org';
8
6
  exports.JSDELIVR_CDN_URL = 'https://cdn.jsdelivr.net/npm';
9
7
  exports.MAX_CONCURRENT_REQUESTS = 150;
10
8
  exports.CACHE_TTL = 5 * 60 * 1000; // 5 minutes in milliseconds
11
9
  exports.REQUEST_TIMEOUT = 60000; // 60 seconds in milliseconds
12
- /**
13
- * Registry selection: 'jsdelivr' for fast CDN lookups, 'npm' for direct npm registry
14
- * Set to 'npm' to use npm registry by default instead of jsdelivr
15
- */
16
10
  exports.DEFAULT_REGISTRY = 'jsdelivr';
17
- /**
18
- * Package manager lock files
19
- */
20
- exports.LOCK_FILES = {
21
- npm: 'package-lock.json',
22
- yarn: 'yarn.lock',
23
- pnpm: 'pnpm-lock.yaml',
24
- bun: 'bun.lockb',
25
- };
26
- /**
27
- * Package manager workspace files
28
- */
29
- exports.WORKSPACE_FILES = {
30
- pnpm: 'pnpm-workspace.yaml',
31
- // npm, yarn, and bun use package.json workspaces field
32
- };
33
11
  //# sourceMappingURL=constants.js.map
@@ -44,9 +44,6 @@ class PackageDetector {
44
44
  this.packageJson = null;
45
45
  this.cwd = options?.cwd || process.cwd();
46
46
  this.excludePatterns = options?.excludePatterns || [];
47
- // Explicitly check for true to ensure false/undefined both become false (opt-in)
48
- this.includePeerDeps = options?.includePeerDeps === true;
49
- this.includeOptionalDeps = options?.includeOptionalDeps === true;
50
47
  this.packageJsonPath = (0, utils_1.findPackageJson)(this.cwd);
51
48
  if (this.packageJsonPath) {
52
49
  this.packageJson = (0, utils_1.readPackageJson)(this.packageJsonPath);
@@ -67,8 +64,8 @@ class PackageDetector {
67
64
  // Step 2: Collect all dependencies from package.json files (parallelized)
68
65
  this.showProgress('🔍 Reading dependencies from package.json files...');
69
66
  const allDepsRaw = await (0, utils_1.collectAllDependenciesAsync)(allPackageJsonFiles, {
70
- includePeerDeps: this.includePeerDeps,
71
- includeOptionalDeps: this.includeOptionalDeps,
67
+ includePeerDeps: true,
68
+ includeOptionalDeps: true,
72
69
  });
73
70
  // Step 3: Get unique package names while filtering out workspace references
74
71
  this.showProgress('🔍 Identifying unique packages...');
@@ -44,11 +44,8 @@ class UpgradeRunner {
44
44
  let shouldProceed = false;
45
45
  let previousSelections;
46
46
  while (true) {
47
- // Interactive selection (pass options for filtering)
48
- selectedChoices = await this.ui.selectPackagesToUpgrade(packages, previousSelections, {
49
- includePeerDeps: this.options?.includePeerDeps,
50
- includeOptionalDeps: this.options?.includeOptionalDeps,
51
- });
47
+ // Interactive selection
48
+ selectedChoices = await this.ui.selectPackagesToUpgrade(packages, previousSelections);
52
49
  if (selectedChoices.length === 0) {
53
50
  console.log(chalk_1.default.yellow('No packages selected. Exiting...'));
54
51
  return;
@@ -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();
@@ -51,51 +53,14 @@ class InteractiveUI {
51
53
  async displayPackagesTable(packages) {
52
54
  console.log(this.renderer.renderPackagesTable(packages));
53
55
  }
54
- async selectPackagesToUpgrade(packages, previousSelections, options) {
56
+ async selectPackagesToUpgrade(packages, previousSelections) {
55
57
  const outdatedPackages = packages.filter((p) => p.isOutdated);
56
58
  if (outdatedPackages.length === 0) {
57
59
  return [];
58
60
  }
59
- // Filter packages based on CLI options.
60
- // IMPORTANT: This uses an opt-in approach where:
61
- // - Default (no flags): shows dependencies + devDependencies
62
- // - With -p flag: shows ONLY peerDependencies (excludes dependencies)
63
- // - With -o flag: shows ONLY optionalDependencies (excludes dependencies)
64
- // - With -p -o flags: shows peerDependencies + optionalDependencies (excludes dependencies)
65
- //
66
- // This design allows users to focus on one dependency type at a time,
67
- // which is useful since peer/optional deps have different upgrade semantics.
68
- let filteredPackages = outdatedPackages;
69
- let dependencyTypeLabel = '';
70
- if (options?.includePeerDeps || options?.includeOptionalDeps) {
71
- // If any special-case flag is provided, filter to show ONLY those types
72
- // (excluding regular dependencies/devDependencies)
73
- filteredPackages = outdatedPackages.filter((pkg) => {
74
- if (options.includePeerDeps && pkg.type === 'peerDependencies')
75
- return true;
76
- if (options.includeOptionalDeps && pkg.type === 'optionalDependencies')
77
- return true;
78
- return false;
79
- });
80
- // Build label describing which types are shown
81
- const types = [];
82
- if (options.includePeerDeps)
83
- types.push('Peer Deps');
84
- if (options.includeOptionalDeps)
85
- types.push('Optional Deps');
86
- dependencyTypeLabel = types.join(' & ');
87
- }
88
- else {
89
- // Default: show only regular dependencies and devDependencies
90
- filteredPackages = outdatedPackages.filter((pkg) => pkg.type === 'dependencies' || pkg.type === 'devDependencies');
91
- dependencyTypeLabel = 'Deps & Dev Deps';
92
- }
93
- if (filteredPackages.length === 0) {
94
- return [];
95
- }
96
61
  // Deduplicate packages by name and version specifier, but track all package.json paths
97
62
  const uniquePackages = new Map();
98
- for (const pkg of filteredPackages) {
63
+ for (const pkg of outdatedPackages) {
99
64
  const key = `${pkg.name}@${pkg.currentVersion}`;
100
65
  if (!uniquePackages.has(key)) {
101
66
  uniquePackages.set(key, {
@@ -148,7 +113,7 @@ class InteractiveUI {
148
113
  };
149
114
  });
150
115
  // Use custom interactive table selector (simplified - no grouping)
151
- const selectedStates = await this.interactiveTableSelector(selectionStates, dependencyTypeLabel);
116
+ const selectedStates = await this.interactiveTableSelector(selectionStates);
152
117
  // Convert to PackageUpgradeChoice[] - create one choice per package.json path
153
118
  const choices = [];
154
119
  selectedStates
@@ -177,7 +142,7 @@ class InteractiveUI {
177
142
  }
178
143
  return 24; // Fallback default
179
144
  }
180
- async interactiveTableSelector(selectionStates, dependencyTypeLabel) {
145
+ async interactiveTableSelector(selectionStates) {
181
146
  return new Promise((resolve) => {
182
147
  const states = [...selectionStates];
183
148
  const stateManager = new ui_1.StateManager(0, this.getTerminalHeight());
@@ -189,40 +154,45 @@ class InteractiveUI {
189
154
  const filteredStates = stateManager.getFilteredStates(states);
190
155
  switch (action.type) {
191
156
  case 'navigate_up':
192
- if (!uiState.showInfoModal) {
157
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
193
158
  stateManager.navigateUp(filteredStates.length);
194
159
  }
195
160
  break;
196
161
  case 'navigate_down':
197
- if (!uiState.showInfoModal) {
162
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
198
163
  stateManager.navigateDown(filteredStates.length);
199
164
  }
200
165
  break;
201
166
  case 'select_left':
202
- if (!uiState.showInfoModal) {
167
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
203
168
  stateManager.updateSelection(filteredStates, 'left');
204
169
  }
205
170
  break;
206
171
  case 'select_right':
207
- if (!uiState.showInfoModal) {
172
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
208
173
  stateManager.updateSelection(filteredStates, 'right');
209
174
  }
210
175
  break;
211
176
  case 'bulk_select_minor':
212
- if (!uiState.showInfoModal) {
177
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
213
178
  stateManager.bulkSelectMinor(filteredStates);
214
179
  }
215
180
  break;
216
181
  case 'bulk_select_latest':
217
- if (!uiState.showInfoModal) {
182
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
218
183
  stateManager.bulkSelectLatest(filteredStates);
219
184
  }
220
185
  break;
221
186
  case 'bulk_unselect_all':
222
- if (!uiState.showInfoModal) {
187
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
223
188
  stateManager.bulkUnselectAll(filteredStates);
224
189
  }
225
190
  break;
191
+ case 'toggle_dep_type_filter':
192
+ if (!uiState.showInfoModal && !uiState.showThemeModal) {
193
+ stateManager.toggleDependencyTypeFilter(action.depType);
194
+ }
195
+ break;
226
196
  case 'toggle_info_modal':
227
197
  if (!uiState.showInfoModal) {
228
198
  // Opening modal - load package info asynchronously
@@ -275,6 +245,28 @@ class InteractiveUI {
275
245
  stateManager.setInitialRender(true);
276
246
  }
277
247
  break;
248
+ case 'toggle_theme_modal':
249
+ stateManager.toggleThemeModal();
250
+ break;
251
+ case 'theme_navigate_up': {
252
+ const themeManager = stateManager.getThemeManager();
253
+ const currentIndex = themes_1.themeNames.indexOf(themeManager.getPreviewTheme());
254
+ const themeArray = Object.keys(themes_1.themes);
255
+ const nextIndex = currentIndex > 0 ? currentIndex - 1 : themeArray.length - 1;
256
+ stateManager.previewTheme(themeArray[nextIndex]);
257
+ break;
258
+ }
259
+ case 'theme_navigate_down': {
260
+ const themeManager = stateManager.getThemeManager();
261
+ const currentIndex = themes_1.themeNames.indexOf(themeManager.getPreviewTheme());
262
+ const themeArray = Object.keys(themes_1.themes);
263
+ const nextIndex = currentIndex < themeArray.length - 1 ? currentIndex + 1 : 0;
264
+ stateManager.previewTheme(themeArray[nextIndex]);
265
+ break;
266
+ }
267
+ case 'theme_confirm':
268
+ stateManager.confirmTheme();
269
+ break;
278
270
  case 'cancel':
279
271
  handleCancel();
280
272
  return;
@@ -284,6 +276,8 @@ class InteractiveUI {
284
276
  }
285
277
  };
286
278
  const handleConfirm = (selectedStates) => {
279
+ // Reset terminal colors
280
+ process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
287
281
  ui_1.CursorUtils.show();
288
282
  // Clean up listeners
289
283
  if (process.stdin.setRawMode) {
@@ -295,6 +289,8 @@ class InteractiveUI {
295
289
  resolve(selectedStates);
296
290
  };
297
291
  const handleCancel = () => {
292
+ // Reset terminal colors
293
+ process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
298
294
  ui_1.CursorUtils.show();
299
295
  // Clean up listeners
300
296
  if (process.stdin.setRawMode) {
@@ -309,6 +305,9 @@ class InteractiveUI {
309
305
  const renderInterface = () => {
310
306
  const uiState = stateManager.getUIState();
311
307
  const filteredStates = stateManager.getFilteredStates(states);
308
+ // Apply terminal background color
309
+ const bgCode = (0, themes_colors_1.getTerminalBgColorCode)();
310
+ process.stdout.write(bgCode);
312
311
  if (uiState.forceFullRender) {
313
312
  console.clear();
314
313
  ui_1.CursorUtils.hide();
@@ -316,8 +315,27 @@ class InteractiveUI {
316
315
  else {
317
316
  ui_1.CursorUtils.moveToHome();
318
317
  }
319
- // If modal is open, render only the modal with header/footer
320
- if (uiState.showInfoModal && uiState.infoModalRow >= 0 && uiState.infoModalRow < filteredStates.length) {
318
+ // If theme modal is open, render only the theme selector
319
+ if (uiState.showThemeModal) {
320
+ const terminalWidth = process.stdout.columns || 80;
321
+ const terminalHeight = this.getTerminalHeight();
322
+ const themeManager = stateManager.getThemeManager();
323
+ // Render header
324
+ const headerLines = [];
325
+ headerLines.push(' ' + chalk_1.default.bold.magenta('🚀 inup'));
326
+ headerLines.push('');
327
+ headerLines.push(' ' +
328
+ chalk_1.default.bold.white('T ') +
329
+ chalk_1.default.gray('/ Esc Exit theme selector'));
330
+ headerLines.push('');
331
+ headerLines.forEach((line) => console.log(line));
332
+ const modalLines = this.renderer.renderThemeSelectorModal(themeManager.getCurrentTheme(), themeManager.getPreviewTheme(), terminalWidth, terminalHeight);
333
+ modalLines.forEach((line) => console.log(line));
334
+ // Clear any remaining lines from previous render
335
+ ui_1.CursorUtils.clearToEndOfScreen();
336
+ stateManager.markRendered([]);
337
+ }
338
+ else if (uiState.showInfoModal && uiState.infoModalRow >= 0 && uiState.infoModalRow < filteredStates.length) {
321
339
  const selectedState = filteredStates[uiState.infoModalRow];
322
340
  const terminalWidth = process.stdout.columns || 80;
323
341
  const terminalHeight = this.getTerminalHeight();
@@ -346,10 +364,12 @@ class InteractiveUI {
346
364
  }
347
365
  else {
348
366
  // Normal list view (flat rendering - no grouping)
367
+ const terminalWidth = process.stdout.columns || 80;
368
+ const activeFilterLabel = stateManager.getActiveFilterLabel();
349
369
  const lines = this.renderer.renderInterface(filteredStates, uiState.currentRow, uiState.scrollOffset, uiState.maxVisibleItems, uiState.forceFullRender, [], // No renderable items - use flat rendering
350
- dependencyTypeLabel, // Show which dependency type we're upgrading
370
+ activeFilterLabel, // Show current dependency type filter state
351
371
  this.packageManager, // Pass package manager info for header
352
- uiState.filterMode, uiState.filterQuery, states.length);
372
+ uiState.filterMode, uiState.filterQuery, states.length, terminalWidth);
353
373
  // Print all lines
354
374
  lines.forEach((line) => console.log(line));
355
375
  // Clear any remaining lines from previous render
@@ -386,6 +406,8 @@ class InteractiveUI {
386
406
  renderInterface();
387
407
  }
388
408
  catch (error) {
409
+ // Reset terminal colors
410
+ process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
389
411
  // Fallback to simple interface if raw mode fails
390
412
  console.log(chalk_1.default.yellow('Raw mode not available, using fallback interface...'));
391
413
  resolve(states);