inup 1.4.10 → 1.4.12
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 +1 -7
- package/dist/config/constants.js +1 -2
- package/dist/core/package-detector.js +162 -89
- package/dist/core/upgrade-runner.js +62 -13
- package/dist/interactive-ui.js +116 -62
- package/dist/services/changelog-fetcher.js +59 -34
- package/dist/services/index.js +0 -2
- package/dist/services/jsdelivr-registry.js +92 -176
- package/dist/services/npm-registry.js +97 -27
- package/dist/ui/input-handler.js +1 -1
- package/dist/ui/renderer/index.js +2 -2
- package/dist/ui/renderer/package-list.js +32 -5
- package/dist/ui/state/state-manager.js +7 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,12 +14,6 @@ Upgrade your dependencies interactively. Works with npm, yarn, pnpm, and bun.
|
|
|
14
14
|
npx inup
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Scan deeper package layouts:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npx inup --max-depth 15
|
|
21
|
-
```
|
|
22
|
-
|
|
23
17
|
Or install globally:
|
|
24
18
|
|
|
25
19
|
```bash
|
|
@@ -66,7 +60,7 @@ inup [options]
|
|
|
66
60
|
|
|
67
61
|
We don't track anything. Ever.
|
|
68
62
|
|
|
69
|
-
|
|
63
|
+
Version checks and package metadata are fetched from the npm registry. When needed for immutable exact-version manifests, inup may also fetch a pinned `package.json` from jsDelivr. Weekly download counts come from the npm downloads API.
|
|
70
64
|
|
|
71
65
|
## 📄 License
|
|
72
66
|
|
package/dist/config/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.JSDELIVR_POOL_TIMEOUT = exports.JSDELIVR_RETRY_DELAYS = exports.JSDELIVR_RETRY_TIMEOUTS = exports.REQUEST_TIMEOUT = exports.CACHE_TTL = exports.MAX_CONCURRENT_REQUESTS = exports.JSDELIVR_CDN_URL = exports.NPM_REGISTRY_URL = exports.PACKAGE_NAME = void 0;
|
|
4
4
|
exports.PACKAGE_NAME = 'inup';
|
|
5
5
|
exports.NPM_REGISTRY_URL = 'https://registry.npmjs.org';
|
|
6
6
|
exports.JSDELIVR_CDN_URL = 'https://cdn.jsdelivr.net/npm';
|
|
@@ -10,5 +10,4 @@ exports.REQUEST_TIMEOUT = 60000; // 60 seconds in milliseconds
|
|
|
10
10
|
exports.JSDELIVR_RETRY_TIMEOUTS = [2000, 3500]; // short retry budget to keep fallback fast
|
|
11
11
|
exports.JSDELIVR_RETRY_DELAYS = [150]; // tiny backoff between jsDelivr retries in ms
|
|
12
12
|
exports.JSDELIVR_POOL_TIMEOUT = 60000; // keep-alive/connect lifecycle should be looser than per-request timeouts
|
|
13
|
-
exports.DEFAULT_REGISTRY = 'jsdelivr';
|
|
14
13
|
//# sourceMappingURL=constants.js.map
|
|
@@ -44,6 +44,8 @@ class PackageDetector {
|
|
|
44
44
|
constructor(options) {
|
|
45
45
|
this.packageJsonPath = null;
|
|
46
46
|
this.packageJson = null;
|
|
47
|
+
this.batchSizes = [10, 15, 20, 25];
|
|
48
|
+
this.batchConcurrency = 5;
|
|
47
49
|
this.cwd = options?.cwd || process.cwd();
|
|
48
50
|
this.excludePatterns = options?.excludePatterns || [];
|
|
49
51
|
this.ignorePackages = options?.ignorePackages || [];
|
|
@@ -57,21 +59,87 @@ class PackageDetector {
|
|
|
57
59
|
return this.packageJsonPath !== null && this.packageJson !== null;
|
|
58
60
|
}
|
|
59
61
|
async getOutdatedPackages() {
|
|
62
|
+
const packages = [];
|
|
63
|
+
await this.streamOutdatedPackages((event) => {
|
|
64
|
+
if (event.type === 'batch') {
|
|
65
|
+
event.payload.batch.forEach((item) => {
|
|
66
|
+
packages.push(...item.packageInfo);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else if (event.type === 'complete') {
|
|
70
|
+
packages.splice(0, packages.length, ...event.payload.packages);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
return packages;
|
|
74
|
+
}
|
|
75
|
+
async streamOutdatedPackages(onEvent) {
|
|
60
76
|
if (!this.packageJson) {
|
|
61
77
|
throw new Error('No package.json found in current directory');
|
|
62
78
|
}
|
|
63
|
-
const packages = [];
|
|
64
79
|
const t0 = Date.now();
|
|
65
80
|
utils_3.debugLog.info('PackageDetector', `Starting scan in ${this.cwd}`);
|
|
66
|
-
|
|
81
|
+
const prepared = await this.prepareDependencies();
|
|
82
|
+
const initialPayload = {
|
|
83
|
+
allDependencies: prepared.allDependencies,
|
|
84
|
+
uniquePackages: prepared.uniquePackages,
|
|
85
|
+
currentVersions: prepared.currentVersions,
|
|
86
|
+
progress: this.createProgressSnapshot(prepared.uniquePackages.length, 0, 0, true),
|
|
87
|
+
};
|
|
88
|
+
onEvent({ type: 'initial', payload: initialPayload });
|
|
89
|
+
const packageLookup = new Map();
|
|
90
|
+
let resolved = 0;
|
|
91
|
+
let failed = 0;
|
|
92
|
+
const tFetch = Date.now();
|
|
93
|
+
utils_3.debugLog.info('PackageDetector', 'fetching version data via npm registry in batches');
|
|
94
|
+
await (0, services_1.getAllPackageDataBatched)(prepared.uniquePackages, (batch) => {
|
|
95
|
+
const batchItems = batch.map((batchItem) => {
|
|
96
|
+
const packageInfo = this.resolvePackageGroup(batchItem.packageName, prepared.allDependencies, batchItem.data);
|
|
97
|
+
packageLookup.set(batchItem.packageName, packageInfo);
|
|
98
|
+
resolved++;
|
|
99
|
+
const isFailed = batchItem.data.latestVersion === 'unknown';
|
|
100
|
+
if (isFailed) {
|
|
101
|
+
failed++;
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
packageName: batchItem.packageName,
|
|
105
|
+
packageInfo,
|
|
106
|
+
failed: isFailed,
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
const progress = this.createProgressSnapshot(prepared.uniquePackages.length, resolved, failed, resolved < prepared.uniquePackages.length);
|
|
110
|
+
onEvent({
|
|
111
|
+
type: 'batch',
|
|
112
|
+
payload: {
|
|
113
|
+
batch: batchItems,
|
|
114
|
+
progress,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}, prepared.currentVersions, {
|
|
118
|
+
batchSizes: this.batchSizes,
|
|
119
|
+
concurrency: this.batchConcurrency,
|
|
120
|
+
});
|
|
121
|
+
utils_3.debugLog.perf('PackageDetector', `registry fetch (${resolved}/${prepared.uniquePackages.length} resolved)`, tFetch);
|
|
122
|
+
const finalPackages = prepared.uniquePackages.flatMap((packageName) => packageLookup.get(packageName) ?? []);
|
|
123
|
+
const progress = this.createProgressSnapshot(prepared.uniquePackages.length, resolved, failed, false);
|
|
124
|
+
utils_3.debugLog.perf('PackageDetector', `total scan complete (${finalPackages.filter((p) => p.isOutdated).length} outdated of ${finalPackages.length} deps)`, t0);
|
|
125
|
+
onEvent({
|
|
126
|
+
type: 'complete',
|
|
127
|
+
payload: {
|
|
128
|
+
packages: finalPackages,
|
|
129
|
+
progress,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
utils_2.ConsoleUtils.clearProgress();
|
|
133
|
+
return finalPackages;
|
|
134
|
+
}
|
|
135
|
+
async prepareDependencies() {
|
|
67
136
|
this.showProgress('🔍 Scanning repository for package.json files...');
|
|
68
137
|
const tScan = Date.now();
|
|
69
|
-
const allPackageJsonFiles = await this.findPackageJsonFilesWithTimeout(30000);
|
|
138
|
+
const allPackageJsonFiles = await this.findPackageJsonFilesWithTimeout(30000);
|
|
70
139
|
utils_3.debugLog.perf('PackageDetector', `file scan (${allPackageJsonFiles.length} files)`, tScan, {
|
|
71
140
|
files: allPackageJsonFiles,
|
|
72
141
|
});
|
|
73
142
|
this.showProgress(`🔍 Found ${allPackageJsonFiles.length} package.json file${allPackageJsonFiles.length === 1 ? '' : 's'}`);
|
|
74
|
-
// Step 2: Collect all dependencies from package.json files (parallelized)
|
|
75
143
|
this.showProgress('🔍 Reading dependencies from package.json files...');
|
|
76
144
|
const tDeps = Date.now();
|
|
77
145
|
const allDepsRaw = await (0, utils_1.collectAllDependenciesAsync)(allPackageJsonFiles, {
|
|
@@ -79,10 +147,9 @@ class PackageDetector {
|
|
|
79
147
|
includeOptionalDeps: true,
|
|
80
148
|
});
|
|
81
149
|
utils_3.debugLog.perf('PackageDetector', `dependency collection (${allDepsRaw.length} raw deps)`, tDeps);
|
|
82
|
-
// Step 3: Get unique package names while filtering out workspace references and ignored packages
|
|
83
150
|
this.showProgress('🔍 Identifying unique packages...');
|
|
84
151
|
const uniquePackageNames = new Set();
|
|
85
|
-
const
|
|
152
|
+
const allDependencies = [];
|
|
86
153
|
let ignoredCount = 0;
|
|
87
154
|
const seenWorkspaceRefs = new Set();
|
|
88
155
|
const seenIgnored = new Set();
|
|
@@ -103,102 +170,110 @@ class PackageDetector {
|
|
|
103
170
|
}
|
|
104
171
|
continue;
|
|
105
172
|
}
|
|
106
|
-
|
|
173
|
+
allDependencies.push({
|
|
174
|
+
name: dep.name,
|
|
175
|
+
version: dep.version,
|
|
176
|
+
type: dep.type,
|
|
177
|
+
packageJsonPath: dep.packageJsonPath,
|
|
178
|
+
});
|
|
107
179
|
uniquePackageNames.add(dep.name);
|
|
108
180
|
}
|
|
109
181
|
if (ignoredCount > 0) {
|
|
110
182
|
this.showProgress(`🔍 Skipped ${ignoredCount} ignored package(s)`);
|
|
111
183
|
}
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
184
|
+
const uniquePackages = Array.from(uniquePackageNames).sort((a, b) => {
|
|
185
|
+
const aIsScoped = a.startsWith('@');
|
|
186
|
+
const bIsScoped = b.startsWith('@');
|
|
187
|
+
if (aIsScoped && !bIsScoped)
|
|
188
|
+
return -1;
|
|
189
|
+
if (!aIsScoped && bIsScoped)
|
|
190
|
+
return 1;
|
|
191
|
+
return a.localeCompare(b);
|
|
192
|
+
});
|
|
193
|
+
utils_3.debugLog.info('PackageDetector', `${uniquePackages.length} unique packages to check, ${ignoredCount} ignored`);
|
|
116
194
|
const currentVersions = new Map();
|
|
117
|
-
for (const dep of
|
|
118
|
-
// Use the first occurrence of each package's version
|
|
195
|
+
for (const dep of allDependencies) {
|
|
119
196
|
if (!currentVersions.has(dep.name)) {
|
|
120
197
|
currentVersions.set(dep.name, dep.version);
|
|
121
198
|
}
|
|
122
199
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
});
|
|
132
|
-
utils_3.debugLog.perf('PackageDetector', `registry fetch (${allPackageData.size}/${packageNames.length} resolved)`, tFetch);
|
|
133
|
-
const loggedOutdated = new Set();
|
|
200
|
+
return {
|
|
201
|
+
allDependencies,
|
|
202
|
+
uniquePackages,
|
|
203
|
+
currentVersions,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
resolvePackageGroup(packageName, allDependencies, packageData) {
|
|
207
|
+
const dependencies = allDependencies.filter((dep) => dep.name === packageName);
|
|
134
208
|
const loggedNoData = new Set();
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if (!
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
utils_3.debugLog.warn('PackageDetector', `no data returned for ${dep.name} — skipping`);
|
|
143
|
-
}
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
const { latestVersion, allVersions } = packageData;
|
|
147
|
-
// Find closest minor version (same major, higher minor) that satisfies the current range
|
|
148
|
-
// Falls back to patch updates if no minor updates are available
|
|
149
|
-
const closestMinorVersion = (0, utils_1.findClosestMinorVersion)(dep.version, allVersions);
|
|
150
|
-
const installedClean = semver.coerce(dep.version)?.version || dep.version;
|
|
151
|
-
const minorClean = closestMinorVersion
|
|
152
|
-
? semver.coerce(closestMinorVersion)?.version || closestMinorVersion
|
|
153
|
-
: null;
|
|
154
|
-
const latestClean = semver.coerce(latestVersion)?.version || latestVersion;
|
|
155
|
-
const hasRangeUpdate = minorClean !== null && minorClean !== installedClean;
|
|
156
|
-
const hasMajorUpdate = semver.major(latestClean) > semver.major(installedClean);
|
|
157
|
-
const isOutdated = hasRangeUpdate || hasMajorUpdate;
|
|
158
|
-
if (isOutdated) {
|
|
159
|
-
const outdatedKey = `${dep.name}@${dep.version}`;
|
|
160
|
-
if (!loggedOutdated.has(outdatedKey)) {
|
|
161
|
-
loggedOutdated.add(outdatedKey);
|
|
162
|
-
utils_3.debugLog.info('PackageDetector', `outdated: ${dep.name} ${dep.version} → range:${closestMinorVersion ?? '-'} latest:${latestVersion}`);
|
|
163
|
-
}
|
|
209
|
+
const loggedOutdated = new Set();
|
|
210
|
+
return dependencies.map((dep) => {
|
|
211
|
+
try {
|
|
212
|
+
if (!packageData || packageData.latestVersion === 'unknown') {
|
|
213
|
+
if (!loggedNoData.has(dep.name)) {
|
|
214
|
+
loggedNoData.add(dep.name);
|
|
215
|
+
utils_3.debugLog.warn('PackageDetector', `no data returned for ${dep.name} — marking unavailable`);
|
|
164
216
|
}
|
|
165
|
-
|
|
166
|
-
name: dep.name,
|
|
167
|
-
currentVersion: dep.version, // Keep original version specifier with prefix
|
|
168
|
-
rangeVersion: closestMinorVersion || dep.version,
|
|
169
|
-
latestVersion,
|
|
170
|
-
type: dep.type,
|
|
171
|
-
packageJsonPath: dep.packageJsonPath,
|
|
172
|
-
isOutdated,
|
|
173
|
-
hasRangeUpdate,
|
|
174
|
-
hasMajorUpdate,
|
|
175
|
-
});
|
|
217
|
+
return this.createFailedPackageInfo(dep);
|
|
176
218
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
219
|
+
const { latestVersion, allVersions } = packageData;
|
|
220
|
+
const closestMinorVersion = (0, utils_1.findClosestMinorVersion)(dep.version, allVersions);
|
|
221
|
+
const installedClean = semver.coerce(dep.version)?.version || dep.version;
|
|
222
|
+
const minorClean = closestMinorVersion
|
|
223
|
+
? semver.coerce(closestMinorVersion)?.version || closestMinorVersion
|
|
224
|
+
: null;
|
|
225
|
+
const latestClean = semver.coerce(latestVersion)?.version || latestVersion;
|
|
226
|
+
const hasRangeUpdate = minorClean !== null && minorClean !== installedClean;
|
|
227
|
+
const hasMajorUpdate = semver.valid(latestClean) !== null &&
|
|
228
|
+
semver.valid(installedClean) !== null &&
|
|
229
|
+
semver.major(latestClean) > semver.major(installedClean);
|
|
230
|
+
const isOutdated = hasRangeUpdate || hasMajorUpdate;
|
|
231
|
+
if (isOutdated) {
|
|
232
|
+
const outdatedKey = `${dep.name}@${dep.version}`;
|
|
233
|
+
if (!loggedOutdated.has(outdatedKey)) {
|
|
234
|
+
loggedOutdated.add(outdatedKey);
|
|
235
|
+
utils_3.debugLog.info('PackageDetector', `outdated: ${dep.name} ${dep.version} → range:${closestMinorVersion ?? '-'} latest:${latestVersion}`);
|
|
236
|
+
}
|
|
191
237
|
}
|
|
238
|
+
return {
|
|
239
|
+
name: dep.name,
|
|
240
|
+
currentVersion: dep.version,
|
|
241
|
+
rangeVersion: closestMinorVersion || dep.version,
|
|
242
|
+
latestVersion,
|
|
243
|
+
type: dep.type,
|
|
244
|
+
packageJsonPath: dep.packageJsonPath,
|
|
245
|
+
isOutdated,
|
|
246
|
+
hasRangeUpdate,
|
|
247
|
+
hasMajorUpdate,
|
|
248
|
+
};
|
|
192
249
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
250
|
+
catch (error) {
|
|
251
|
+
utils_3.debugLog.error('PackageDetector', `error processing ${dep.name}`, error);
|
|
252
|
+
return this.createFailedPackageInfo(dep);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
createFailedPackageInfo(dep) {
|
|
257
|
+
return {
|
|
258
|
+
name: dep.name,
|
|
259
|
+
currentVersion: dep.version,
|
|
260
|
+
rangeVersion: 'unknown',
|
|
261
|
+
latestVersion: 'unknown',
|
|
262
|
+
type: dep.type,
|
|
263
|
+
packageJsonPath: dep.packageJsonPath,
|
|
264
|
+
isOutdated: false,
|
|
265
|
+
hasRangeUpdate: false,
|
|
266
|
+
hasMajorUpdate: false,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
createProgressSnapshot(total, resolved, failed, isLoading) {
|
|
270
|
+
return {
|
|
271
|
+
discovered: total,
|
|
272
|
+
resolved,
|
|
273
|
+
total,
|
|
274
|
+
failed,
|
|
275
|
+
isLoading,
|
|
276
|
+
};
|
|
202
277
|
}
|
|
203
278
|
async findPackageJsonFilesWithTimeout(timeoutMs) {
|
|
204
279
|
try {
|
|
@@ -206,7 +281,6 @@ class PackageDetector {
|
|
|
206
281
|
try {
|
|
207
282
|
return await Promise.race([
|
|
208
283
|
(0, utils_1.findAllPackageJsonFilesAsync)(this.cwd, this.excludePatterns, this.maxDepth, (currentDir, foundCount) => {
|
|
209
|
-
// Show scanning progress with current directory and count
|
|
210
284
|
const truncatedDir = currentDir.length > 50 ? '...' + currentDir.slice(-47) : currentDir;
|
|
211
285
|
this.showProgress(`🔍 Scanning ${truncatedDir} (found ${foundCount})`);
|
|
212
286
|
}),
|
|
@@ -229,7 +303,6 @@ class PackageDetector {
|
|
|
229
303
|
}
|
|
230
304
|
}
|
|
231
305
|
isWorkspaceReference(version) {
|
|
232
|
-
// Check for common workspace reference patterns
|
|
233
306
|
return (version.includes('workspace:') ||
|
|
234
307
|
version === '*' ||
|
|
235
308
|
version.startsWith('file:') ||
|
|
@@ -31,27 +31,72 @@ class UpgradeRunner {
|
|
|
31
31
|
try {
|
|
32
32
|
// Check prerequisites
|
|
33
33
|
this.checkPrerequisites();
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
const progress = {
|
|
35
|
+
discovered: 0,
|
|
36
|
+
resolved: 0,
|
|
37
|
+
total: 0,
|
|
38
|
+
failed: 0,
|
|
39
|
+
isLoading: true,
|
|
40
|
+
};
|
|
41
|
+
let selectionStates = [];
|
|
42
|
+
let refreshUI;
|
|
43
|
+
let latestPackages = [];
|
|
44
|
+
let previousSelections;
|
|
45
|
+
const selectionPromise = new Promise((resolve, reject) => {
|
|
46
|
+
const streamPromise = this.detector.streamOutdatedPackages((event) => {
|
|
47
|
+
if (event.type === 'initial') {
|
|
48
|
+
progress.discovered = event.payload.progress.discovered;
|
|
49
|
+
progress.resolved = event.payload.progress.resolved;
|
|
50
|
+
progress.total = event.payload.progress.total;
|
|
51
|
+
progress.failed = event.payload.progress.failed;
|
|
52
|
+
progress.isLoading = event.payload.progress.isLoading;
|
|
53
|
+
selectionStates = [];
|
|
54
|
+
this.ui
|
|
55
|
+
.selectPackagesToUpgradeProgressive(selectionStates, progress, (refresh) => {
|
|
56
|
+
refreshUI = refresh;
|
|
57
|
+
})
|
|
58
|
+
.then(resolve)
|
|
59
|
+
.catch(reject);
|
|
60
|
+
}
|
|
61
|
+
if (event.type === 'batch') {
|
|
62
|
+
latestPackages = latestPackages
|
|
63
|
+
.filter((pkg) => !event.payload.batch.some((item) => item.packageName === pkg.name))
|
|
64
|
+
.concat(event.payload.batch.flatMap((item) => item.packageInfo));
|
|
65
|
+
progress.discovered = event.payload.progress.discovered;
|
|
66
|
+
progress.resolved = event.payload.progress.resolved;
|
|
67
|
+
progress.total = event.payload.progress.total;
|
|
68
|
+
progress.failed = event.payload.progress.failed;
|
|
69
|
+
progress.isLoading = event.payload.progress.isLoading;
|
|
70
|
+
this.ui.appendOutdatedBatchToSelectionStates(selectionStates, event.payload.batch, previousSelections);
|
|
71
|
+
refreshUI?.();
|
|
72
|
+
}
|
|
73
|
+
if (event.type === 'complete') {
|
|
74
|
+
latestPackages = event.payload.packages;
|
|
75
|
+
progress.discovered = event.payload.progress.discovered;
|
|
76
|
+
progress.resolved = event.payload.progress.resolved;
|
|
77
|
+
progress.total = event.payload.progress.total;
|
|
78
|
+
progress.failed = event.payload.progress.failed;
|
|
79
|
+
progress.isLoading = event.payload.progress.isLoading;
|
|
80
|
+
refreshUI?.();
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
streamPromise.catch(reject);
|
|
84
|
+
});
|
|
85
|
+
let selectedChoices = await selectionPromise;
|
|
86
|
+
const outdatedPackages = this.detector.getOutdatedPackagesOnly(latestPackages);
|
|
87
|
+
if (outdatedPackages.length === 0 && selectedChoices.length === 0) {
|
|
88
|
+
console.log(chalk_1.default.green('✅ All packages are up to date!'));
|
|
40
89
|
return;
|
|
41
90
|
}
|
|
42
91
|
// Interactive selection and confirmation loop
|
|
43
|
-
let selectedChoices = [];
|
|
44
92
|
let shouldProceed = false;
|
|
45
|
-
let previousSelections;
|
|
46
93
|
while (true) {
|
|
47
|
-
// Interactive selection
|
|
48
|
-
selectedChoices = await this.ui.selectPackagesToUpgrade(packages, previousSelections);
|
|
49
94
|
if (selectedChoices.length === 0) {
|
|
50
95
|
console.log(chalk_1.default.yellow('No packages selected. Exiting...'));
|
|
51
96
|
return;
|
|
52
97
|
}
|
|
53
98
|
// Validate selected choices before confirmation
|
|
54
|
-
this.validateSelectedChoices(selectedChoices,
|
|
99
|
+
this.validateSelectedChoices(selectedChoices, latestPackages);
|
|
55
100
|
// Store current selections for potential return to selection
|
|
56
101
|
previousSelections = new Map();
|
|
57
102
|
// Convert selectedChoices back to selection state format
|
|
@@ -71,7 +116,11 @@ class UpgradeRunner {
|
|
|
71
116
|
// User pressed N or ESC - go back to selection with current selections preserved
|
|
72
117
|
console.clear();
|
|
73
118
|
console.log(chalk_1.default.bold.blue('🚀 inup\n'));
|
|
74
|
-
|
|
119
|
+
selectedChoices = progress.isLoading
|
|
120
|
+
? await this.ui.selectPackagesToUpgradeProgressive(selectionStates, progress, (refresh) => {
|
|
121
|
+
refreshUI = refresh;
|
|
122
|
+
})
|
|
123
|
+
: await this.ui.selectPackagesToUpgrade(latestPackages, previousSelections);
|
|
75
124
|
continue;
|
|
76
125
|
}
|
|
77
126
|
if (!shouldProceed) {
|
|
@@ -82,7 +131,7 @@ class UpgradeRunner {
|
|
|
82
131
|
break;
|
|
83
132
|
}
|
|
84
133
|
// Perform upgrade
|
|
85
|
-
await this.upgrader.upgradePackages(selectedChoices,
|
|
134
|
+
await this.upgrader.upgradePackages(selectedChoices, latestPackages);
|
|
86
135
|
}
|
|
87
136
|
catch (error) {
|
|
88
137
|
console.error(chalk_1.default.red(`Error: ${error}`));
|