inup 1.6.6 → 1.6.8

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.
Files changed (110) hide show
  1. package/README.md +25 -2
  2. package/dist/{interactive-ui.js → app/interactive-ui.js} +34 -21
  3. package/dist/{core → app}/upgrade-runner.js +18 -22
  4. package/dist/cli.js +19 -18
  5. package/dist/{services → features/audit}/background-audit.js +2 -2
  6. package/dist/features/{headless/vulnerability-audit.js → audit/headless-audit.js} +8 -11
  7. package/dist/features/audit/index.js +36 -0
  8. package/dist/{ui/presenters/vulnerability.js → features/audit/presenter.js} +1 -3
  9. package/dist/{ui/controllers → features/audit}/vulnerability-audit-controller.js +14 -8
  10. package/dist/{services → features/audit}/vulnerability-checker.js +9 -10
  11. package/dist/features/changelog/clients/github-client.js +41 -21
  12. package/dist/features/changelog/clients/npm-registry-client.js +16 -2
  13. package/dist/features/changelog/index.js +1 -1
  14. package/dist/features/changelog/services/package-metadata-service.js +6 -2
  15. package/dist/features/changelog/services/release-notes-service.js +9 -12
  16. package/dist/features/changelog/types.js +3 -0
  17. package/dist/features/debug/index.js +3 -4
  18. package/dist/features/debug/{services/perf-logger.js → perf-logger.js} +15 -15
  19. package/dist/features/debug/types.js +3 -0
  20. package/dist/features/headless/headless-runner.js +32 -19
  21. package/dist/features/headless/index.js +2 -5
  22. package/dist/features/headless/report.js +2 -0
  23. package/dist/features/interactive/controllers/index.js +6 -0
  24. package/dist/{ui → features/interactive}/controllers/package-info-modal-controller.js +3 -3
  25. package/dist/features/interactive/index.js +21 -0
  26. package/dist/{ui → features/interactive}/input-handler.js +6 -6
  27. package/dist/{ui → features/interactive}/modal/index.js +1 -1
  28. package/dist/{ui → features/interactive}/modal/layout.js +5 -5
  29. package/dist/{ui/renderer/package-list.js → features/interactive/modal/package-info-sections/index.js} +3 -3
  30. package/dist/{ui → features/interactive}/modal/package-info-sections/release-notes.js +1 -1
  31. package/dist/{ui → features/interactive}/modal/package-info-sections/sections.js +55 -24
  32. package/dist/{ui → features/interactive}/modal/package-info-sections/text.js +6 -6
  33. package/dist/{ui → features/interactive}/modal/package-info.js +33 -18
  34. package/dist/features/interactive/modal/types.js +3 -0
  35. package/dist/{ui → features/interactive}/presenters/health.js +2 -2
  36. package/dist/{ui → features/interactive}/renderer/confirmation.js +6 -3
  37. package/dist/{ui → features/interactive}/renderer/help-modal.js +3 -3
  38. package/dist/{ui → features/interactive}/renderer/index.js +3 -4
  39. package/dist/{types.js → features/interactive/renderer/package-list/index.js} +3 -4
  40. package/dist/{ui → features/interactive}/renderer/package-list/interface.js +15 -16
  41. package/dist/{ui → features/interactive}/renderer/package-list/rows.js +31 -25
  42. package/dist/features/{debug → interactive}/renderer/performance-modal.js +3 -3
  43. package/dist/{ui/utils/version.js → features/interactive/renderer/version-format.js} +9 -13
  44. package/dist/{ui → features/interactive}/session/action-dispatcher.js +2 -2
  45. package/dist/{ui → features/interactive}/session/index.js +5 -4
  46. package/dist/{ui → features/interactive}/session/interactive-session.js +44 -23
  47. package/dist/{ui → features/interactive}/session/selection-state-builder.js +25 -9
  48. package/dist/{ui → features/interactive}/state/filter-manager.js +3 -3
  49. package/dist/{ui → features/interactive}/state/index.js +7 -7
  50. package/dist/{ui → features/interactive}/state/state-manager.js +10 -8
  51. package/dist/{ui → features/interactive}/state/theme-manager.js +7 -5
  52. package/dist/{ui → features/interactive}/themes-colors.js +3 -1
  53. package/dist/features/upgrade/index.js +8 -0
  54. package/dist/{core → features/upgrade}/package-detector.js +96 -37
  55. package/dist/{core → features/upgrade}/upgrader.js +84 -35
  56. package/dist/index.js +2 -2
  57. package/dist/{config → shared/config}/package-meta.js +1 -1
  58. package/dist/{config → shared/config}/project-config.js +10 -8
  59. package/dist/{utils/config.js → shared/config/user-config.js} +11 -11
  60. package/dist/{utils → shared}/debug-logger.js +9 -9
  61. package/dist/{utils → shared}/exec.js +4 -4
  62. package/dist/{ui/modal/package-info-sections.js → shared/fs/index.js} +4 -3
  63. package/dist/{utils/filesystem → shared/fs}/io.js +3 -4
  64. package/dist/shared/fs/paths.js +19 -0
  65. package/dist/{utils/filesystem → shared/fs}/scan.js +23 -20
  66. package/dist/{utils → shared}/git.js +3 -3
  67. package/dist/{services → shared}/http/etag-store.js +56 -4
  68. package/dist/{services → shared}/http/resizable-semaphore.js +3 -1
  69. package/dist/{utils → shared}/local-env.js +8 -8
  70. package/dist/{services/package-manager-detector.js → shared/package-manager.js} +26 -25
  71. package/dist/shared/pnpm-catalogs.js +138 -0
  72. package/dist/{services → shared/registry}/npm-registry.js +54 -33
  73. package/dist/shared/registry/registry-config.js +76 -0
  74. package/dist/{services → shared/registry}/version-checker.js +25 -26
  75. package/dist/{ui/utils → shared/terminal}/cursor.js +1 -1
  76. package/dist/{ui/utils → shared/terminal}/index.js +5 -7
  77. package/dist/{ui/utils → shared/terminal}/terminal-input.js +5 -0
  78. package/dist/shared/terminal/text.js +48 -0
  79. package/dist/shared/types/index.js +20 -0
  80. package/dist/{utils/version.js → shared/versions.js} +45 -30
  81. package/package.json +21 -8
  82. package/dist/core/index.js +0 -23
  83. package/dist/features/changelog/types/changelog.types.js +0 -3
  84. package/dist/features/debug/types/debug.types.js +0 -3
  85. package/dist/services/index.js +0 -25
  86. package/dist/ui/controllers/index.js +0 -8
  87. package/dist/ui/index.js +0 -27
  88. package/dist/ui/presenters/index.js +0 -11
  89. package/dist/ui/utils/text.js +0 -76
  90. package/dist/utils/filesystem/paths.js +0 -19
  91. package/dist/utils/filesystem.js +0 -20
  92. package/dist/utils/index.js +0 -34
  93. /package/dist/{ui/modal → features/audit}/types.js +0 -0
  94. /package/dist/features/debug/{services/performance-tracker.js → performance-tracker.js} +0 -0
  95. /package/dist/{ui → features/interactive}/keymap.js +0 -0
  96. /package/dist/{ui → features/interactive}/modal/theme-selector.js +0 -0
  97. /package/dist/{ui → features/interactive}/state/modal-manager.js +0 -0
  98. /package/dist/{ui → features/interactive}/state/navigation-manager.js +0 -0
  99. /package/dist/{ui → features/interactive}/themes.js +0 -0
  100. /package/dist/{config → shared/config}/constants.js +0 -0
  101. /package/dist/{config → shared/config}/index.js +0 -0
  102. /package/dist/{utils → shared}/engines.js +0 -0
  103. /package/dist/{services → shared}/http/adaptive-controller.js +0 -0
  104. /package/dist/{services → shared}/http/inflight.js +0 -0
  105. /package/dist/{services → shared}/http/retry.js +0 -0
  106. /package/dist/{utils → shared}/manifest.js +0 -0
  107. /package/dist/{utils → shared/terminal}/color.js +0 -0
  108. /package/dist/{types → shared/types}/domain.js +0 -0
  109. /package/dist/{types → shared/types}/streaming.js +0 -0
  110. /package/dist/{types → shared/types}/ui.js +0 -0
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StateManager = void 0;
4
- const navigation_manager_1 = require("./navigation-manager");
5
- const modal_manager_1 = require("./modal-manager");
6
4
  const filter_manager_1 = require("./filter-manager");
5
+ const modal_manager_1 = require("./modal-manager");
6
+ const navigation_manager_1 = require("./navigation-manager");
7
7
  const theme_manager_1 = require("./theme-manager");
8
8
  class StateManager {
9
9
  navigationManager;
@@ -99,7 +99,7 @@ class StateManager {
99
99
  return;
100
100
  const currentRow = this.navigationManager.getCurrentRow();
101
101
  const currentState = states[currentRow];
102
- if (!currentState || currentState.loadState !== 'ready')
102
+ if (currentState?.loadState !== 'ready')
103
103
  return;
104
104
  if (direction === 'left') {
105
105
  // Move selection left with wraparound: latest -> range -> none -> latest
@@ -114,8 +114,9 @@ class StateManager {
114
114
  else if (currentState.selectedOption === 'range') {
115
115
  currentState.selectedOption = 'none';
116
116
  }
117
- else if (currentState.selectedOption === 'none') {
118
- // Wrap around to the last available option
117
+ else {
118
+ // selectedOption === 'none' (the union has exactly three members):
119
+ // wrap around to the last available option.
119
120
  if (currentState.hasMajorUpdate) {
120
121
  currentState.selectedOption = 'latest';
121
122
  }
@@ -143,8 +144,9 @@ class StateManager {
143
144
  currentState.selectedOption = 'none';
144
145
  }
145
146
  }
146
- else if (currentState.selectedOption === 'latest') {
147
- // Wrap around to none
147
+ else {
148
+ // selectedOption === 'latest' (the union has exactly three members):
149
+ // wrap around to none.
148
150
  currentState.selectedOption = 'none';
149
151
  }
150
152
  }
@@ -185,7 +187,7 @@ class StateManager {
185
187
  if (states.length === 0)
186
188
  return;
187
189
  const currentState = states[this.navigationManager.getCurrentRow()];
188
- if (!currentState || currentState.loadState !== 'ready')
190
+ if (currentState?.loadState !== 'ready')
189
191
  return;
190
192
  if (currentState.selectedOption !== 'none') {
191
193
  currentState.selectedOption = 'none';
@@ -3,15 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ThemeManager = void 0;
4
4
  exports.getThemeColors = getThemeColors;
5
5
  exports.getCurrentThemeName = getCurrentThemeName;
6
+ const user_config_1 = require("../../../shared/config/user-config");
6
7
  const themes_1 = require("../themes");
7
- const config_1 = require("../../utils/config");
8
8
  // Global theme state for renderers to access
9
9
  let globalCurrentTheme = themes_1.defaultTheme;
10
10
  class ThemeManager {
11
11
  state;
12
12
  constructor() {
13
13
  // Load saved theme from config, fallback to default
14
- const savedTheme = config_1.configManager.getTheme();
14
+ const savedTheme = user_config_1.configManager.getTheme();
15
15
  const initialTheme = savedTheme && themes_1.themeNames.includes(savedTheme) ? savedTheme : themes_1.defaultTheme;
16
16
  this.state = {
17
17
  showThemeModal: false,
@@ -55,7 +55,7 @@ class ThemeManager {
55
55
  this.state.currentTheme = this.state.previewTheme;
56
56
  globalCurrentTheme = this.state.currentTheme;
57
57
  // Save theme to config
58
- config_1.configManager.setTheme(this.state.currentTheme);
58
+ user_config_1.configManager.setTheme(this.state.currentTheme);
59
59
  this.closeThemeModal();
60
60
  }
61
61
  setTheme(themeName) {
@@ -64,7 +64,7 @@ class ThemeManager {
64
64
  this.state.previewTheme = themeName;
65
65
  globalCurrentTheme = themeName;
66
66
  // Save theme to config
67
- config_1.configManager.setTheme(themeName);
67
+ user_config_1.configManager.setTheme(themeName);
68
68
  }
69
69
  }
70
70
  toggleThemeModal() {
@@ -79,7 +79,9 @@ class ThemeManager {
79
79
  exports.ThemeManager = ThemeManager;
80
80
  // Helper function for renderers to get current theme colors
81
81
  function getThemeColors() {
82
- return themes_1.themes[globalCurrentTheme]?.colors || themes_1.themes[themes_1.defaultTheme].colors;
82
+ // globalCurrentTheme is only ever assigned a name validated against
83
+ // themeNames, so the lookup always resolves.
84
+ return themes_1.themes[globalCurrentTheme].colors;
83
85
  }
84
86
  // Helper function to get current theme name
85
87
  function getCurrentThemeName() {
@@ -6,12 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.themeColors = void 0;
7
7
  exports.getThemeColor = getThemeColor;
8
8
  exports.getThemeBgColor = getThemeBgColor;
9
+ exports.hexToRgb = hexToRgb;
9
10
  exports.getTerminalBgColorCode = getTerminalBgColorCode;
10
11
  exports.getTerminalResetCode = getTerminalResetCode;
11
12
  exports.coloredInupLogo = coloredInupLogo;
12
13
  const chalk_1 = __importDefault(require("chalk"));
14
+ const config_1 = require("../../shared/config");
13
15
  const theme_manager_1 = require("./state/theme-manager");
14
- const config_1 = require("../config");
15
16
  // Centralized theme color definitions - single source of truth
16
17
  const themeColorDefinitions = {
17
18
  default: {
@@ -173,6 +174,7 @@ function getThemeBgColor() {
173
174
  */
174
175
  function hexToRgb(hex) {
175
176
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
177
+ // Malformed input falls back to black — a safe default for a color parser.
176
178
  return result
177
179
  ? {
178
180
  r: parseInt(result[1], 16),
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PackageUpgrader = exports.PackageDetector = void 0;
4
+ var package_detector_1 = require("./package-detector");
5
+ Object.defineProperty(exports, "PackageDetector", { enumerable: true, get: function () { return package_detector_1.PackageDetector; } });
6
+ var upgrader_1 = require("./upgrader");
7
+ Object.defineProperty(exports, "PackageUpgrader", { enumerable: true, get: function () { return upgrader_1.PackageUpgrader; } });
8
+ //# sourceMappingURL=index.js.map
@@ -39,12 +39,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.PackageDetector = void 0;
40
40
  const chalk_1 = __importDefault(require("chalk"));
41
41
  const semver = __importStar(require("semver"));
42
- const utils_1 = require("../utils");
43
- const services_1 = require("../services");
44
- const config_1 = require("../config");
45
- const utils_2 = require("../ui/utils");
46
- const utils_3 = require("../utils");
47
- const debug_1 = require("../features/debug");
42
+ const config_1 = require("../../shared/config");
43
+ const debug_logger_1 = require("../../shared/debug-logger");
44
+ const fs_1 = require("../../shared/fs");
45
+ const pnpm_catalogs_1 = require("../../shared/pnpm-catalogs");
46
+ const npm_registry_1 = require("../../shared/registry/npm-registry");
47
+ const terminal_1 = require("../../shared/terminal");
48
+ const versions_1 = require("../../shared/versions");
49
+ const debug_1 = require("../debug");
48
50
  class PackageDetector {
49
51
  packageJsonPath = null;
50
52
  packageJson = null;
@@ -63,9 +65,9 @@ class PackageDetector {
63
65
  this.ignorePackages = options?.ignorePackages || [];
64
66
  this.maxDepth = options?.maxDepth ?? 10;
65
67
  this.adaptive = options?.adaptive ?? true;
66
- this.packageJsonPath = (0, utils_1.findPackageJson)(this.cwd);
68
+ this.packageJsonPath = (0, fs_1.findPackageJson)(this.cwd);
67
69
  if (this.packageJsonPath) {
68
- this.packageJson = (0, utils_1.readPackageJson)(this.packageJsonPath);
70
+ this.packageJson = (0, fs_1.readPackageJson)(this.packageJsonPath);
69
71
  }
70
72
  }
71
73
  hasPackageJson() {
@@ -103,7 +105,7 @@ class PackageDetector {
103
105
  throw new Error('No package.json found in current directory');
104
106
  }
105
107
  const t0 = Date.now();
106
- utils_3.debugLog.info('PackageDetector', `Starting scan in ${this.cwd}`);
108
+ debug_logger_1.debugLog.info('PackageDetector', `Starting scan in ${this.cwd}`);
107
109
  const prepared = await this.prepareDependencies();
108
110
  const initialPayload = {
109
111
  allDependencies: prepared.allDependencies,
@@ -119,8 +121,8 @@ class PackageDetector {
119
121
  let batchIndex = 0;
120
122
  let lastBatchEndAt = Date.now();
121
123
  const tFetch = Date.now();
122
- utils_3.debugLog.info('PackageDetector', 'fetching version data via npm registry in batches');
123
- await (0, services_1.fetchPackageVersions)(prepared.uniquePackages, {
124
+ debug_logger_1.debugLog.info('PackageDetector', 'fetching version data via npm registry in batches');
125
+ await (0, npm_registry_1.fetchPackageVersions)(prepared.uniquePackages, {
124
126
  currentVersions: prepared.currentVersions,
125
127
  batchSize: this.batchSize,
126
128
  maxConcurrency: this.maxConcurrency,
@@ -167,11 +169,11 @@ class PackageDetector {
167
169
  });
168
170
  },
169
171
  });
170
- utils_3.debugLog.perf('PackageDetector', `registry fetch (${resolved}/${prepared.uniquePackages.length} resolved)`, tFetch);
172
+ debug_logger_1.debugLog.perf('PackageDetector', `registry fetch (${resolved}/${prepared.uniquePackages.length} resolved)`, tFetch);
171
173
  performanceTracker.recordPhaseDuration('registryFetch', Date.now() - tFetch);
172
174
  const finalPackages = prepared.uniquePackages.flatMap((packageName) => packageLookup.get(packageName) ?? []);
173
175
  const progress = this.createProgressSnapshot(prepared.uniquePackages.length, resolved, failed, false);
174
- utils_3.debugLog.perf('PackageDetector', `total scan complete (${finalPackages.filter((p) => p.isOutdated).length} outdated of ${finalPackages.length} deps)`, t0);
176
+ debug_logger_1.debugLog.perf('PackageDetector', `total scan complete (${finalPackages.filter((p) => p.isOutdated).length} outdated of ${finalPackages.length} deps)`, t0);
175
177
  onEvent({
176
178
  type: 'complete',
177
179
  payload: {
@@ -179,7 +181,7 @@ class PackageDetector {
179
181
  progress,
180
182
  },
181
183
  });
182
- utils_2.ConsoleUtils.clearProgress();
184
+ terminal_1.ConsoleUtils.clearProgress();
183
185
  return finalPackages;
184
186
  }
185
187
  async prepareDependencies() {
@@ -187,7 +189,7 @@ class PackageDetector {
187
189
  this.showProgress('🔍 Scanning repository for package.json files...');
188
190
  const tScan = Date.now();
189
191
  const allPackageJsonFiles = await this.findPackageJsonFilesWithTimeout(30000);
190
- utils_3.debugLog.perf('PackageDetector', `file scan (${allPackageJsonFiles.length} files)`, tScan, {
192
+ debug_logger_1.debugLog.perf('PackageDetector', `file scan (${allPackageJsonFiles.length} files)`, tScan, {
191
193
  files: allPackageJsonFiles,
192
194
  });
193
195
  performanceTracker.recordPhaseDuration('discovery', Date.now() - tScan);
@@ -195,11 +197,11 @@ class PackageDetector {
195
197
  this.showProgress(`🔍 Found ${allPackageJsonFiles.length} package.json file${allPackageJsonFiles.length === 1 ? '' : 's'}`);
196
198
  this.showProgress('🔍 Reading dependencies from package.json files...');
197
199
  const tDeps = Date.now();
198
- const allDepsRaw = await (0, utils_1.collectAllDependenciesAsync)(allPackageJsonFiles, {
200
+ const allDepsRaw = await (0, fs_1.collectAllDependenciesAsync)(allPackageJsonFiles, {
199
201
  includePeerDeps: true,
200
202
  includeOptionalDeps: true,
201
203
  });
202
- utils_3.debugLog.perf('PackageDetector', `dependency collection (${allDepsRaw.length} raw deps)`, tDeps);
204
+ debug_logger_1.debugLog.perf('PackageDetector', `dependency collection (${allDepsRaw.length} raw deps)`, tDeps);
203
205
  performanceTracker.recordPhaseDuration('depCollection', Date.now() - tDeps);
204
206
  performanceTracker.recordCounts({ rawDependencies: allDepsRaw.length });
205
207
  this.showProgress('🔍 Identifying unique packages...');
@@ -209,12 +211,57 @@ class PackageDetector {
209
211
  let ignoredCount = 0;
210
212
  const seenWorkspaceRefs = new Set();
211
213
  const seenIgnored = new Set();
212
- for (const dep of allDepsRaw) {
213
- if (this.isWorkspaceReference(dep.version)) {
214
+ // pnpm catalogs: `"react": "catalog:"` gets its real range from
215
+ // pnpm-workspace.yaml. Each catalog entry becomes ONE upgradable dependency
216
+ // sourced from that file, no matter how many workspace packages reference it.
217
+ const catalogs = pnpm_catalogs_1.PnpmCatalogs.load(this.cwd);
218
+ // Entries here always carry catalogReferencedBy (set on first-seen below),
219
+ // so require it in the value type — that lets re-references push onto the
220
+ // array without an optional-fallback branch.
221
+ const seenCatalogEntries = new Map();
222
+ for (const rawDep of allDepsRaw) {
223
+ let dep = {
224
+ name: rawDep.name,
225
+ version: rawDep.version,
226
+ type: rawDep.type,
227
+ packageJsonPath: rawDep.packageJsonPath,
228
+ };
229
+ if ((0, pnpm_catalogs_1.isCatalogReference)(rawDep.version)) {
230
+ // A catalog ref resolves its range from pnpm-workspace.yaml. If that
231
+ // file was absent (catalogs === null) or the entry is missing, we can't
232
+ // resolve a range — warn and skip.
233
+ const resolution = catalogs?.resolve(rawDep.name, rawDep.version);
234
+ if (!catalogs || !resolution) {
235
+ debug_logger_1.debugLog.warn('PackageDetector', `skipping unresolvable catalog ref: ${rawDep.name}@${rawDep.version}`);
236
+ continue;
237
+ }
238
+ const catalogKey = `${resolution.catalog}:${rawDep.name}`;
239
+ const existing = seenCatalogEntries.get(catalogKey);
240
+ if (existing) {
241
+ // Same catalog entry, another referencing package: remember who uses
242
+ // it (for the info modal's Used-by tab) but keep the single entry.
243
+ if (!existing.catalogReferencedBy.includes(rawDep.packageJsonPath)) {
244
+ existing.catalogReferencedBy.push(rawDep.packageJsonPath);
245
+ }
246
+ continue;
247
+ }
248
+ const catalogEntry = {
249
+ name: rawDep.name,
250
+ version: resolution.range,
251
+ type: rawDep.type,
252
+ packageJsonPath: catalogs.path,
253
+ catalog: resolution.catalog,
254
+ catalogEntries: catalogs.entriesOf(resolution.catalog),
255
+ catalogReferencedBy: [rawDep.packageJsonPath],
256
+ };
257
+ seenCatalogEntries.set(catalogKey, catalogEntry);
258
+ dep = catalogEntry;
259
+ }
260
+ if (this.isNonRegistrySpecifier(dep.version)) {
214
261
  const key = `${dep.name}@${dep.version}`;
215
262
  if (!seenWorkspaceRefs.has(key)) {
216
263
  seenWorkspaceRefs.add(key);
217
- utils_3.debugLog.info('PackageDetector', `skipping workspace ref: ${key}`);
264
+ debug_logger_1.debugLog.info('PackageDetector', `skipping non-registry specifier: ${key}`);
218
265
  }
219
266
  continue;
220
267
  }
@@ -222,16 +269,11 @@ class PackageDetector {
222
269
  ignoredCount++;
223
270
  if (!seenIgnored.has(dep.name)) {
224
271
  seenIgnored.add(dep.name);
225
- utils_3.debugLog.info('PackageDetector', `ignoring package: ${dep.name}`);
272
+ debug_logger_1.debugLog.info('PackageDetector', `ignoring package: ${dep.name}`);
226
273
  }
227
274
  continue;
228
275
  }
229
- allDependencies.push({
230
- name: dep.name,
231
- version: dep.version,
232
- type: dep.type,
233
- packageJsonPath: dep.packageJsonPath,
234
- });
276
+ allDependencies.push(dep);
235
277
  uniquePackageNames.add(dep.name);
236
278
  }
237
279
  if (ignoredCount > 0) {
@@ -246,7 +288,7 @@ class PackageDetector {
246
288
  return 1;
247
289
  return a.localeCompare(b);
248
290
  });
249
- utils_3.debugLog.info('PackageDetector', `${uniquePackages.length} unique packages to check, ${ignoredCount} ignored`);
291
+ debug_logger_1.debugLog.info('PackageDetector', `${uniquePackages.length} unique packages to check, ${ignoredCount} ignored`);
250
292
  performanceTracker.recordPhaseDuration('filter', Date.now() - tFilter);
251
293
  performanceTracker.recordCounts({
252
294
  uniquePackages: uniquePackages.length,
@@ -274,12 +316,12 @@ class PackageDetector {
274
316
  if (!packageData || packageData.latestVersion === 'unknown') {
275
317
  if (!loggedNoData.has(dep.name)) {
276
318
  loggedNoData.add(dep.name);
277
- utils_3.debugLog.warn('PackageDetector', `no data returned for ${dep.name} — marking unavailable`);
319
+ debug_logger_1.debugLog.warn('PackageDetector', `no data returned for ${dep.name} — marking unavailable`);
278
320
  }
279
321
  return this.createFailedPackageInfo(dep);
280
322
  }
281
323
  const { latestVersion, allVersions } = packageData;
282
- const closestMinorVersion = (0, utils_1.findClosestMinorVersion)(dep.version, allVersions);
324
+ const closestMinorVersion = (0, versions_1.findClosestMinorVersion)(dep.version, allVersions);
283
325
  const installedClean = semver.coerce(dep.version)?.version || dep.version;
284
326
  const minorClean = closestMinorVersion
285
327
  ? semver.coerce(closestMinorVersion)?.version || closestMinorVersion
@@ -294,7 +336,7 @@ class PackageDetector {
294
336
  const outdatedKey = `${dep.name}@${dep.version}`;
295
337
  if (!loggedOutdated.has(outdatedKey)) {
296
338
  loggedOutdated.add(outdatedKey);
297
- utils_3.debugLog.info('PackageDetector', `outdated: ${dep.name} ${dep.version} → range:${closestMinorVersion ?? '-'} latest:${latestVersion}`);
339
+ debug_logger_1.debugLog.info('PackageDetector', `outdated: ${dep.name} ${dep.version} → range:${closestMinorVersion ?? '-'} latest:${latestVersion}`);
298
340
  }
299
341
  }
300
342
  return {
@@ -304,6 +346,9 @@ class PackageDetector {
304
346
  latestVersion,
305
347
  type: dep.type,
306
348
  packageJsonPath: dep.packageJsonPath,
349
+ catalog: dep.catalog,
350
+ catalogEntries: dep.catalogEntries,
351
+ catalogReferencedBy: dep.catalogReferencedBy,
307
352
  isOutdated,
308
353
  hasRangeUpdate,
309
354
  hasMajorUpdate,
@@ -313,7 +358,7 @@ class PackageDetector {
313
358
  };
314
359
  }
315
360
  catch (error) {
316
- utils_3.debugLog.error('PackageDetector', `error processing ${dep.name}`, error);
361
+ debug_logger_1.debugLog.error('PackageDetector', `error processing ${dep.name}`, error);
317
362
  return this.createFailedPackageInfo(dep);
318
363
  }
319
364
  });
@@ -326,6 +371,9 @@ class PackageDetector {
326
371
  latestVersion: 'unknown',
327
372
  type: dep.type,
328
373
  packageJsonPath: dep.packageJsonPath,
374
+ catalog: dep.catalog,
375
+ catalogEntries: dep.catalogEntries,
376
+ catalogReferencedBy: dep.catalogReferencedBy,
329
377
  isOutdated: false,
330
378
  hasRangeUpdate: false,
331
379
  hasMajorUpdate: false,
@@ -346,8 +394,8 @@ class PackageDetector {
346
394
  let timeoutId;
347
395
  try {
348
396
  const files = await Promise.race([
349
- (0, utils_1.findAllPackageJsonFilesAsync)(this.cwd, this.excludePatterns, this.maxDepth, (currentDir, foundCount) => {
350
- const truncatedDir = currentDir.length > 50 ? '...' + currentDir.slice(-47) : currentDir;
397
+ (0, fs_1.findAllPackageJsonFilesAsync)(this.cwd, this.excludePatterns, this.maxDepth, (currentDir, foundCount) => {
398
+ const truncatedDir = currentDir.length > 50 ? `...${currentDir.slice(-47)}` : currentDir;
351
399
  this.showProgress(`🔍 Scanning ${truncatedDir} (found ${foundCount})`);
352
400
  }, {
353
401
  scanDirs: this.scanDirs,
@@ -387,17 +435,28 @@ class PackageDetector {
387
435
  list.map((dir) => ` - ${dir}`).join('\n') +
388
436
  `\n Add the directory name(s) to "scanDirs" in .inuprc to include them.`));
389
437
  }
390
- isWorkspaceReference(version) {
438
+ /**
439
+ * Specifiers that don't point at a plain registry range, so there is nothing to resolve or
440
+ * upgrade: workspace/file/link refs, git hosts and URLs, tarball URLs, and `npm:` aliases.
441
+ * An `npm:` alias in particular must never be looked up under its alias name — the packument
442
+ * for that name is a different (or nonexistent) package.
443
+ */
444
+ isNonRegistrySpecifier(version) {
391
445
  return (version.includes('workspace:') ||
392
446
  version === '*' ||
393
447
  version.startsWith('file:') ||
394
448
  version.startsWith('link:') ||
395
449
  version.startsWith('github:') ||
396
450
  version.startsWith('gitlab:') ||
397
- version.startsWith('bitbucket:'));
451
+ version.startsWith('bitbucket:') ||
452
+ version.startsWith('npm:') ||
453
+ version.startsWith('git:') ||
454
+ version.startsWith('git+') ||
455
+ version.startsWith('http:') ||
456
+ version.startsWith('https:'));
398
457
  }
399
458
  showProgress(message) {
400
- utils_2.ConsoleUtils.showProgress(message);
459
+ terminal_1.ConsoleUtils.showProgress(message);
401
460
  }
402
461
  getOutdatedPackagesOnly(packages) {
403
462
  return packages.filter((pkg) => pkg.isOutdated);
@@ -4,12 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.PackageUpgrader = void 0;
7
+ const node_child_process_1 = require("node:child_process");
8
+ const node_fs_1 = require("node:fs");
9
+ const node_path_1 = require("node:path");
7
10
  const chalk_1 = __importDefault(require("chalk"));
8
11
  const nanospinner_1 = require("nanospinner");
9
- const fs_1 = require("fs");
10
- const path_1 = require("path");
11
- const child_process_1 = require("child_process");
12
- const utils_1 = require("../utils");
12
+ const exec_1 = require("../../shared/exec");
13
+ const fs_1 = require("../../shared/fs");
14
+ const pnpm_catalogs_1 = require("../../shared/pnpm-catalogs");
13
15
  class PackageUpgrader {
14
16
  packageManager;
15
17
  quiet;
@@ -25,15 +27,23 @@ class PackageUpgrader {
25
27
  this.log(chalk_1.default.yellow('No packages to upgrade.'));
26
28
  return;
27
29
  }
30
+ // Catalog entries live in pnpm-workspace.yaml, not a package.json — they
31
+ // take the YAML write path below. The type predicate narrows the catalog
32
+ // group so downstream code sees `catalog` as a required string.
33
+ const catalogChoices = choices.filter((choice) => choice.catalog !== undefined);
34
+ const fileChoices = choices.filter((choice) => choice.catalog === undefined);
28
35
  // Group choices by package.json path and dependency type
29
- const choicesByFileAndType = this.groupChoicesByFileAndType(choices);
36
+ const choicesByFileAndType = this.groupChoicesByFileAndType(fileChoices);
30
37
  for (const [fileAndType, choiceList] of Object.entries(choicesByFileAndType)) {
31
- if (choiceList.length === 0)
32
- continue;
38
+ // groupChoicesByFileAndType only creates a group once it has a member,
39
+ // so choiceList is always non-empty here.
33
40
  const [packageJsonPath, type] = fileAndType.split('|');
34
41
  this.log(`Processing ${type} in ${packageJsonPath}`);
35
42
  await this.upgradeChoiceGroup(choiceList, packageJsonPath, type);
36
43
  }
44
+ if (catalogChoices.length > 0) {
45
+ await this.upgradeCatalogChoices(catalogChoices);
46
+ }
37
47
  // Count unique packages upgraded
38
48
  const uniquePackages = new Set(choices.map((c) => c.name));
39
49
  this.log(chalk_1.default.green(`\n✅ Successfully upgraded ${uniquePackages.size} package(s)!`));
@@ -41,20 +51,19 @@ class PackageUpgrader {
41
51
  await this.runInstall(choices);
42
52
  }
43
53
  async runInstall(choices) {
44
- if (choices.length === 0) {
45
- return;
46
- }
54
+ // The sole caller (upgradePackages) returns early on an empty selection,
55
+ // so choices is always non-empty here.
47
56
  // Determine the directory to run install in
48
57
  // Use workspace root if it exists, otherwise use the directory of the first package.json
49
58
  const firstPackageJsonPath = choices[0].packageJsonPath;
50
- const firstPackageDir = (0, path_1.dirname)(firstPackageJsonPath);
51
- const workspaceRoot = (0, utils_1.findWorkspaceRoot)(firstPackageDir, this.packageManager.name);
59
+ const firstPackageDir = (0, node_path_1.dirname)(firstPackageJsonPath);
60
+ const workspaceRoot = (0, fs_1.findWorkspaceRoot)(firstPackageDir, this.packageManager.name);
52
61
  const installDir = workspaceRoot || firstPackageDir;
53
62
  // Check if package manager is installed
54
63
  try {
55
- (0, utils_1.executeCommand)(`${this.packageManager.name} --version`, installDir);
64
+ (0, exec_1.executeCommand)(`${this.packageManager.name} --version`, installDir);
56
65
  }
57
- catch (error) {
66
+ catch {
58
67
  this.log(chalk_1.default.yellow(`\n⚠️ ${this.packageManager.displayName} is detected but not installed on your system.\n` +
59
68
  `Please run the install command manually:\n` +
60
69
  ` cd ${installDir}\n` +
@@ -69,7 +78,7 @@ class PackageUpgrader {
69
78
  // inherited fds, so its progress output bypasses any JS shim — redirecting at spawn time is
70
79
  // the only reliable way to keep stdout reserved for the --json document. stderr stays inherited.
71
80
  const stdio = this.quiet ? ['inherit', 2, 'inherit'] : 'inherit';
72
- const result = (0, child_process_1.spawnSync)(installCommand, {
81
+ const result = (0, node_child_process_1.spawnSync)(installCommand, {
73
82
  cwd: installDir,
74
83
  stdio,
75
84
  shell: true,
@@ -84,6 +93,53 @@ class PackageUpgrader {
84
93
  throw new Error(`${installCommand} exited with code ${result.status}`);
85
94
  }
86
95
  }
96
+ /**
97
+ * Apply catalog upgrades by rewriting the referenced ranges inside
98
+ * pnpm-workspace.yaml (comment- and format-preserving). One write per file.
99
+ */
100
+ async upgradeCatalogChoices(choices) {
101
+ const choicesByFile = new Map();
102
+ choices.forEach((choice) => {
103
+ const group = choicesByFile.get(choice.packageJsonPath) ?? [];
104
+ group.push(choice);
105
+ choicesByFile.set(choice.packageJsonPath, group);
106
+ });
107
+ for (const [workspaceFilePath, fileChoices] of choicesByFile) {
108
+ if (!(0, node_fs_1.existsSync)(workspaceFilePath)) {
109
+ this.log(chalk_1.default.yellow(`⚠️ Skipping catalog entries in ${workspaceFilePath} - file not found`));
110
+ continue;
111
+ }
112
+ this.log(`Processing catalog entries in ${workspaceFilePath}`);
113
+ const spinner = this.quiet
114
+ ? null
115
+ : (0, nanospinner_1.createSpinner)(`Upgrading catalog entries in ${workspaceFilePath}...`).start();
116
+ try {
117
+ (0, pnpm_catalogs_1.writeCatalogUpdates)(workspaceFilePath, fileChoices.map((choice) => ({
118
+ catalog: choice.catalog,
119
+ name: choice.name,
120
+ range: choice.targetVersion,
121
+ })));
122
+ const message = `Upgraded ${fileChoices.length} catalog entr${fileChoices.length === 1 ? 'y' : 'ies'} in ${workspaceFilePath}`;
123
+ if (spinner)
124
+ spinner.success({ text: message });
125
+ else
126
+ this.log(chalk_1.default.green(`✔ ${message}`));
127
+ fileChoices.forEach((choice) => {
128
+ const upgradeTypeColor = choice.upgradeType === 'range' ? chalk_1.default.yellow : chalk_1.default.red;
129
+ const catalogLabel = choice.catalog === 'default' ? 'catalog' : `catalog:${choice.catalog}`;
130
+ this.log(` ${chalk_1.default.green('✓')} ${chalk_1.default.cyan(choice.name)} (${catalogLabel}) → ${upgradeTypeColor(choice.targetVersion)}`);
131
+ });
132
+ }
133
+ catch (error) {
134
+ if (spinner)
135
+ spinner.error({ text: `Failed to upgrade catalog entries in ${workspaceFilePath}` });
136
+ else
137
+ this.log(chalk_1.default.red(`✖ Failed to upgrade catalog entries in ${workspaceFilePath}`));
138
+ console.error(chalk_1.default.red(`Error: ${error}`));
139
+ throw error;
140
+ }
141
+ }
142
+ }
87
143
  groupChoicesByFileAndType(choices) {
88
144
  const groups = {};
89
145
  choices.forEach((choice) => {
@@ -97,7 +153,7 @@ class PackageUpgrader {
97
153
  }
98
154
  async upgradeChoiceGroup(choices, packageJsonPath, type) {
99
155
  // Validate that package.json exists
100
- if (!(0, fs_1.existsSync)(packageJsonPath)) {
156
+ if (!(0, node_fs_1.existsSync)(packageJsonPath)) {
101
157
  this.log(chalk_1.default.yellow(`⚠️ Skipping ${type} in ${packageJsonPath} - package.json file not found`));
102
158
  return;
103
159
  }
@@ -108,40 +164,33 @@ class PackageUpgrader {
108
164
  : (0, nanospinner_1.createSpinner)(`Upgrading ${type} in ${packageDir}...`).start();
109
165
  try {
110
166
  // Read the current package.json — keep the raw text so we can round-trip its formatting
111
- const rawContent = (0, fs_1.readFileSync)(packageJsonPath, 'utf-8');
112
- const packageJson = (0, utils_1.readPackageJson)(packageJsonPath);
167
+ const rawContent = (0, node_fs_1.readFileSync)(packageJsonPath, 'utf-8');
168
+ const packageJson = (0, fs_1.readPackageJson)(packageJsonPath);
113
169
  // Group by upgrade type (range vs latest)
114
170
  const rangeChoices = choices.filter((c) => c.upgradeType === 'range');
115
171
  const latestChoices = choices.filter((c) => c.upgradeType === 'latest');
116
- let modified = false;
117
172
  // Upgrade range versions by directly modifying package.json
118
173
  if (rangeChoices.length > 0) {
119
- if (!packageJson[type]) {
120
- packageJson[type] = {};
121
- }
174
+ const section = packageJson[type] ?? {};
175
+ packageJson[type] = section;
122
176
  rangeChoices.forEach((choice) => {
123
- packageJson[type][choice.name] = choice.targetVersion;
124
- modified = true;
177
+ section[choice.name] = choice.targetVersion;
125
178
  });
126
179
  }
127
180
  // Upgrade to latest versions by directly modifying package.json
128
181
  if (latestChoices.length > 0) {
129
- if (!packageJson[type]) {
130
- packageJson[type] = {};
131
- }
182
+ const section = packageJson[type] ?? {};
183
+ packageJson[type] = section;
132
184
  latestChoices.forEach((choice) => {
133
- packageJson[type][choice.name] = choice.targetVersion;
134
- modified = true;
185
+ section[choice.name] = choice.targetVersion;
135
186
  });
136
187
  }
137
188
  // Write back the modified package.json, preserving the original indentation and
138
189
  // trailing-newline style. Skip the write entirely when nothing actually changed.
139
- if (modified) {
140
- const format = (0, utils_1.detectJsonFormat)(rawContent);
141
- const nextContent = JSON.stringify(packageJson, null, format.indent) + (format.trailingNewline ? '\n' : '');
142
- if (nextContent !== rawContent) {
143
- (0, fs_1.writeFileSync)(packageJsonPath, nextContent);
144
- }
190
+ const format = (0, fs_1.detectJsonFormat)(rawContent);
191
+ const nextContent = JSON.stringify(packageJson, null, format.indent) + (format.trailingNewline ? '\n' : '');
192
+ if (nextContent !== rawContent) {
193
+ (0, node_fs_1.writeFileSync)(packageJsonPath, nextContent);
145
194
  }
146
195
  if (spinner)
147
196
  spinner.success({ text: `Upgraded ${choices.length} ${type} in ${packageDir}` });
package/dist/index.js CHANGED
@@ -4,6 +4,6 @@
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.UpgradeRunner = void 0;
7
- var core_1 = require("./core");
8
- Object.defineProperty(exports, "UpgradeRunner", { enumerable: true, get: function () { return core_1.UpgradeRunner; } });
7
+ var upgrade_runner_1 = require("./app/upgrade-runner");
8
+ Object.defineProperty(exports, "UpgradeRunner", { enumerable: true, get: function () { return upgrade_runner_1.UpgradeRunner; } });
9
9
  //# sourceMappingURL=index.js.map
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.PACKAGE_VERSION = exports.PACKAGE_NAME = void 0;
7
- const package_json_1 = __importDefault(require("../../package.json"));
7
+ const package_json_1 = __importDefault(require("../../../package.json"));
8
8
  exports.PACKAGE_NAME = package_json_1.default.name;
9
9
  exports.PACKAGE_VERSION = package_json_1.default.version;
10
10
  //# sourceMappingURL=package-meta.js.map