inup 1.5.4 → 1.5.6

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 (65) hide show
  1. package/README.md +24 -10
  2. package/dist/cli.js +20 -22
  3. package/dist/config/constants.js +4 -2
  4. package/dist/config/package-meta.js +10 -0
  5. package/dist/config/project-config.js +6 -1
  6. package/dist/core/package-detector.js +8 -4
  7. package/dist/core/upgrade-runner.js +7 -10
  8. package/dist/core/upgrader.js +6 -8
  9. package/dist/features/changelog/clients/github-client.js +5 -6
  10. package/dist/features/changelog/services/changelog-service.js +2 -4
  11. package/dist/features/changelog/services/package-metadata-service.js +6 -11
  12. package/dist/features/changelog/services/release-notes-service.js +4 -2
  13. package/dist/features/debug/services/performance-tracker.js +6 -8
  14. package/dist/index.js +1 -2
  15. package/dist/interactive-ui.js +30 -587
  16. package/dist/services/background-audit.js +3 -5
  17. package/dist/services/cache-manager.js +5 -7
  18. package/dist/services/http/inflight.js +22 -0
  19. package/dist/services/http/retry.js +30 -0
  20. package/dist/services/jsdelivr/client.js +191 -0
  21. package/dist/services/jsdelivr/manifest.js +136 -0
  22. package/dist/services/jsdelivr-registry.js +6 -392
  23. package/dist/services/npm-registry.js +12 -81
  24. package/dist/services/persistent-cache.js +8 -13
  25. package/dist/types/domain.js +3 -0
  26. package/dist/types/streaming.js +3 -0
  27. package/dist/types/ui.js +3 -0
  28. package/dist/types.js +17 -0
  29. package/dist/ui/controllers/package-info-modal-controller.js +22 -31
  30. package/dist/ui/controllers/vulnerability-audit-controller.js +17 -8
  31. package/dist/ui/index.js +3 -0
  32. package/dist/ui/input-handler.js +62 -77
  33. package/dist/ui/keymap.js +208 -0
  34. package/dist/ui/modal/package-info-sections/release-notes.js +161 -0
  35. package/dist/ui/modal/package-info-sections/sections.js +150 -0
  36. package/dist/ui/modal/package-info-sections/text.js +75 -0
  37. package/dist/ui/modal/package-info-sections.js +15 -368
  38. package/dist/ui/modal/package-info.js +1 -1
  39. package/dist/ui/renderer/help-modal.js +75 -0
  40. package/dist/ui/renderer/index.js +2 -5
  41. package/dist/ui/renderer/package-list/interface.js +184 -0
  42. package/dist/ui/renderer/package-list/rows.js +172 -0
  43. package/dist/ui/renderer/package-list.js +15 -462
  44. package/dist/ui/session/action-dispatcher.js +233 -0
  45. package/dist/ui/session/index.js +13 -0
  46. package/dist/ui/session/interactive-session.js +280 -0
  47. package/dist/ui/session/selection-state-builder.js +144 -0
  48. package/dist/ui/state/filter-manager.js +17 -6
  49. package/dist/ui/state/modal-manager.js +35 -0
  50. package/dist/ui/state/navigation-manager.js +33 -4
  51. package/dist/ui/state/state-manager.js +68 -3
  52. package/dist/ui/state/theme-manager.js +1 -0
  53. package/dist/ui/themes-colors.js +8 -0
  54. package/dist/ui/themes.js +11 -19
  55. package/dist/ui/utils/cursor.js +3 -4
  56. package/dist/ui/utils/index.js +6 -1
  57. package/dist/ui/utils/text.js +3 -2
  58. package/dist/ui/utils/version.js +60 -86
  59. package/dist/utils/config.js +13 -1
  60. package/dist/utils/filesystem/io.js +87 -0
  61. package/dist/utils/filesystem/paths.js +19 -0
  62. package/dist/utils/filesystem/scan.js +205 -0
  63. package/dist/utils/filesystem.js +17 -335
  64. package/dist/utils/version.js +31 -1
  65. package/package.json +10 -9
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildReleaseNotesSections = buildReleaseNotesSections;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const themes_colors_1 = require("../../themes-colors");
9
+ const text_1 = require("./text");
10
+ function formatReleaseNotesMarkdown(markdown, width, repositoryUrl) {
11
+ const lines = [];
12
+ const rawLines = markdown.split('\n');
13
+ let prevBlank = false;
14
+ for (const rawLine of rawLines) {
15
+ const trimmed = rawLine.trim();
16
+ if (trimmed === '') {
17
+ if (!prevBlank && lines.length > 0) {
18
+ lines.push('');
19
+ prevBlank = true;
20
+ }
21
+ continue;
22
+ }
23
+ prevBlank = false;
24
+ if (/^```/.test(trimmed) || /^---+$/.test(trimmed)) {
25
+ continue;
26
+ }
27
+ const cleaned = (0, text_1.sanitizeMarkdownText)(trimmed);
28
+ if (!cleaned) {
29
+ continue;
30
+ }
31
+ const quoteMatch = trimmed.match(/^>\s*(.+)/);
32
+ if (quoteMatch) {
33
+ const quoteBody = (0, text_1.linkifyMarkdownText)((0, text_1.sanitizeMarkdownText)(quoteMatch[1]), repositoryUrl);
34
+ const admonitionMatch = quoteBody.match(/^\[!([A-Z]+)\]$/i);
35
+ if (admonitionMatch) {
36
+ const label = `${admonitionMatch[1][0]}${admonitionMatch[1].slice(1).toLowerCase()}`;
37
+ if (lines.length > 0 && lines[lines.length - 1] !== '') {
38
+ lines.push('');
39
+ }
40
+ lines.push(chalk_1.default.blue.bold(` ${label}`));
41
+ }
42
+ else {
43
+ (0, text_1.pushWrappedLines)(lines, quoteBody, width, ' ', ' ', chalk_1.default.gray);
44
+ }
45
+ continue;
46
+ }
47
+ const headerMatch = cleaned.match(/^(#{1,6})\s+(.+)/);
48
+ if (headerMatch) {
49
+ const title = (0, text_1.sanitizeMarkdownText)(headerMatch[2]);
50
+ const lower = title.toLowerCase();
51
+ let style = chalk_1.default.white.bold;
52
+ if (lower.includes('breaking')) {
53
+ style = chalk_1.default.red.bold;
54
+ }
55
+ else if (lower.includes('feature') ||
56
+ lower.includes('added') ||
57
+ lower.includes('improvement')) {
58
+ style = chalk_1.default.green.bold;
59
+ }
60
+ else if (lower.includes('fix') || lower.includes('bug')) {
61
+ style = chalk_1.default.yellow.bold;
62
+ }
63
+ else if (lower.includes('deprecat')) {
64
+ style = chalk_1.default.magenta.bold;
65
+ }
66
+ if (lines.length > 0 && lines[lines.length - 1] !== '') {
67
+ lines.push('');
68
+ }
69
+ lines.push(style(` ${title}`));
70
+ continue;
71
+ }
72
+ const bulletMatch = cleaned.match(/^(\s*)[*-]\s+(.+)/);
73
+ if (bulletMatch) {
74
+ const indentLevel = Math.min(2, Math.floor(bulletMatch[1].length / 2));
75
+ const prefix = ` ${' '.repeat(indentLevel)}${chalk_1.default.gray('•')} `;
76
+ const restPrefix = ` ${' '.repeat(indentLevel + 1)}`;
77
+ const style = /breaking/i.test(bulletMatch[2]) ? chalk_1.default.red : undefined;
78
+ (0, text_1.pushWrappedLines)(lines, (0, text_1.linkifyMarkdownText)((0, text_1.sanitizeMarkdownText)(bulletMatch[2]), repositoryUrl), width, prefix, restPrefix, style);
79
+ continue;
80
+ }
81
+ const orderedMatch = cleaned.match(/^(\s*)(\d+)\.\s+(.+)/);
82
+ if (orderedMatch) {
83
+ const indentLevel = Math.min(2, Math.floor(orderedMatch[1].length / 2));
84
+ const marker = `${orderedMatch[2]}.`;
85
+ const prefix = ` ${' '.repeat(indentLevel)}${marker} `;
86
+ const restPrefix = ` ${' '.repeat(indentLevel)}${' '.repeat(marker.length + 1)}`;
87
+ (0, text_1.pushWrappedLines)(lines, (0, text_1.linkifyMarkdownText)((0, text_1.sanitizeMarkdownText)(orderedMatch[3]), repositoryUrl), width, prefix, restPrefix);
88
+ continue;
89
+ }
90
+ const style = (0, text_1.isLowSignalTrailerLine)(cleaned) ? chalk_1.default.gray : undefined;
91
+ (0, text_1.pushWrappedLines)(lines, (0, text_1.linkifyMarkdownText)(cleaned, repositoryUrl), width, ' ', ' ', style);
92
+ }
93
+ while (lines.length > 0 && lines[lines.length - 1] === '') {
94
+ lines.pop();
95
+ }
96
+ return lines;
97
+ }
98
+ function buildReleaseNotesSections(state, modalWidth) {
99
+ const sections = [];
100
+ if (!state.releaseNotesVersions || state.releaseNotesVersions.length === 0) {
101
+ return sections;
102
+ }
103
+ const loaded = state.releaseNotesLoaded;
104
+ const viewIndex = state.releaseNotesViewIndex ?? 0;
105
+ const totalVersions = state.releaseNotesVersions.length;
106
+ const currentVersion = state.releaseNotesVersions[viewIndex];
107
+ if (!currentVersion)
108
+ return sections;
109
+ if (state.releaseNotesLoadingVersion === currentVersion) {
110
+ sections.push({
111
+ key: 'release-loading',
112
+ rows: [chalk_1.default.gray(`Loading release notes for v${currentVersion}...`)],
113
+ behavior: 'status',
114
+ });
115
+ return sections;
116
+ }
117
+ if (!loaded || !loaded.has(currentVersion)) {
118
+ sections.push({
119
+ key: 'release-pending',
120
+ rows: [chalk_1.default.gray(`Press ←/→ to load release notes for v${currentVersion}`)],
121
+ behavior: 'status',
122
+ });
123
+ return sections;
124
+ }
125
+ const content = loaded.get(currentVersion);
126
+ if (!content) {
127
+ sections.push({
128
+ key: 'release-none',
129
+ rows: [chalk_1.default.gray.italic(`No release notes found for v${currentVersion}`)],
130
+ behavior: 'status',
131
+ });
132
+ }
133
+ else {
134
+ const versionHeader = (0, themes_colors_1.getThemeColor)('primary')(`Version ${currentVersion}`);
135
+ const navHint = totalVersions > 1 ? chalk_1.default.gray(` (${viewIndex + 1}/${totalVersions})`) : '';
136
+ const rows = [chalk_1.default.bold(versionHeader) + navHint];
137
+ const formatted = formatReleaseNotesMarkdown(content, modalWidth - 4, state.repository);
138
+ rows.push(...formatted);
139
+ sections.push({
140
+ key: `release-${currentVersion}`,
141
+ rows,
142
+ behavior: 'body',
143
+ });
144
+ }
145
+ const canGoNewer = viewIndex > 0;
146
+ const canGoOlder = viewIndex < totalVersions - 1;
147
+ if (canGoNewer || canGoOlder) {
148
+ const hints = [];
149
+ if (canGoNewer)
150
+ hints.push('← newer');
151
+ if (canGoOlder)
152
+ hints.push('→ older');
153
+ sections.push({
154
+ key: 'release-nav',
155
+ rows: [chalk_1.default.gray(hints.join(' · '))],
156
+ behavior: 'status',
157
+ });
158
+ }
159
+ return sections;
160
+ }
161
+ //# sourceMappingURL=release-notes.js.map
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildUsedBySections = buildUsedBySections;
7
+ exports.buildPackageInfoSections = buildPackageInfoSections;
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const themes_colors_1 = require("../../themes-colors");
11
+ const vulnerability_1 = require("../../presenters/vulnerability");
12
+ const utils_1 = require("../../utils");
13
+ const release_notes_1 = require("./release-notes");
14
+ function formatNumber(num) {
15
+ if (!num)
16
+ return 'N/A';
17
+ if (num >= 1000000)
18
+ return (num / 1000000).toFixed(1) + 'M';
19
+ if (num >= 1000)
20
+ return (num / 1000).toFixed(1) + 'K';
21
+ return num.toString();
22
+ }
23
+ function getUsedByPaths(state) {
24
+ return state.packageJsonPaths ?? [state.packageJsonPath];
25
+ }
26
+ function buildTabBarSuffix(activeTab, usedByCount) {
27
+ const styleFor = (tab) => tab === activeTab ? chalk_1.default.bold.underline : chalk_1.default.gray;
28
+ const usedByLabel = `Used by${usedByCount > 0 ? ` (${usedByCount})` : ''}`;
29
+ return (' ' +
30
+ chalk_1.default.gray('[ ') +
31
+ styleFor('info')('Info') +
32
+ chalk_1.default.gray(' │ ') +
33
+ styleFor('usedBy')(usedByLabel) +
34
+ chalk_1.default.gray(' ]'));
35
+ }
36
+ function buildUsedBySections(state, modalWidth) {
37
+ const paths = getUsedByPaths(state);
38
+ const cwd = process.cwd();
39
+ const contentWidth = Math.max(10, modalWidth - 4);
40
+ const formatRelative = (absolutePath) => {
41
+ const display = node_path_1.default.relative(cwd, absolutePath) || absolutePath;
42
+ return (0, utils_1.truncatePlainText)(display, contentWidth);
43
+ };
44
+ return [
45
+ {
46
+ key: 'used-by-summary',
47
+ rows: [
48
+ chalk_1.default.bold(`${paths.length} package.json file${paths.length === 1 ? '' : 's'} depend on ${state.name}`),
49
+ chalk_1.default.gray(`Type: ${state.type}`),
50
+ ],
51
+ required: true,
52
+ behavior: 'pinned',
53
+ },
54
+ {
55
+ key: 'used-by-list',
56
+ rows: paths.map((p) => `${chalk_1.default.gray('•')} ${formatRelative(p)}`),
57
+ behavior: 'body',
58
+ },
59
+ ];
60
+ }
61
+ function buildPackageInfoSections(state, modalWidth, activeTab) {
62
+ const title = chalk_1.default.bold('Package: ') +
63
+ (0, themes_colors_1.getThemeColor)('packageName')(state.name) +
64
+ buildTabBarSuffix(activeTab, getUsedByPaths(state).length);
65
+ const authorLicense = chalk_1.default.gray(`${state.author || 'Unknown'} • ${state.license || 'MIT'}`);
66
+ const currentVersion = chalk_1.default.yellow(state.currentVersionSpecifier);
67
+ const targetVersion = chalk_1.default.green(state.selectedOption === 'range' ? state.rangeVersion : state.latestVersion);
68
+ const sections = [
69
+ {
70
+ key: 'header',
71
+ rows: [title, authorLicense],
72
+ required: true,
73
+ behavior: 'pinned',
74
+ },
75
+ ];
76
+ if (activeTab === 'usedBy') {
77
+ sections.push(...buildUsedBySections(state, modalWidth));
78
+ return sections;
79
+ }
80
+ sections.push({
81
+ key: 'meta',
82
+ rows: [
83
+ `Current: ${currentVersion} Target: ${targetVersion}`,
84
+ ...(state.weeklyDownloads !== undefined
85
+ ? [(0, themes_colors_1.getThemeColor)('primary')(`Downloads/week: ${formatNumber(state.weeklyDownloads)}`)]
86
+ : []),
87
+ ],
88
+ required: true,
89
+ behavior: 'pinned',
90
+ });
91
+ if (state.homepage) {
92
+ sections.push({
93
+ key: 'homepage',
94
+ rows: [
95
+ `Homepage: ${chalk_1.default.underline((0, themes_colors_1.getThemeColor)('primary')((0, utils_1.truncatePlainText)(state.homepage, modalWidth - 14)))}`,
96
+ ],
97
+ behavior: 'pinned',
98
+ });
99
+ }
100
+ if (state.description) {
101
+ sections.push({
102
+ key: 'description',
103
+ rows: (0, utils_1.wrapPlainText)(state.description, modalWidth - 4)
104
+ .slice(0, 4)
105
+ .map((line, index, rows) => index === rows.length - 1 && rows.length === 4
106
+ ? (0, utils_1.truncatePlainText)(line, modalWidth - 4)
107
+ : line),
108
+ behavior: 'pinned',
109
+ });
110
+ }
111
+ if (state.vulnerability && state.vulnerability.count > 0) {
112
+ const representative = (0, vulnerability_1.selectRepresentativeAdvisory)(state.vulnerability);
113
+ const severityColor = (0, vulnerability_1.getVulnerabilitySeverityColor)(state.vulnerability.highestSeverity);
114
+ const vulnerabilityRows = [
115
+ chalk_1.default.red.bold(`${state.vulnerability.count} known vulnerabilit${state.vulnerability.count === 1 ? 'y' : 'ies'} (${severityColor(state.vulnerability.highestSeverity.toUpperCase())})`),
116
+ ];
117
+ if (representative) {
118
+ const severityLabel = ` ${severityColor(`[${representative.severity.toUpperCase()}]`)} `;
119
+ const availableTitleWidth = Math.max(0, modalWidth - 4 - (0, utils_1.getVisualLength)(severityLabel));
120
+ vulnerabilityRows.push(`${severityLabel}${(0, utils_1.truncatePlainText)(representative.title, availableTitleWidth)}`);
121
+ }
122
+ const detailsUrl = state.vulnerability.detailsUrl || representative?.url;
123
+ if (detailsUrl) {
124
+ const linkPrefix = ` ${(0, vulnerability_1.getVulnerabilityLinkLabel)(detailsUrl)} `;
125
+ const availableLinkWidth = Math.max(0, modalWidth - 4 - (0, utils_1.getVisualLength)(linkPrefix));
126
+ vulnerabilityRows.push(`${linkPrefix}${chalk_1.default.underline((0, themes_colors_1.getThemeColor)('primary')((0, utils_1.truncatePlainText)(detailsUrl, availableLinkWidth)))}`);
127
+ }
128
+ if (state.vulnerability.count > 1) {
129
+ vulnerabilityRows.push(chalk_1.default.gray(` ... and ${state.vulnerability.count - 1} more`));
130
+ }
131
+ sections.push({
132
+ key: 'vulnerability',
133
+ rows: vulnerabilityRows,
134
+ required: true,
135
+ behavior: 'pinned',
136
+ });
137
+ }
138
+ if (state.repository) {
139
+ sections.push({
140
+ key: 'changelog',
141
+ rows: [
142
+ `Changelog: ${chalk_1.default.underline((0, themes_colors_1.getThemeColor)('primary')((0, utils_1.truncatePlainText)(state.repository, modalWidth - 15)))}`,
143
+ ],
144
+ behavior: 'pinned',
145
+ });
146
+ }
147
+ sections.push(...(0, release_notes_1.buildReleaseNotesSections)(state, modalWidth));
148
+ return sections;
149
+ }
150
+ //# sourceMappingURL=sections.js.map
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatTerminalLink = formatTerminalLink;
4
+ exports.getRepositoryBaseUrl = getRepositoryBaseUrl;
5
+ exports.sanitizeMarkdownText = sanitizeMarkdownText;
6
+ exports.linkifyContributorMentions = linkifyContributorMentions;
7
+ exports.linkifyRepositoryReferences = linkifyRepositoryReferences;
8
+ exports.linkifyMarkdownText = linkifyMarkdownText;
9
+ exports.pushWrappedLines = pushWrappedLines;
10
+ exports.isLowSignalTrailerLine = isLowSignalTrailerLine;
11
+ const utils_1 = require("../../utils");
12
+ function formatTerminalLink(label, url) {
13
+ return `]8;;${url}${label}]8;;`;
14
+ }
15
+ function getRepositoryBaseUrl(repositoryUrl) {
16
+ if (!repositoryUrl) {
17
+ return null;
18
+ }
19
+ return repositoryUrl.replace(/\/releases\/?$/, '');
20
+ }
21
+ function sanitizeMarkdownText(text) {
22
+ return text
23
+ .replace(/<[^>]+>/g, '')
24
+ .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1')
25
+ .replace(/[`*_~]/g, '')
26
+ .replace(/\s+/g, ' ')
27
+ .trim();
28
+ }
29
+ function linkifyContributorMentions(text) {
30
+ return text.replace(/(^|[\s(])@([a-zA-Z0-9-]+)/g, (_match, prefix, username) => {
31
+ return `${prefix}${formatTerminalLink(`@${username}`, `https://github.com/${username}`)}`;
32
+ });
33
+ }
34
+ function linkifyRepositoryReferences(text, repositoryUrl) {
35
+ const repoBaseUrl = getRepositoryBaseUrl(repositoryUrl);
36
+ if (!repoBaseUrl || !repoBaseUrl.includes('github.com')) {
37
+ return text;
38
+ }
39
+ return text
40
+ .replace(/(^|[\s(])#(\d+)\b/g, (_match, prefix, number) => {
41
+ return `${prefix}${formatTerminalLink(`#${number}`, `${repoBaseUrl}/pull/${number}`)}`;
42
+ })
43
+ .replace(/(^|[\s(])([0-9a-f]{7,40})\b/gi, (_match, prefix, hash) => {
44
+ return `${prefix}${formatTerminalLink(hash, `${repoBaseUrl}/commit/${hash}`)}`;
45
+ });
46
+ }
47
+ function linkifyMarkdownText(text, repositoryUrl) {
48
+ return linkifyRepositoryReferences(linkifyContributorMentions(text), repositoryUrl);
49
+ }
50
+ function pushWrappedLines(lines, text, width, firstPrefix, restPrefix = firstPrefix, style) {
51
+ const firstWidth = Math.max(1, width - (0, utils_1.getVisualLength)(firstPrefix));
52
+ const restWidth = Math.max(1, width - (0, utils_1.getVisualLength)(restPrefix));
53
+ const segments = (0, utils_1.wrapPlainText)(text, firstWidth);
54
+ if (segments.length === 0) {
55
+ lines.push(firstPrefix.trimEnd());
56
+ return;
57
+ }
58
+ lines.push(firstPrefix + (style ? style(segments[0]) : segments[0]));
59
+ for (let i = 1; i < segments.length; i++) {
60
+ const wrappedSegments = (0, utils_1.wrapPlainText)(segments[i], restWidth);
61
+ for (const segment of wrappedSegments) {
62
+ lines.push(restPrefix + (style ? style(segment) : segment));
63
+ }
64
+ }
65
+ }
66
+ function isLowSignalTrailerLine(text) {
67
+ const normalized = text.toLowerCase();
68
+ return (normalized.startsWith('compare') ||
69
+ normalized.startsWith('full changelog') ||
70
+ normalized.startsWith('see full changelog') ||
71
+ normalized.startsWith('release notes') ||
72
+ normalized.includes('/compare/') ||
73
+ /^\w+: https?:\/\//.test(normalized));
74
+ }
75
+ //# sourceMappingURL=text.js.map