inup 1.4.12 → 1.5.1
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/LICENSE +21 -0
- package/README.md +39 -30
- package/dist/cli.js +29 -14
- package/dist/config/project-config.js +6 -0
- package/dist/core/package-detector.js +3 -2
- package/dist/core/upgrade-runner.js +6 -3
- package/dist/features/changelog/clients/github-client.js +134 -0
- package/dist/features/changelog/clients/npm-registry-client.js +53 -0
- package/dist/features/changelog/index.js +19 -0
- package/dist/features/changelog/parsers/changelog-parser.js +68 -0
- package/dist/features/changelog/parsers/github-release-html-parser.js +61 -0
- package/dist/features/changelog/parsers/package-metadata.js +34 -0
- package/dist/features/changelog/parsers/repository-ref.js +26 -0
- package/dist/features/changelog/services/changelog-service.js +30 -0
- package/dist/features/changelog/services/package-metadata-service.js +108 -0
- package/dist/features/changelog/services/release-notes-service.js +180 -0
- package/dist/features/changelog/types/changelog.types.js +3 -0
- package/dist/interactive-ui.js +242 -114
- package/dist/services/background-audit.js +60 -0
- package/dist/services/index.js +3 -1
- package/dist/services/vulnerability-checker.js +133 -0
- package/dist/ui/controllers/index.js +8 -0
- package/dist/ui/controllers/package-info-modal-controller.js +237 -0
- package/dist/ui/controllers/vulnerability-audit-controller.js +82 -0
- package/dist/ui/index.js +3 -0
- package/dist/ui/input-handler.js +40 -9
- package/dist/ui/modal/index.js +22 -0
- package/dist/ui/modal/layout.js +84 -0
- package/dist/ui/modal/package-info-sections.js +327 -0
- package/dist/ui/modal/package-info.js +147 -0
- package/dist/ui/modal/theme-selector.js +46 -0
- package/dist/ui/modal/types.js +3 -0
- package/dist/ui/presenters/index.js +11 -0
- package/dist/ui/presenters/vulnerability.js +76 -0
- package/dist/ui/renderer/index.js +9 -11
- package/dist/ui/renderer/package-list.js +135 -62
- package/dist/ui/state/filter-manager.js +17 -2
- package/dist/ui/state/modal-manager.js +48 -6
- package/dist/ui/state/state-manager.js +42 -7
- package/dist/ui/utils/cursor.js +18 -0
- package/dist/ui/utils/index.js +8 -1
- package/dist/ui/utils/terminal-input.js +125 -0
- package/dist/ui/utils/text.js +75 -0
- package/dist/ui/utils/version.js +3 -2
- package/dist/utils/git.js +33 -0
- package/dist/utils/index.js +1 -0
- package/package.json +22 -19
- package/dist/services/changelog-fetcher.js +0 -215
- package/dist/ui/renderer/modal.js +0 -190
- package/dist/ui/renderer/theme-selector.js +0 -83
package/dist/interactive-ui.js
CHANGED
|
@@ -37,18 +37,31 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.InteractiveUI = void 0;
|
|
40
|
-
const inquirer_1 = __importDefault(require("inquirer"));
|
|
41
40
|
const chalk_1 = __importDefault(require("chalk"));
|
|
42
41
|
const semver = __importStar(require("semver"));
|
|
43
|
-
const keypress = require('keypress');
|
|
44
42
|
const ui_1 = require("./ui");
|
|
45
|
-
const
|
|
43
|
+
const controllers_1 = require("./ui/controllers");
|
|
46
44
|
const themes_1 = require("./ui/themes");
|
|
47
45
|
const themes_colors_1 = require("./ui/themes-colors");
|
|
46
|
+
const DEFAULT_VULNERABILITY_DISPLAY_OPTIONS = {
|
|
47
|
+
showPeerDependencyVulnerabilities: false,
|
|
48
|
+
showOptionalDependencyVulnerabilities: false,
|
|
49
|
+
};
|
|
50
|
+
function normalizeVulnerabilityDisplayOptions(options) {
|
|
51
|
+
return {
|
|
52
|
+
showPeerDependencyVulnerabilities: options?.showPeerDependencyVulnerabilities ??
|
|
53
|
+
DEFAULT_VULNERABILITY_DISPLAY_OPTIONS.showPeerDependencyVulnerabilities,
|
|
54
|
+
showOptionalDependencyVulnerabilities: options?.showOptionalDependencyVulnerabilities ??
|
|
55
|
+
DEFAULT_VULNERABILITY_DISPLAY_OPTIONS.showOptionalDependencyVulnerabilities,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
48
58
|
class InteractiveUI {
|
|
49
|
-
constructor(packageManager) {
|
|
59
|
+
constructor(packageManager, options) {
|
|
60
|
+
this.vulnerabilityAuditController = new controllers_1.VulnerabilityAuditController();
|
|
61
|
+
this.packageInfoModalController = new controllers_1.PackageInfoModalController();
|
|
50
62
|
this.renderer = new ui_1.UIRenderer();
|
|
51
63
|
this.packageManager = packageManager;
|
|
64
|
+
this.options = normalizeVulnerabilityDisplayOptions(options);
|
|
52
65
|
}
|
|
53
66
|
async displayPackagesTable(packages) {
|
|
54
67
|
console.log(this.renderer.renderPackagesTable(packages));
|
|
@@ -83,6 +96,8 @@ class InteractiveUI {
|
|
|
83
96
|
hasRangeUpdate: pkg.hasRangeUpdate,
|
|
84
97
|
hasMajorUpdate: pkg.hasMajorUpdate,
|
|
85
98
|
type: pkg.type,
|
|
99
|
+
vulnerability: this.vulnerabilityAuditController.getCachedSummary(pkg.name, pkg.currentVersion, pkg.type),
|
|
100
|
+
allVersions: pkg.allVersions,
|
|
86
101
|
};
|
|
87
102
|
});
|
|
88
103
|
}
|
|
@@ -112,6 +127,7 @@ class InteractiveUI {
|
|
|
112
127
|
hasRangeUpdate: false,
|
|
113
128
|
hasMajorUpdate: false,
|
|
114
129
|
type: pkg.type,
|
|
130
|
+
vulnerability: this.vulnerabilityAuditController.getCachedSummary(pkg.name, pkg.currentVersion, pkg.type),
|
|
115
131
|
};
|
|
116
132
|
});
|
|
117
133
|
}
|
|
@@ -128,11 +144,16 @@ class InteractiveUI {
|
|
|
128
144
|
seen.add(key);
|
|
129
145
|
}
|
|
130
146
|
});
|
|
147
|
+
this.enqueueSecurityAudit(selectionStates);
|
|
131
148
|
}
|
|
132
149
|
async selectPackagesToUpgradeProgressive(selectionStates, progress, attachRefresh) {
|
|
150
|
+
this.enqueueSecurityAudit(selectionStates);
|
|
133
151
|
const selectedStates = await this.interactiveTableSelector(selectionStates, progress, attachRefresh);
|
|
134
152
|
return this.createUpgradeChoices(selectedStates);
|
|
135
153
|
}
|
|
154
|
+
enqueueSecurityAudit(selectionStates) {
|
|
155
|
+
this.vulnerabilityAuditController.enqueueStates(selectionStates, () => this.refreshView?.());
|
|
156
|
+
}
|
|
136
157
|
deduplicatePackages(packages) {
|
|
137
158
|
const uniquePackages = new Map();
|
|
138
159
|
for (const pkg of packages) {
|
|
@@ -180,7 +201,9 @@ class InteractiveUI {
|
|
|
180
201
|
}
|
|
181
202
|
getTerminalHeight() {
|
|
182
203
|
// Check if stdout is a TTY and has rows property
|
|
183
|
-
if (process.stdout.isTTY &&
|
|
204
|
+
if (process.stdout.isTTY &&
|
|
205
|
+
typeof process.stdout.rows === 'number' &&
|
|
206
|
+
process.stdout.rows > 0) {
|
|
184
207
|
return process.stdout.rows;
|
|
185
208
|
}
|
|
186
209
|
return 24; // Fallback default
|
|
@@ -190,84 +213,150 @@ class InteractiveUI {
|
|
|
190
213
|
const states = selectionStates;
|
|
191
214
|
const stateManager = new ui_1.StateManager(0, this.getTerminalHeight());
|
|
192
215
|
let isResolved = false;
|
|
216
|
+
let ownsAlternateScreen = false;
|
|
217
|
+
const vulnerabilityDisplayOptions = this.options;
|
|
218
|
+
const claimInteractiveScreen = () => {
|
|
219
|
+
if (ownsAlternateScreen) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
ui_1.ConsoleUtils.clearProgress();
|
|
223
|
+
ui_1.CursorUtils.enterAlternateScreen();
|
|
224
|
+
ui_1.CursorUtils.clearScreen();
|
|
225
|
+
ownsAlternateScreen = true;
|
|
226
|
+
};
|
|
227
|
+
const releaseInteractiveScreen = () => {
|
|
228
|
+
if (!ownsAlternateScreen) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
ui_1.CursorUtils.exitAlternateScreen();
|
|
232
|
+
ownsAlternateScreen = false;
|
|
233
|
+
};
|
|
193
234
|
// No grouping needed - packages are already filtered by type
|
|
194
235
|
// This simplifies scrolling and avoids rendering issues
|
|
195
236
|
stateManager.setRenderableItems([]);
|
|
237
|
+
// Track the current max scroll offset for the info modal
|
|
238
|
+
let infoModalMaxScrollOffset = 0;
|
|
239
|
+
let previousViewportMode = null;
|
|
240
|
+
let previousModalViewportLineCount = null;
|
|
196
241
|
const handleAction = (action) => {
|
|
197
242
|
const uiState = stateManager.getUIState();
|
|
198
|
-
const filteredStates = stateManager.getFilteredStates(states);
|
|
243
|
+
const filteredStates = stateManager.getFilteredStates(states, vulnerabilityDisplayOptions);
|
|
199
244
|
switch (action.type) {
|
|
200
245
|
case 'navigate_up':
|
|
201
|
-
if (!uiState.
|
|
246
|
+
if (!uiState.showThemeModal) {
|
|
202
247
|
stateManager.navigateUp(filteredStates.length);
|
|
203
248
|
}
|
|
204
249
|
break;
|
|
205
250
|
case 'navigate_down':
|
|
206
|
-
if (!uiState.
|
|
251
|
+
if (!uiState.showThemeModal) {
|
|
207
252
|
stateManager.navigateDown(filteredStates.length);
|
|
208
253
|
}
|
|
209
254
|
break;
|
|
210
255
|
case 'select_left':
|
|
211
|
-
if (!uiState.
|
|
256
|
+
if (!uiState.showThemeModal) {
|
|
212
257
|
stateManager.updateSelection(filteredStates, 'left');
|
|
213
258
|
}
|
|
214
259
|
break;
|
|
215
260
|
case 'select_right':
|
|
216
|
-
if (!uiState.
|
|
261
|
+
if (!uiState.showThemeModal) {
|
|
217
262
|
stateManager.updateSelection(filteredStates, 'right');
|
|
218
263
|
}
|
|
219
264
|
break;
|
|
220
265
|
case 'bulk_select_minor':
|
|
221
|
-
if (!uiState.
|
|
266
|
+
if (!uiState.showThemeModal) {
|
|
222
267
|
stateManager.bulkSelectMinor(filteredStates);
|
|
223
268
|
}
|
|
224
269
|
break;
|
|
225
270
|
case 'bulk_select_latest':
|
|
226
|
-
if (!uiState.
|
|
271
|
+
if (!uiState.showThemeModal) {
|
|
227
272
|
stateManager.bulkSelectLatest(filteredStates);
|
|
228
273
|
}
|
|
229
274
|
break;
|
|
230
275
|
case 'bulk_unselect_all':
|
|
231
|
-
if (!uiState.
|
|
276
|
+
if (!uiState.showThemeModal) {
|
|
232
277
|
stateManager.bulkUnselectAll(filteredStates);
|
|
233
278
|
}
|
|
234
279
|
break;
|
|
235
280
|
case 'toggle_dep_type_filter':
|
|
236
|
-
if (!uiState.
|
|
281
|
+
if (!uiState.showThemeModal) {
|
|
237
282
|
stateManager.toggleDependencyTypeFilter(action.depType);
|
|
238
283
|
}
|
|
239
284
|
break;
|
|
240
285
|
case 'toggle_info_modal':
|
|
241
286
|
if (!uiState.showInfoModal) {
|
|
242
287
|
// Opening modal - load package info asynchronously
|
|
243
|
-
stateManager.toggleInfoModal();
|
|
288
|
+
const modalSessionId = stateManager.toggleInfoModal();
|
|
244
289
|
const currentState = filteredStates[uiState.currentRow];
|
|
245
290
|
const canFetchMetadata = currentState?.loadState === 'ready';
|
|
246
|
-
stateManager.setModalLoading(canFetchMetadata);
|
|
291
|
+
stateManager.setModalLoading(canFetchMetadata, modalSessionId);
|
|
247
292
|
renderInterface();
|
|
248
293
|
if (currentState && canFetchMetadata) {
|
|
249
|
-
|
|
250
|
-
.
|
|
251
|
-
.then((
|
|
252
|
-
if (
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
currentState
|
|
294
|
+
this.packageInfoModalController
|
|
295
|
+
.hydrate(currentState)
|
|
296
|
+
.then(() => {
|
|
297
|
+
if (isResolved || stateManager.getInfoModalSessionId() !== modalSessionId)
|
|
298
|
+
return;
|
|
299
|
+
stateManager.setModalLoading(false, modalSessionId);
|
|
300
|
+
renderInterface();
|
|
301
|
+
// Auto-load the first version's release notes
|
|
302
|
+
if (stateManager.getInfoModalSessionId() === modalSessionId &&
|
|
303
|
+
this.packageInfoModalController.getVersionCount(currentState) > 0) {
|
|
304
|
+
this.packageInfoModalController.loadVersionAtIndex(currentState, 0, () => {
|
|
305
|
+
if (!isResolved)
|
|
306
|
+
renderInterface();
|
|
307
|
+
});
|
|
259
308
|
}
|
|
260
|
-
|
|
309
|
+
})
|
|
310
|
+
.catch(() => {
|
|
311
|
+
if (isResolved || stateManager.getInfoModalSessionId() !== modalSessionId)
|
|
312
|
+
return;
|
|
313
|
+
stateManager.setModalLoading(false, modalSessionId);
|
|
261
314
|
renderInterface();
|
|
262
315
|
});
|
|
263
316
|
}
|
|
264
317
|
}
|
|
265
318
|
else {
|
|
266
|
-
// Closing modal
|
|
319
|
+
// Closing modal - cancel in-flight fetches
|
|
320
|
+
this.packageInfoModalController.cancel();
|
|
267
321
|
stateManager.toggleInfoModal();
|
|
268
322
|
renderInterface();
|
|
269
323
|
}
|
|
270
324
|
break;
|
|
325
|
+
case 'scroll_info_modal_up':
|
|
326
|
+
if (!stateManager.scrollInfoModalUp()) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
break;
|
|
330
|
+
case 'scroll_info_modal_down':
|
|
331
|
+
if (!stateManager.scrollInfoModalDown(infoModalMaxScrollOffset)) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
break;
|
|
335
|
+
case 'navigate_info_modal_version':
|
|
336
|
+
{
|
|
337
|
+
if (uiState.infoModalRow >= 0 && uiState.infoModalRow < filteredStates.length) {
|
|
338
|
+
const currentState = filteredStates[uiState.infoModalRow];
|
|
339
|
+
const newIndex = this.packageInfoModalController.navigateVersion(currentState, action.direction);
|
|
340
|
+
if (newIndex >= 0) {
|
|
341
|
+
// Reset scroll to top when switching versions
|
|
342
|
+
stateManager.resetInfoModalScroll();
|
|
343
|
+
// Load the version if not already loaded
|
|
344
|
+
if (!this.packageInfoModalController.isVersionLoaded(currentState, newIndex)) {
|
|
345
|
+
this.packageInfoModalController.loadVersionAtIndex(currentState, newIndex, () => {
|
|
346
|
+
if (!isResolved)
|
|
347
|
+
renderInterface();
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
break;
|
|
271
360
|
case 'enter_filter_mode':
|
|
272
361
|
stateManager.enterFilterMode(action.preserveQuery);
|
|
273
362
|
break;
|
|
@@ -315,7 +404,19 @@ class InteractiveUI {
|
|
|
315
404
|
case 'theme_confirm':
|
|
316
405
|
stateManager.confirmTheme();
|
|
317
406
|
break;
|
|
407
|
+
case 'trigger_audit_scan':
|
|
408
|
+
if (!uiState.showThemeModal) {
|
|
409
|
+
const auditProgress = this.vulnerabilityAuditController.getProgress();
|
|
410
|
+
if (auditProgress.hasData) {
|
|
411
|
+
stateManager.toggleVulnerableFilter();
|
|
412
|
+
}
|
|
413
|
+
else if (!auditProgress.isRunning) {
|
|
414
|
+
this.enqueueSecurityAudit(states);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
break;
|
|
318
418
|
case 'cancel':
|
|
419
|
+
this.packageInfoModalController.cancel();
|
|
319
420
|
handleCancel();
|
|
320
421
|
return;
|
|
321
422
|
}
|
|
@@ -324,42 +425,79 @@ class InteractiveUI {
|
|
|
324
425
|
}
|
|
325
426
|
};
|
|
326
427
|
const handleConfirm = (selectedStates) => {
|
|
327
|
-
|
|
328
|
-
// Reset terminal colors
|
|
329
|
-
process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
|
|
330
|
-
ui_1.CursorUtils.show();
|
|
331
|
-
// Clean up listeners
|
|
332
|
-
if (process.stdin.setRawMode) {
|
|
333
|
-
process.stdin.setRawMode(false);
|
|
334
|
-
}
|
|
335
|
-
process.stdin.removeAllListeners('keypress');
|
|
336
|
-
process.stdin.pause();
|
|
337
|
-
process.removeAllListeners('SIGWINCH');
|
|
338
|
-
resolve(selectedStates);
|
|
428
|
+
finalizeSelection(selectedStates);
|
|
339
429
|
};
|
|
340
430
|
const handleCancel = () => {
|
|
341
|
-
|
|
342
|
-
|
|
431
|
+
finalizeSelection(states.map((s) => ({ ...s, selectedOption: 'none' })));
|
|
432
|
+
};
|
|
433
|
+
const inputHandler = new ui_1.InputHandler(stateManager, handleAction, handleConfirm, handleCancel);
|
|
434
|
+
const resetAnsiPattern = /\x1b\[(?:0|49)m/g;
|
|
435
|
+
const packageListRenderOptions = {
|
|
436
|
+
showPeerDependencyVulnerabilities: this.options.showPeerDependencyVulnerabilities,
|
|
437
|
+
showOptionalDependencyVulnerabilities: this.options.showOptionalDependencyVulnerabilities,
|
|
438
|
+
};
|
|
439
|
+
const keypressHandler = (str, key) => inputHandler.handleKeypress(str, key, states);
|
|
440
|
+
const buildRemainingViewport = (terminalWidth, terminalHeight, usedLines) => {
|
|
441
|
+
const remainingLines = Math.max(0, terminalHeight - usedLines);
|
|
442
|
+
const blankLine = ' '.repeat(terminalWidth);
|
|
443
|
+
return Array.from({ length: remainingLines }, () => blankLine);
|
|
444
|
+
};
|
|
445
|
+
const applyBackgroundToLine = (line, bgCode) => `${bgCode}${line.replace(resetAnsiPattern, (match) => `${match}${bgCode}`)}${(0, themes_colors_1.getTerminalResetCode)()}`;
|
|
446
|
+
const writeFrame = (lines, bgCode) => {
|
|
447
|
+
if (lines.length === 0) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
process.stdout.write(lines.map((line) => applyBackgroundToLine(line, bgCode)).join('\n'));
|
|
451
|
+
};
|
|
452
|
+
const buildModalHeaderLines = (shortcutLabel) => [
|
|
453
|
+
' ' + chalk_1.default.bold.magenta('🚀 inup'),
|
|
454
|
+
'',
|
|
455
|
+
' ' + shortcutLabel,
|
|
456
|
+
'',
|
|
457
|
+
];
|
|
458
|
+
const renderViewport = (lines, terminalWidth, terminalHeight, bgCode) => {
|
|
459
|
+
const viewportLines = [
|
|
460
|
+
...lines,
|
|
461
|
+
...buildRemainingViewport(terminalWidth, terminalHeight, lines.length),
|
|
462
|
+
];
|
|
463
|
+
writeFrame(viewportLines, bgCode);
|
|
464
|
+
};
|
|
465
|
+
const renderModalViewport = (mode, shortcutLabel, modalLines, terminalWidth, terminalHeight, bgCode) => {
|
|
466
|
+
const viewportLineCount = buildModalHeaderLines(shortcutLabel).length + modalLines.length;
|
|
467
|
+
const shouldClearBeforeRender = previousViewportMode !== mode || previousModalViewportLineCount !== viewportLineCount;
|
|
468
|
+
if (shouldClearBeforeRender) {
|
|
469
|
+
ui_1.CursorUtils.clearScreen();
|
|
470
|
+
ui_1.CursorUtils.hide();
|
|
471
|
+
}
|
|
472
|
+
renderViewport([...buildModalHeaderLines(shortcutLabel), ...modalLines], terminalWidth, terminalHeight, bgCode);
|
|
473
|
+
previousViewportMode = mode;
|
|
474
|
+
previousModalViewportLineCount = viewportLineCount;
|
|
475
|
+
stateManager.markRendered([]);
|
|
476
|
+
};
|
|
477
|
+
let cleanupInteractiveSession = () => {
|
|
343
478
|
process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
|
|
344
479
|
ui_1.CursorUtils.show();
|
|
345
|
-
|
|
346
|
-
if (process.stdin.setRawMode) {
|
|
347
|
-
process.stdin.setRawMode(false);
|
|
348
|
-
}
|
|
349
|
-
process.stdin.removeAllListeners('keypress');
|
|
480
|
+
process.stdin.off('keypress', keypressHandler);
|
|
350
481
|
process.stdin.pause();
|
|
351
|
-
process.
|
|
352
|
-
|
|
482
|
+
process.off('SIGWINCH', handleResize);
|
|
483
|
+
this.refreshView = undefined;
|
|
484
|
+
};
|
|
485
|
+
const finalizeSelection = (selectedStates) => {
|
|
486
|
+
isResolved = true;
|
|
487
|
+
this.packageInfoModalController.cancel();
|
|
488
|
+
releaseInteractiveScreen();
|
|
489
|
+
cleanupInteractiveSession();
|
|
490
|
+
resolve(selectedStates);
|
|
353
491
|
};
|
|
354
|
-
const inputHandler = new ui_1.InputHandler(stateManager, handleAction, handleConfirm, handleCancel);
|
|
355
492
|
const renderInterface = () => {
|
|
356
493
|
const uiState = stateManager.getUIState();
|
|
357
|
-
const filteredStates = stateManager.getFilteredStates(states);
|
|
494
|
+
const filteredStates = stateManager.getFilteredStates(states, vulnerabilityDisplayOptions);
|
|
495
|
+
const auditProgress = this.vulnerabilityAuditController.getProgress();
|
|
358
496
|
// Apply terminal background color
|
|
359
497
|
const bgCode = (0, themes_colors_1.getTerminalBgColorCode)();
|
|
360
498
|
process.stdout.write(bgCode);
|
|
361
499
|
if (uiState.forceFullRender) {
|
|
362
|
-
|
|
500
|
+
ui_1.CursorUtils.clearScreen();
|
|
363
501
|
ui_1.CursorUtils.hide();
|
|
364
502
|
}
|
|
365
503
|
else {
|
|
@@ -370,62 +508,48 @@ class InteractiveUI {
|
|
|
370
508
|
const terminalWidth = process.stdout.columns || 80;
|
|
371
509
|
const terminalHeight = this.getTerminalHeight();
|
|
372
510
|
const themeManager = stateManager.getThemeManager();
|
|
373
|
-
// Render header
|
|
374
|
-
const headerLines = [];
|
|
375
|
-
headerLines.push(' ' + chalk_1.default.bold.magenta('🚀 inup'));
|
|
376
|
-
headerLines.push('');
|
|
377
|
-
headerLines.push(' ' +
|
|
378
|
-
chalk_1.default.bold.white('T ') +
|
|
379
|
-
chalk_1.default.gray('/ Esc Exit theme selector'));
|
|
380
|
-
headerLines.push('');
|
|
381
|
-
headerLines.forEach((line) => console.log(line));
|
|
382
511
|
const modalLines = this.renderer.renderThemeSelectorModal(themeManager.getCurrentTheme(), themeManager.getPreviewTheme(), terminalWidth, terminalHeight);
|
|
383
|
-
|
|
384
|
-
// Clear any remaining lines from previous render
|
|
385
|
-
ui_1.CursorUtils.clearToEndOfScreen();
|
|
386
|
-
stateManager.markRendered([]);
|
|
512
|
+
renderModalViewport('theme-modal', chalk_1.default.bold.white('T ') + chalk_1.default.gray('/ Esc Exit theme selector'), modalLines, terminalWidth, terminalHeight, bgCode);
|
|
387
513
|
}
|
|
388
|
-
else if (uiState.showInfoModal &&
|
|
514
|
+
else if (uiState.showInfoModal &&
|
|
515
|
+
uiState.infoModalRow >= 0 &&
|
|
516
|
+
uiState.infoModalRow < filteredStates.length) {
|
|
389
517
|
const selectedState = filteredStates[uiState.infoModalRow];
|
|
390
518
|
const terminalWidth = process.stdout.columns || 80;
|
|
391
519
|
const terminalHeight = this.getTerminalHeight();
|
|
392
|
-
// Render header
|
|
393
|
-
const headerLines = [];
|
|
394
|
-
headerLines.push(' ' + chalk_1.default.bold.magenta('🚀 inup'));
|
|
395
|
-
headerLines.push('');
|
|
396
|
-
headerLines.push(' ' +
|
|
397
|
-
chalk_1.default.bold.white('I / Esc ') +
|
|
398
|
-
chalk_1.default.gray('Exit this view'));
|
|
399
|
-
headerLines.push('');
|
|
400
|
-
headerLines.forEach((line) => console.log(line));
|
|
401
520
|
if (uiState.isLoadingModalInfo) {
|
|
402
521
|
// Show loading state
|
|
403
|
-
const
|
|
404
|
-
|
|
522
|
+
const result = this.renderer.renderPackageInfoLoading(selectedState, terminalWidth, Math.max(8, terminalHeight - 4));
|
|
523
|
+
infoModalMaxScrollOffset = result.maxScrollOffset;
|
|
524
|
+
renderModalViewport('info-modal', chalk_1.default.bold.white('I / Esc ') + chalk_1.default.gray('Exit this view'), result.lines, terminalWidth, terminalHeight, bgCode);
|
|
405
525
|
}
|
|
406
526
|
else {
|
|
407
|
-
// Show full info
|
|
408
|
-
const
|
|
409
|
-
|
|
527
|
+
// Show full info with scroll support
|
|
528
|
+
const result = this.renderer.renderPackageInfoModal(selectedState, terminalWidth, Math.max(8, terminalHeight - 4), uiState.infoModalScrollOffset);
|
|
529
|
+
infoModalMaxScrollOffset = result.maxScrollOffset;
|
|
530
|
+
stateManager.clampInfoModalScrollOffset(infoModalMaxScrollOffset);
|
|
531
|
+
const scrollHint = result.usesInternalScroll && result.maxScrollOffset > 0
|
|
532
|
+
? chalk_1.default.bold.white('↑/↓ ') + chalk_1.default.gray('Scroll · ')
|
|
533
|
+
: '';
|
|
534
|
+
renderModalViewport('info-modal', scrollHint +
|
|
535
|
+
chalk_1.default.bold.white('←/→ ') +
|
|
536
|
+
chalk_1.default.gray('Version · ') +
|
|
537
|
+
chalk_1.default.bold.white('I / Esc ') +
|
|
538
|
+
chalk_1.default.gray('Exit this view'), result.lines, terminalWidth, terminalHeight, bgCode);
|
|
410
539
|
}
|
|
411
|
-
// Clear any remaining lines from previous render
|
|
412
|
-
ui_1.CursorUtils.clearToEndOfScreen();
|
|
413
|
-
stateManager.markRendered([]);
|
|
414
540
|
}
|
|
415
541
|
else {
|
|
416
542
|
// Normal list view (flat rendering - no grouping)
|
|
417
543
|
const terminalWidth = process.stdout.columns || 80;
|
|
544
|
+
const terminalHeight = this.getTerminalHeight();
|
|
418
545
|
const activeFilterLabel = stateManager.getActiveFilterLabel();
|
|
419
546
|
const lines = this.renderer.renderInterface(filteredStates, uiState.currentRow, uiState.scrollOffset, uiState.maxVisibleItems, uiState.forceFullRender, [], // No renderable items - use flat rendering
|
|
420
547
|
activeFilterLabel, // Show current dependency type filter state
|
|
421
548
|
this.packageManager, // Pass package manager info for header
|
|
422
|
-
uiState.filterMode, uiState.filterQuery, states.length, terminalWidth, loadingProgress);
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
if (!uiState.forceFullRender) {
|
|
427
|
-
ui_1.CursorUtils.clearToEndOfScreen();
|
|
428
|
-
}
|
|
549
|
+
uiState.filterMode, uiState.filterQuery, states.length, terminalWidth, loadingProgress, auditProgress, packageListRenderOptions);
|
|
550
|
+
renderViewport(lines, terminalWidth, terminalHeight, bgCode);
|
|
551
|
+
previousViewportMode = 'list';
|
|
552
|
+
previousModalViewportLineCount = null;
|
|
429
553
|
stateManager.markRendered(lines);
|
|
430
554
|
}
|
|
431
555
|
stateManager.setInitialRender(false);
|
|
@@ -438,32 +562,41 @@ class InteractiveUI {
|
|
|
438
562
|
};
|
|
439
563
|
// Setup keypress handling
|
|
440
564
|
try {
|
|
565
|
+
claimInteractiveScreen();
|
|
566
|
+
this.refreshView = () => {
|
|
567
|
+
if (!isResolved) {
|
|
568
|
+
renderInterface();
|
|
569
|
+
}
|
|
570
|
+
};
|
|
441
571
|
attachRefresh?.(() => {
|
|
442
572
|
if (!isResolved) {
|
|
443
573
|
renderInterface();
|
|
444
574
|
}
|
|
445
575
|
});
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
576
|
+
const keypressSession = ui_1.TerminalInput.startKeypressSession(keypressHandler);
|
|
577
|
+
const previousCleanup = cleanupInteractiveSession;
|
|
578
|
+
cleanupInteractiveSession = () => {
|
|
579
|
+
keypressSession.close();
|
|
580
|
+
previousCleanup();
|
|
581
|
+
};
|
|
452
582
|
// Setup resize handler
|
|
453
583
|
process.on('SIGWINCH', handleResize);
|
|
454
584
|
// Update terminal height directly before initial render to ensure correct dimensions
|
|
455
585
|
// This handles cases where process.stdout.rows might not be accurate at startup
|
|
456
586
|
const currentHeight = this.getTerminalHeight();
|
|
457
587
|
if (stateManager.updateTerminalHeight(currentHeight)) {
|
|
458
|
-
const initialFiltered = stateManager.getFilteredStates(states);
|
|
588
|
+
const initialFiltered = stateManager.getFilteredStates(states, vulnerabilityDisplayOptions);
|
|
459
589
|
stateManager.resetForResize(initialFiltered.length);
|
|
460
590
|
}
|
|
461
591
|
// Initial render
|
|
462
592
|
renderInterface();
|
|
593
|
+
this.enqueueSecurityAudit(states);
|
|
463
594
|
}
|
|
464
595
|
catch (error) {
|
|
596
|
+
releaseInteractiveScreen();
|
|
465
597
|
// Reset terminal colors
|
|
466
598
|
process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
|
|
599
|
+
this.refreshView = undefined;
|
|
467
600
|
// Fallback to simple interface if raw mode fails
|
|
468
601
|
console.log(chalk_1.default.yellow('Raw mode not available, using fallback interface...'));
|
|
469
602
|
resolve(states);
|
|
@@ -473,32 +606,27 @@ class InteractiveUI {
|
|
|
473
606
|
async confirmUpgrade(choices) {
|
|
474
607
|
console.log(this.renderer.renderConfirmation(choices));
|
|
475
608
|
return new Promise((resolve) => {
|
|
609
|
+
let cleanupConfirmationSession = () => {
|
|
610
|
+
ui_1.CursorUtils.show();
|
|
611
|
+
};
|
|
476
612
|
const handleConfirm = (confirmed) => {
|
|
613
|
+
cleanupConfirmationSession();
|
|
477
614
|
resolve(confirmed);
|
|
478
615
|
};
|
|
479
616
|
const inputHandler = new ui_1.ConfirmationInputHandler(handleConfirm);
|
|
617
|
+
const keypressHandler = (str, key) => inputHandler.handleKeypress(str, key);
|
|
480
618
|
// Setup keypress handling
|
|
481
619
|
try {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
620
|
+
const keypressSession = ui_1.TerminalInput.startKeypressSession(keypressHandler);
|
|
621
|
+
cleanupConfirmationSession = () => {
|
|
622
|
+
keypressSession.close();
|
|
623
|
+
ui_1.CursorUtils.show();
|
|
624
|
+
};
|
|
486
625
|
ui_1.CursorUtils.hide();
|
|
487
|
-
process.stdin.resume();
|
|
488
|
-
process.stdin.on('keypress', (str, key) => inputHandler.handleKeypress(str, key));
|
|
489
626
|
}
|
|
490
627
|
catch (error) {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
.prompt([
|
|
494
|
-
{
|
|
495
|
-
type: 'confirm',
|
|
496
|
-
name: 'proceed',
|
|
497
|
-
message: 'Proceed with upgrade?',
|
|
498
|
-
default: true,
|
|
499
|
-
},
|
|
500
|
-
])
|
|
501
|
-
.then((answer) => resolve(answer.proceed))
|
|
628
|
+
ui_1.TerminalInput.promptForConfirmation('Proceed with upgrade? [Y/n] ')
|
|
629
|
+
.then(resolve)
|
|
502
630
|
.catch(() => resolve(false));
|
|
503
631
|
}
|
|
504
632
|
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BackgroundAuditTracker = void 0;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
class BackgroundAuditTracker {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.pending = new Map();
|
|
8
|
+
this.inFlight = new Set();
|
|
9
|
+
this.completed = new Set();
|
|
10
|
+
}
|
|
11
|
+
enqueue(packages) {
|
|
12
|
+
let added = 0;
|
|
13
|
+
for (const pkg of packages) {
|
|
14
|
+
if (!pkg.name || !pkg.version)
|
|
15
|
+
continue;
|
|
16
|
+
if (this.pending.has(pkg.name) ||
|
|
17
|
+
this.inFlight.has(pkg.name) ||
|
|
18
|
+
this.completed.has(pkg.name)) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
this.pending.set(pkg.name, pkg.version);
|
|
22
|
+
added++;
|
|
23
|
+
}
|
|
24
|
+
if (added > 0) {
|
|
25
|
+
utils_1.debugLog.info('background-audit', `queued ${added} package(s)`);
|
|
26
|
+
}
|
|
27
|
+
return added;
|
|
28
|
+
}
|
|
29
|
+
reserveNextBatch(limit = 20) {
|
|
30
|
+
const packages = new Map();
|
|
31
|
+
const packageNames = [];
|
|
32
|
+
for (const [name, version] of this.pending) {
|
|
33
|
+
packages.set(name, version);
|
|
34
|
+
packageNames.push(name);
|
|
35
|
+
this.pending.delete(name);
|
|
36
|
+
this.inFlight.add(name);
|
|
37
|
+
if (packageNames.length >= limit) {
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { packages, packageNames };
|
|
42
|
+
}
|
|
43
|
+
markCompleted(packageNames) {
|
|
44
|
+
for (const packageName of packageNames) {
|
|
45
|
+
this.inFlight.delete(packageName);
|
|
46
|
+
this.completed.add(packageName);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
getProgress() {
|
|
50
|
+
const total = this.pending.size + this.inFlight.size + this.completed.size;
|
|
51
|
+
return {
|
|
52
|
+
completed: this.completed.size,
|
|
53
|
+
total,
|
|
54
|
+
isRunning: this.pending.size > 0 || this.inFlight.size > 0,
|
|
55
|
+
hasData: this.completed.size > 0,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.BackgroundAuditTracker = BackgroundAuditTracker;
|
|
60
|
+
//# sourceMappingURL=background-audit.js.map
|
package/dist/services/index.js
CHANGED
|
@@ -19,6 +19,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
20
|
__exportStar(require("./npm-registry"), exports);
|
|
21
21
|
__exportStar(require("./jsdelivr-registry"), exports);
|
|
22
|
-
__exportStar(require("
|
|
22
|
+
__exportStar(require("../features/changelog"), exports);
|
|
23
23
|
__exportStar(require("./version-checker"), exports);
|
|
24
|
+
__exportStar(require("./vulnerability-checker"), exports);
|
|
25
|
+
__exportStar(require("./background-audit"), exports);
|
|
24
26
|
//# sourceMappingURL=index.js.map
|