inup 1.5.5 → 1.6.0

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 (75) hide show
  1. package/README.md +53 -10
  2. package/dist/cli.js +53 -31
  3. package/dist/config/constants.js +4 -6
  4. package/dist/config/package-meta.js +10 -0
  5. package/dist/config/project-config.js +11 -1
  6. package/dist/core/package-detector.js +37 -5
  7. package/dist/core/upgrade-runner.js +8 -10
  8. package/dist/core/upgrader.js +15 -11
  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 +7 -23
  12. package/dist/features/changelog/services/release-notes-service.js +4 -29
  13. package/dist/features/debug/services/performance-tracker.js +6 -8
  14. package/dist/features/headless/headless-runner.js +53 -0
  15. package/dist/features/headless/index.js +27 -0
  16. package/dist/features/headless/report.js +64 -0
  17. package/dist/features/headless/types.js +6 -0
  18. package/dist/features/headless/vulnerability-audit.js +106 -0
  19. package/dist/index.js +1 -2
  20. package/dist/interactive-ui.js +15 -606
  21. package/dist/services/background-audit.js +3 -5
  22. package/dist/services/cache-manager.js +5 -7
  23. package/dist/services/http/inflight.js +22 -0
  24. package/dist/services/http/retry.js +30 -0
  25. package/dist/services/index.js +0 -1
  26. package/dist/services/npm-registry.js +20 -97
  27. package/dist/services/package-manager-detector.js +6 -3
  28. package/dist/services/persistent-cache.js +8 -13
  29. package/dist/types/domain.js +3 -0
  30. package/dist/types/streaming.js +3 -0
  31. package/dist/types/ui.js +3 -0
  32. package/dist/types.js +17 -0
  33. package/dist/ui/controllers/package-info-modal-controller.js +22 -31
  34. package/dist/ui/controllers/vulnerability-audit-controller.js +17 -8
  35. package/dist/ui/index.js +3 -0
  36. package/dist/ui/input-handler.js +58 -75
  37. package/dist/ui/keymap.js +208 -0
  38. package/dist/ui/modal/package-info-sections/release-notes.js +161 -0
  39. package/dist/ui/modal/package-info-sections/sections.js +174 -0
  40. package/dist/ui/modal/package-info-sections/text.js +75 -0
  41. package/dist/ui/modal/package-info-sections.js +15 -369
  42. package/dist/ui/modal/package-info.js +1 -1
  43. package/dist/ui/presenters/health.js +24 -0
  44. package/dist/ui/renderer/help-modal.js +75 -0
  45. package/dist/ui/renderer/index.js +2 -5
  46. package/dist/ui/renderer/package-list/interface.js +184 -0
  47. package/dist/ui/renderer/package-list/rows.js +177 -0
  48. package/dist/ui/renderer/package-list.js +15 -455
  49. package/dist/ui/session/action-dispatcher.js +233 -0
  50. package/dist/ui/session/index.js +13 -0
  51. package/dist/ui/session/interactive-session.js +280 -0
  52. package/dist/ui/session/selection-state-builder.js +149 -0
  53. package/dist/ui/state/filter-manager.js +17 -6
  54. package/dist/ui/state/modal-manager.js +35 -0
  55. package/dist/ui/state/navigation-manager.js +33 -4
  56. package/dist/ui/state/state-manager.js +68 -3
  57. package/dist/ui/state/theme-manager.js +1 -0
  58. package/dist/ui/themes-colors.js +16 -4
  59. package/dist/ui/themes.js +11 -19
  60. package/dist/ui/utils/cursor.js +12 -7
  61. package/dist/ui/utils/index.js +6 -1
  62. package/dist/ui/utils/text.js +3 -2
  63. package/dist/ui/utils/version.js +60 -86
  64. package/dist/utils/color.js +38 -0
  65. package/dist/utils/config.js +13 -1
  66. package/dist/utils/engines.js +63 -0
  67. package/dist/utils/filesystem/io.js +103 -0
  68. package/dist/utils/filesystem/paths.js +19 -0
  69. package/dist/utils/filesystem/scan.js +280 -0
  70. package/dist/utils/filesystem.js +17 -335
  71. package/dist/utils/index.js +3 -0
  72. package/dist/utils/manifest.js +35 -0
  73. package/dist/utils/version.js +38 -1
  74. package/package.json +8 -7
  75. package/dist/services/jsdelivr-registry.js +0 -395
@@ -3,15 +3,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FilterManager = void 0;
4
4
  const vulnerability_1 = require("../presenters/vulnerability");
5
5
  class FilterManager {
6
- constructor() {
6
+ state;
7
+ constructor(initial) {
7
8
  this.state = {
8
9
  filterMode: false,
9
10
  filterQuery: '',
10
- showDependencies: true,
11
- showDevDependencies: true,
12
- showPeerDependencies: true,
13
- showOptionalDependencies: true,
14
- showOnlyVulnerable: false,
11
+ showDependencies: initial?.showDependencies ?? true,
12
+ showDevDependencies: initial?.showDevDependencies ?? true,
13
+ showPeerDependencies: initial?.showPeerDependencies ?? true,
14
+ showOptionalDependencies: initial?.showOptionalDependencies ?? true,
15
+ showOnlyVulnerable: initial?.showOnlyVulnerable ?? false,
16
+ };
17
+ }
18
+ /** Snapshot of the persistable filter toggles (no transient search state). */
19
+ getPersistableState() {
20
+ return {
21
+ showDependencies: this.state.showDependencies,
22
+ showDevDependencies: this.state.showDevDependencies,
23
+ showPeerDependencies: this.state.showPeerDependencies,
24
+ showOptionalDependencies: this.state.showOptionalDependencies,
25
+ showOnlyVulnerable: this.state.showOnlyVulnerable,
15
26
  };
16
27
  }
17
28
  getState() {
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ModalManager = void 0;
4
4
  class ModalManager {
5
+ state;
5
6
  constructor() {
6
7
  this.state = {
7
8
  showInfoModal: false,
@@ -12,6 +13,8 @@ class ModalManager {
12
13
  infoModalTab: 'info',
13
14
  showDebugModal: false,
14
15
  debugModalScrollOffset: 0,
16
+ showHelpModal: false,
17
+ helpModalScrollOffset: 0,
15
18
  };
16
19
  }
17
20
  getInfoModalTab() {
@@ -31,6 +34,38 @@ class ModalManager {
31
34
  this.state.showDebugModal = !this.state.showDebugModal;
32
35
  this.state.debugModalScrollOffset = 0;
33
36
  }
37
+ isHelpModalOpen() {
38
+ return this.state.showHelpModal;
39
+ }
40
+ toggleHelpModal() {
41
+ this.state.showHelpModal = !this.state.showHelpModal;
42
+ this.state.helpModalScrollOffset = 0;
43
+ }
44
+ closeHelpModal() {
45
+ this.state.showHelpModal = false;
46
+ this.state.helpModalScrollOffset = 0;
47
+ }
48
+ scrollHelpModalUp() {
49
+ if (this.state.helpModalScrollOffset > 0) {
50
+ this.state.helpModalScrollOffset--;
51
+ return true;
52
+ }
53
+ return false;
54
+ }
55
+ scrollHelpModalDown(maxOffset) {
56
+ if (this.state.helpModalScrollOffset < maxOffset) {
57
+ this.state.helpModalScrollOffset++;
58
+ return true;
59
+ }
60
+ return false;
61
+ }
62
+ clampHelpModalScrollOffset(maxOffset) {
63
+ const next = Math.max(0, Math.min(this.state.helpModalScrollOffset, maxOffset));
64
+ if (next === this.state.helpModalScrollOffset)
65
+ return false;
66
+ this.state.helpModalScrollOffset = next;
67
+ return true;
68
+ }
34
69
  closeDebugModal() {
35
70
  this.state.showDebugModal = false;
36
71
  this.state.debugModalScrollOffset = 0;
@@ -2,9 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NavigationManager = void 0;
4
4
  class NavigationManager {
5
+ state;
6
+ renderableItems = [];
7
+ maxVisibleItems;
5
8
  constructor(initialRow = 0, maxVisibleItems = 19) {
6
- this.renderableItems = [];
7
- this.headerLines = 5; // title (with label) + empty + 1 instruction line + status + empty
8
9
  this.state = {
9
10
  currentRow: initialRow,
10
11
  previousRow: -1,
@@ -65,8 +66,6 @@ class NavigationManager {
65
66
  return currentPackageIndex >= totalPackages - 1 ? 0 : currentPackageIndex + 1;
66
67
  }
67
68
  }
68
- // Find current visual index
69
- const currentVisualIndex = this.packageIndexToVisualIndex(currentPackageIndex);
70
69
  // Get all package items with their visual indices
71
70
  const packageItems = [];
72
71
  for (let i = 0; i < this.renderableItems.length; i++) {
@@ -105,6 +104,36 @@ class NavigationManager {
105
104
  this.state.currentRow = this.findNextPackageIndex(this.state.currentRow, 'down', totalItems);
106
105
  this.ensureVisible(this.state.currentRow, totalItems);
107
106
  }
107
+ navigateTop(totalItems) {
108
+ if (totalItems === 0)
109
+ return;
110
+ this.state.previousRow = this.state.currentRow;
111
+ this.state.currentRow = this.firstPackageIndex();
112
+ this.ensureVisible(this.state.currentRow, totalItems);
113
+ }
114
+ navigateBottom(totalItems) {
115
+ if (totalItems === 0)
116
+ return;
117
+ this.state.previousRow = this.state.currentRow;
118
+ this.state.currentRow = this.lastPackageIndex(totalItems);
119
+ this.ensureVisible(this.state.currentRow, totalItems);
120
+ }
121
+ firstPackageIndex() {
122
+ if (this.renderableItems.length === 0)
123
+ return 0;
124
+ const first = this.renderableItems.find((item) => item.type === 'package');
125
+ return first ? first.originalIndex : 0;
126
+ }
127
+ lastPackageIndex(totalPackages) {
128
+ if (this.renderableItems.length === 0)
129
+ return totalPackages - 1;
130
+ for (let i = this.renderableItems.length - 1; i >= 0; i--) {
131
+ const item = this.renderableItems[i];
132
+ if (item.type === 'package')
133
+ return item.originalIndex;
134
+ }
135
+ return totalPackages - 1;
136
+ }
108
137
  ensureVisible(packageIndex, totalPackages) {
109
138
  // Convert package index to visual index for scrolling
110
139
  const visualIndex = this.packageIndexToVisualIndex(packageIndex);
@@ -6,12 +6,19 @@ const modal_manager_1 = require("./modal-manager");
6
6
  const filter_manager_1 = require("./filter-manager");
7
7
  const theme_manager_1 = require("./theme-manager");
8
8
  class StateManager {
9
- constructor(initialRow = 0, terminalHeight = 24) {
10
- this.headerLines = 5; // title (with label) + empty + 1 instruction line + status + empty
9
+ navigationManager;
10
+ modalManager;
11
+ filterManager;
12
+ themeManager;
13
+ displayState;
14
+ renderState;
15
+ notice = null;
16
+ headerLines = 5; // title (with label) + empty + 1 instruction line + status + empty
17
+ constructor(initialRow = 0, terminalHeight = 24, persistedFilters) {
11
18
  const maxVisibleItems = Math.max(5, terminalHeight - this.headerLines - 2);
12
19
  this.navigationManager = new navigation_manager_1.NavigationManager(initialRow, maxVisibleItems);
13
20
  this.modalManager = new modal_manager_1.ModalManager();
14
- this.filterManager = new filter_manager_1.FilterManager();
21
+ this.filterManager = new filter_manager_1.FilterManager(persistedFilters);
15
22
  this.themeManager = new theme_manager_1.ThemeManager();
16
23
  this.displayState = {
17
24
  maxVisibleItems,
@@ -46,12 +53,26 @@ class StateManager {
46
53
  infoModalTab: modalState.infoModalTab,
47
54
  showDebugModal: modalState.showDebugModal,
48
55
  debugModalScrollOffset: modalState.debugModalScrollOffset,
56
+ showHelpModal: modalState.showHelpModal,
57
+ helpModalScrollOffset: modalState.helpModalScrollOffset,
49
58
  filterMode: filterState.filterMode,
50
59
  filterQuery: filterState.filterQuery,
51
60
  showThemeModal: themeState.showThemeModal,
52
61
  currentTheme: themeState.currentTheme,
62
+ notice: this.notice,
53
63
  };
54
64
  }
65
+ // Transient status hint shown once (e.g. "nothing selected"); cleared by the
66
+ // dispatcher on the next action so it never lingers.
67
+ setNotice(message) {
68
+ this.notice = message;
69
+ }
70
+ clearNotice() {
71
+ this.notice = null;
72
+ }
73
+ getNotice() {
74
+ return this.notice;
75
+ }
55
76
  setRenderableItems(items) {
56
77
  this.renderState.renderableItems = items;
57
78
  this.navigationManager.setRenderableItems(items);
@@ -63,6 +84,12 @@ class StateManager {
63
84
  navigateDown(totalItems) {
64
85
  this.navigationManager.navigateDown(totalItems);
65
86
  }
87
+ navigateTop(totalItems) {
88
+ this.navigationManager.navigateTop(totalItems);
89
+ }
90
+ navigateBottom(totalItems) {
91
+ this.navigationManager.navigateBottom(totalItems);
92
+ }
66
93
  packageIndexToVisualIndex(packageIndex) {
67
94
  return this.navigationManager.packageIndexToVisualIndex(packageIndex);
68
95
  }
@@ -152,6 +179,24 @@ class StateManager {
152
179
  }
153
180
  });
154
181
  }
182
+ // Toggle the current row: clear it if selected, otherwise pick the best
183
+ // available update (latest preferred, then range).
184
+ toggleSelection(states) {
185
+ if (states.length === 0)
186
+ return;
187
+ const currentState = states[this.navigationManager.getCurrentRow()];
188
+ if (!currentState || currentState.loadState !== 'ready')
189
+ return;
190
+ if (currentState.selectedOption !== 'none') {
191
+ currentState.selectedOption = 'none';
192
+ }
193
+ else if (currentState.hasMajorUpdate) {
194
+ currentState.selectedOption = 'latest';
195
+ }
196
+ else if (currentState.hasRangeUpdate) {
197
+ currentState.selectedOption = 'range';
198
+ }
199
+ }
155
200
  // Modal delegation
156
201
  toggleInfoModal() {
157
202
  const currentRow = this.navigationManager.getCurrentRow();
@@ -206,6 +251,23 @@ class StateManager {
206
251
  closeDebugModal() {
207
252
  this.modalManager.closeDebugModal();
208
253
  }
254
+ toggleHelpModal() {
255
+ this.modalManager.toggleHelpModal();
256
+ this.renderState.forceFullRender = true;
257
+ }
258
+ closeHelpModal() {
259
+ this.modalManager.closeHelpModal();
260
+ this.renderState.forceFullRender = true;
261
+ }
262
+ scrollHelpModalUp() {
263
+ return this.modalManager.scrollHelpModalUp();
264
+ }
265
+ scrollHelpModalDown(maxOffset) {
266
+ return this.modalManager.scrollHelpModalDown(maxOffset);
267
+ }
268
+ clampHelpModalScrollOffset(maxOffset) {
269
+ return this.modalManager.clampHelpModalScrollOffset(maxOffset);
270
+ }
209
271
  scrollDebugModalUp() {
210
272
  return this.modalManager.scrollDebugModalUp();
211
273
  }
@@ -264,6 +326,9 @@ class StateManager {
264
326
  getActiveFilterLabel() {
265
327
  return this.filterManager.getActiveFilterLabel();
266
328
  }
329
+ getFilterSnapshot() {
330
+ return this.filterManager.getPersistableState();
331
+ }
267
332
  // Display and render state management
268
333
  updateTerminalHeight(newHeight) {
269
334
  const newMaxVisibleItems = Math.max(5, newHeight - this.headerLines - 2);
@@ -8,6 +8,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
+ state;
11
12
  constructor() {
12
13
  // Load saved theme from config, fallback to default
13
14
  const savedTheme = config_1.configManager.getTheme();
@@ -11,6 +11,7 @@ exports.getTerminalResetCode = getTerminalResetCode;
11
11
  exports.coloredInupLogo = coloredInupLogo;
12
12
  const chalk_1 = __importDefault(require("chalk"));
13
13
  const theme_manager_1 = require("./state/theme-manager");
14
+ const config_1 = require("../config");
14
15
  // Centralized theme color definitions - single source of truth
15
16
  const themeColorDefinitions = {
16
17
  default: {
@@ -181,22 +182,33 @@ function hexToRgb(hex) {
181
182
  : { r: 0, g: 0, b: 0 };
182
183
  }
183
184
  /**
184
- * Get ANSI escape code to set terminal background color
185
+ * Get ANSI escape code to set terminal background color.
186
+ *
187
+ * Returns an empty string when color output is disabled (`--no-color`/`NO_COLOR`
188
+ * set `chalk.level` to 0), so the TUI inherits the user's own terminal
189
+ * background instead of painting over it. This escape is raw (not produced by
190
+ * chalk), so it must be gated explicitly.
185
191
  */
186
192
  function getTerminalBgColorCode() {
193
+ if (chalk_1.default.level === 0) {
194
+ return '';
195
+ }
187
196
  const hex = getThemeBgColor();
188
197
  const rgb = hexToRgb(hex);
189
198
  return `\x1b[48;2;${rgb.r};${rgb.g};${rgb.b}m`;
190
199
  }
191
200
  /**
192
- * Get ANSI escape code to reset terminal colors
201
+ * Get ANSI escape code to reset terminal colors. Empty when color is disabled,
202
+ * so a `--no-color` run emits no escape sequences at all.
193
203
  */
194
204
  function getTerminalResetCode() {
195
- return '\x1b[0m';
205
+ return chalk_1.default.level === 0 ? '' : '\x1b[0m';
196
206
  }
197
207
  const BRAND_COLORS = [chalk_1.default.red, chalk_1.default.yellow, chalk_1.default.blue, chalk_1.default.magenta];
198
208
  function coloredInupLogo() {
199
- return BRAND_COLORS.map((color, i) => color.bold('inup'[i])).join('');
209
+ return Array.from(config_1.PACKAGE_NAME)
210
+ .map((ch, i) => BRAND_COLORS[i % BRAND_COLORS.length].bold(ch))
211
+ .join('');
200
212
  }
201
213
  exports.themeColors = {
202
214
  primary: () => getThemeColor('primary'),
package/dist/ui/themes.js CHANGED
@@ -5,26 +5,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.themeNames = exports.defaultTheme = exports.themes = void 0;
7
7
  const chalk_1 = __importDefault(require("chalk"));
8
- const themesMetadata = {
9
- default: 'Default',
10
- catppuccin: 'Catppuccin',
11
- dracula: 'Dracula',
12
- vsc: 'VS Code',
13
- monokai: 'Monokai',
14
- tokyonight: 'Tokyo Night',
15
- onedark: 'One Dark',
16
- gruvbox: 'Gruvbox',
17
- solarized: 'Solarized',
18
- github: 'GitHub',
8
+ exports.themes = {
9
+ default: { name: 'Default', colors: chalk_1.default },
10
+ catppuccin: { name: 'Catppuccin', colors: chalk_1.default },
11
+ dracula: { name: 'Dracula', colors: chalk_1.default },
12
+ vsc: { name: 'VS Code', colors: chalk_1.default },
13
+ monokai: { name: 'Monokai', colors: chalk_1.default },
14
+ tokyonight: { name: 'Tokyo Night', colors: chalk_1.default },
15
+ onedark: { name: 'One Dark', colors: chalk_1.default },
16
+ gruvbox: { name: 'Gruvbox', colors: chalk_1.default },
17
+ solarized: { name: 'Solarized', colors: chalk_1.default },
18
+ github: { name: 'GitHub', colors: chalk_1.default },
19
19
  };
20
- // Theme definitions
21
- exports.themes = Object.entries(themesMetadata).reduce((acc, [key, name]) => {
22
- acc[key] = {
23
- name,
24
- colors: chalk_1.default,
25
- };
26
- return acc;
27
- }, {});
28
20
  exports.defaultTheme = 'default';
29
21
  exports.themeNames = Object.keys(exports.themes);
30
22
  //# sourceMappingURL=themes.js.map
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
- /**
3
- * Cursor and terminal utility functions
4
- */
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ConsoleUtils = exports.CursorUtils = void 0;
3
+ exports.ConsoleUtils = exports.CursorUtils = exports.RAW_SHOW_CURSOR = exports.RAW_EXIT_ALT_SCREEN = void 0;
4
+ exports.RAW_EXIT_ALT_SCREEN = '\x1b[?1049l';
5
+ exports.RAW_SHOW_CURSOR = '\x1b[?25h';
7
6
  exports.CursorUtils = {
8
7
  /**
9
8
  * Switch to the terminal alternate screen buffer.
@@ -68,16 +67,22 @@ exports.ConsoleUtils = {
68
67
  */
69
68
  LINE_WIDTH: 80,
70
69
  /**
71
- * Show a progress message on the current line (overwrites previous content)
70
+ * Show a progress message on the current line (overwrites previous content).
71
+ * Written to stderr so stdout stays clean for --json / piped output, and only
72
+ * when stderr is a TTY — the \r animation is just noise in a redirected log.
72
73
  */
73
74
  showProgress(message) {
74
- process.stdout.write(`\r${' '.repeat(exports.ConsoleUtils.LINE_WIDTH)}\r${message}`);
75
+ if (!process.stderr.isTTY)
76
+ return;
77
+ process.stderr.write(`\r${' '.repeat(exports.ConsoleUtils.LINE_WIDTH)}\r${message}`);
75
78
  },
76
79
  /**
77
80
  * Clear the current progress line
78
81
  */
79
82
  clearProgress() {
80
- process.stdout.write('\r' + ' '.repeat(exports.ConsoleUtils.LINE_WIDTH) + '\r');
83
+ if (!process.stderr.isTTY)
84
+ return;
85
+ process.stderr.write('\r' + ' '.repeat(exports.ConsoleUtils.LINE_WIDTH) + '\r');
81
86
  },
82
87
  };
83
88
  //# sourceMappingURL=cursor.js.map
@@ -1,11 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wrapPlainText = exports.truncatePlainText = exports.stripAnsi = exports.getVisualLength = exports.TerminalInput = exports.ConsoleUtils = exports.CursorUtils = exports.VersionUtils = void 0;
3
+ exports.wrapPlainText = exports.truncatePlainText = exports.stripAnsi = exports.getVisualLength = exports.TerminalInput = exports.RAW_SHOW_CURSOR = exports.RAW_EXIT_ALT_SCREEN = exports.ConsoleUtils = exports.CursorUtils = exports.formatVersionDiff = exports.truncateMiddle = exports.applyVersionPrefix = exports.VersionUtils = void 0;
4
4
  var version_1 = require("./version");
5
5
  Object.defineProperty(exports, "VersionUtils", { enumerable: true, get: function () { return version_1.VersionUtils; } });
6
+ Object.defineProperty(exports, "applyVersionPrefix", { enumerable: true, get: function () { return version_1.applyVersionPrefix; } });
7
+ Object.defineProperty(exports, "truncateMiddle", { enumerable: true, get: function () { return version_1.truncateMiddle; } });
8
+ Object.defineProperty(exports, "formatVersionDiff", { enumerable: true, get: function () { return version_1.formatVersionDiff; } });
6
9
  var cursor_1 = require("./cursor");
7
10
  Object.defineProperty(exports, "CursorUtils", { enumerable: true, get: function () { return cursor_1.CursorUtils; } });
8
11
  Object.defineProperty(exports, "ConsoleUtils", { enumerable: true, get: function () { return cursor_1.ConsoleUtils; } });
12
+ Object.defineProperty(exports, "RAW_EXIT_ALT_SCREEN", { enumerable: true, get: function () { return cursor_1.RAW_EXIT_ALT_SCREEN; } });
13
+ Object.defineProperty(exports, "RAW_SHOW_CURSOR", { enumerable: true, get: function () { return cursor_1.RAW_SHOW_CURSOR; } });
9
14
  var terminal_input_1 = require("./terminal-input");
10
15
  Object.defineProperty(exports, "TerminalInput", { enumerable: true, get: function () { return terminal_input_1.TerminalInput; } });
11
16
  var text_1 = require("./text");
@@ -4,9 +4,10 @@ exports.stripAnsi = stripAnsi;
4
4
  exports.getVisualLength = getVisualLength;
5
5
  exports.truncatePlainText = truncatePlainText;
6
6
  exports.wrapPlainText = wrapPlainText;
7
- const version_1 = require("./version");
7
+ const ANSI_PATTERN = /\[[0-9;?]*[ -/]*[@-~]/g;
8
+ const OSC8_PATTERN = /]8;;.*?(?:|\\)|]8;;(?:|\\)/g;
8
9
  function stripAnsi(text) {
9
- return version_1.VersionUtils.stripAnsi(text);
10
+ return text.replace(OSC8_PATTERN, '').replace(ANSI_PATTERN, '');
10
11
  }
11
12
  function getVisualLength(text) {
12
13
  const cleaned = stripAnsi(text);
@@ -3,100 +3,74 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.VersionUtils = void 0;
6
+ exports.VersionUtils = exports.getVisualLength = exports.stripAnsi = void 0;
7
+ exports.applyVersionPrefix = applyVersionPrefix;
8
+ exports.truncateMiddle = truncateMiddle;
9
+ exports.formatVersionDiff = formatVersionDiff;
7
10
  const chalk_1 = __importDefault(require("chalk"));
8
- /**
9
- * ANSI escape code pattern for stripping terminal colors
10
- */
11
- const ANSI_PATTERN = /\u001b\[[0-9;?]*[ -/]*[@-~]/g;
12
- const OSC8_PATTERN = /\u001b]8;;.*?(?:\u0007|\u001b\\)|\u001b]8;;(?:\u0007|\u001b\\)/g;
13
- class VersionUtils {
14
- static applyVersionPrefix(originalSpecifier, targetVersion) {
15
- // Extract prefix from original specifier (^ or ~)
16
- const prefixMatch = originalSpecifier.match(/^([^\d]+)/);
17
- const prefix = prefixMatch ? prefixMatch[1] : '';
18
- // Return target version with same prefix
19
- return prefix + targetVersion;
20
- }
21
- /**
22
- * Strip ANSI escape codes from a string
23
- */
24
- static stripAnsi(str) {
25
- return str.replace(OSC8_PATTERN, '').replace(ANSI_PATTERN, '');
11
+ const text_1 = require("./text");
12
+ Object.defineProperty(exports, "stripAnsi", { enumerable: true, get: function () { return text_1.stripAnsi; } });
13
+ Object.defineProperty(exports, "getVisualLength", { enumerable: true, get: function () { return text_1.getVisualLength; } });
14
+ function applyVersionPrefix(originalSpecifier, targetVersion) {
15
+ const prefixMatch = originalSpecifier.match(/^([^\d]+)/);
16
+ const prefix = prefixMatch ? prefixMatch[1] : '';
17
+ return prefix + targetVersion;
18
+ }
19
+ function truncateMiddle(str, maxLength) {
20
+ const visualLength = (0, text_1.getVisualLength)(str);
21
+ if (visualLength <= maxLength) {
22
+ return str;
26
23
  }
27
- /**
28
- * Get the visual length of a string (excluding ANSI codes)
29
- */
30
- static getVisualLength(str) {
31
- return VersionUtils.stripAnsi(str).length;
24
+ const ellipsis = '…';
25
+ const availableLength = maxLength - 1;
26
+ const startLength = Math.ceil(availableLength / 2);
27
+ const endLength = Math.floor(availableLength / 2);
28
+ const rawText = (0, text_1.stripAnsi)(str);
29
+ const start = rawText.substring(0, startLength);
30
+ const end = rawText.substring(rawText.length - endLength);
31
+ return start + ellipsis + end;
32
+ }
33
+ function formatVersionDiff(current, target, colorFn) {
34
+ if (current === target) {
35
+ return chalk_1.default.white(target);
32
36
  }
33
- /**
34
- * Truncate text with ellipsis in the middle if it exceeds maxLength
35
- * Preserves ANSI color codes and applies them to the ellipsis
36
- * @param str The text to truncate (may contain ANSI codes)
37
- * @param maxLength The maximum visual length
38
- * @returns Truncated text with middle ellipsis if needed
39
- */
40
- static truncateMiddle(str, maxLength) {
41
- const visualLength = this.getVisualLength(str);
42
- if (visualLength <= maxLength) {
43
- return str;
37
+ const currentParts = current.split('.').map((part) => parseInt(part) || 0);
38
+ const targetParts = target.split('.').map((part) => parseInt(part) || 0);
39
+ let firstDiffSegment = -1;
40
+ const maxLength = Math.max(currentParts.length, targetParts.length);
41
+ for (let i = 0; i < maxLength; i++) {
42
+ const currentPart = currentParts[i] || 0;
43
+ const targetPart = targetParts[i] || 0;
44
+ if (currentPart !== targetPart) {
45
+ firstDiffSegment = i;
46
+ break;
44
47
  }
45
- // Need to truncate with ellipsis in the middle
46
- const ellipsis = '…';
47
- const availableLength = maxLength - 1; // Reserve 1 char for ellipsis
48
- const startLength = Math.ceil(availableLength / 2);
49
- const endLength = Math.floor(availableLength / 2);
50
- // Extract raw text without ANSI codes to calculate positions
51
- const rawText = VersionUtils.stripAnsi(str);
52
- const start = rawText.substring(0, startLength);
53
- const end = rawText.substring(rawText.length - endLength);
54
- return start + ellipsis + end;
55
48
  }
56
- static formatVersionDiff(current, target, colorFn) {
57
- if (current === target) {
58
- return chalk_1.default.white(target);
59
- }
60
- // Parse semantic versions into parts
61
- const currentParts = current.split('.').map((part) => parseInt(part) || 0);
62
- const targetParts = target.split('.').map((part) => parseInt(part) || 0);
63
- // Find the first differing version segment (major, minor, or patch)
64
- let firstDiffSegment = -1;
65
- const maxLength = Math.max(currentParts.length, targetParts.length);
66
- for (let i = 0; i < maxLength; i++) {
67
- const currentPart = currentParts[i] || 0;
68
- const targetPart = targetParts[i] || 0;
69
- if (currentPart !== targetPart) {
70
- firstDiffSegment = i;
71
- break;
72
- }
49
+ if (firstDiffSegment === -1) {
50
+ return chalk_1.default.white(target);
51
+ }
52
+ const result = [];
53
+ for (let i = 0; i < maxLength; i++) {
54
+ const targetPart = targetParts[i] || 0;
55
+ const partStr = targetPart.toString();
56
+ if (i < firstDiffSegment) {
57
+ result.push(partStr);
73
58
  }
74
- if (firstDiffSegment === -1) {
75
- // Versions are identical (shouldn't happen due to guard above, but just in case)
76
- return chalk_1.default.white(target);
59
+ else {
60
+ result.push(colorFn(partStr));
77
61
  }
78
- // Build the result with proper coloring
79
- const result = [];
80
- for (let i = 0; i < maxLength; i++) {
81
- const targetPart = targetParts[i] || 0;
82
- const partStr = targetPart.toString();
83
- if (i < firstDiffSegment) {
84
- // Unchanged segment - keep white
85
- result.push(partStr);
86
- }
87
- else {
88
- // Changed segment or later - apply color
89
- result.push(colorFn(partStr));
90
- }
91
- // Add dot separator if not the last part
92
- if (i < maxLength - 1) {
93
- // Color the dot the same as the following part
94
- const nextPartColor = i + 1 < firstDiffSegment ? chalk_1.default.white : colorFn;
95
- result.push(nextPartColor('.'));
96
- }
62
+ if (i < maxLength - 1) {
63
+ const nextPartColor = i + 1 < firstDiffSegment ? chalk_1.default.white : colorFn;
64
+ result.push(nextPartColor('.'));
97
65
  }
98
- return result.join('');
99
66
  }
67
+ return result.join('');
100
68
  }
101
- exports.VersionUtils = VersionUtils;
69
+ exports.VersionUtils = {
70
+ applyVersionPrefix,
71
+ truncateMiddle,
72
+ formatVersionDiff,
73
+ stripAnsi: text_1.stripAnsi,
74
+ getVisualLength: text_1.getVisualLength,
75
+ };
102
76
  //# sourceMappingURL=version.js.map
@@ -0,0 +1,38 @@
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.shouldDisableColor = shouldDisableColor;
7
+ exports.applyColorSetting = applyColorSetting;
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ /**
10
+ * Decide whether colored output should be disabled.
11
+ *
12
+ * Precedence (highest first):
13
+ * 1. An explicit `--no-color` flag (`colorFlag === false`) always wins.
14
+ * 2. `FORCE_COLOR` keeps colors on.
15
+ * 3. `NO_COLOR` (any non-empty value) disables them — the de-facto standard.
16
+ *
17
+ * chalk v5 already honors the env vars on its own, but the explicit flag does
18
+ * not flow through automatically, so we resolve the final intent here.
19
+ */
20
+ function shouldDisableColor(colorFlag, env = process.env) {
21
+ if (colorFlag === false) {
22
+ return true;
23
+ }
24
+ if (env.FORCE_COLOR) {
25
+ return false;
26
+ }
27
+ return Boolean(env.NO_COLOR);
28
+ }
29
+ /**
30
+ * Apply the resolved color intent to chalk's global level. Call once at startup
31
+ * before anything renders.
32
+ */
33
+ function applyColorSetting(colorFlag, env = process.env) {
34
+ if (shouldDisableColor(colorFlag, env)) {
35
+ chalk_1.default.level = 0;
36
+ }
37
+ }
38
+ //# sourceMappingURL=color.js.map