inup 1.6.6 → 1.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +25 -2
  2. package/dist/{interactive-ui.js → app/interactive-ui.js} +34 -21
  3. package/dist/{core → app}/upgrade-runner.js +18 -22
  4. package/dist/cli.js +19 -18
  5. package/dist/{services → features/audit}/background-audit.js +2 -2
  6. package/dist/features/{headless/vulnerability-audit.js → audit/headless-audit.js} +8 -11
  7. package/dist/features/audit/index.js +36 -0
  8. package/dist/{ui/presenters/vulnerability.js → features/audit/presenter.js} +1 -3
  9. package/dist/{ui/controllers → features/audit}/vulnerability-audit-controller.js +14 -8
  10. package/dist/{services → features/audit}/vulnerability-checker.js +9 -10
  11. package/dist/features/changelog/clients/github-client.js +41 -21
  12. package/dist/features/changelog/clients/npm-registry-client.js +16 -2
  13. package/dist/features/changelog/index.js +1 -1
  14. package/dist/features/changelog/services/package-metadata-service.js +6 -2
  15. package/dist/features/changelog/services/release-notes-service.js +9 -12
  16. package/dist/features/changelog/types.js +3 -0
  17. package/dist/features/debug/index.js +3 -4
  18. package/dist/features/debug/{services/perf-logger.js → perf-logger.js} +15 -15
  19. package/dist/features/debug/types.js +3 -0
  20. package/dist/features/headless/headless-runner.js +32 -19
  21. package/dist/features/headless/index.js +2 -5
  22. package/dist/features/headless/report.js +2 -0
  23. package/dist/features/interactive/controllers/index.js +6 -0
  24. package/dist/{ui → features/interactive}/controllers/package-info-modal-controller.js +3 -3
  25. package/dist/features/interactive/index.js +21 -0
  26. package/dist/{ui → features/interactive}/input-handler.js +6 -6
  27. package/dist/{ui → features/interactive}/modal/index.js +1 -1
  28. package/dist/{ui → features/interactive}/modal/layout.js +5 -5
  29. package/dist/{ui/renderer/package-list.js → features/interactive/modal/package-info-sections/index.js} +3 -3
  30. package/dist/{ui → features/interactive}/modal/package-info-sections/release-notes.js +1 -1
  31. package/dist/{ui → features/interactive}/modal/package-info-sections/sections.js +55 -24
  32. package/dist/{ui → features/interactive}/modal/package-info-sections/text.js +6 -6
  33. package/dist/{ui → features/interactive}/modal/package-info.js +33 -18
  34. package/dist/features/interactive/modal/types.js +3 -0
  35. package/dist/{ui → features/interactive}/presenters/health.js +2 -2
  36. package/dist/{ui → features/interactive}/renderer/confirmation.js +6 -3
  37. package/dist/{ui → features/interactive}/renderer/help-modal.js +3 -3
  38. package/dist/{ui → features/interactive}/renderer/index.js +3 -4
  39. package/dist/{types.js → features/interactive/renderer/package-list/index.js} +3 -4
  40. package/dist/{ui → features/interactive}/renderer/package-list/interface.js +15 -16
  41. package/dist/{ui → features/interactive}/renderer/package-list/rows.js +31 -25
  42. package/dist/features/{debug → interactive}/renderer/performance-modal.js +3 -3
  43. package/dist/{ui/utils/version.js → features/interactive/renderer/version-format.js} +9 -13
  44. package/dist/{ui → features/interactive}/session/action-dispatcher.js +2 -2
  45. package/dist/{ui → features/interactive}/session/index.js +5 -4
  46. package/dist/{ui → features/interactive}/session/interactive-session.js +44 -23
  47. package/dist/{ui → features/interactive}/session/selection-state-builder.js +25 -9
  48. package/dist/{ui → features/interactive}/state/filter-manager.js +3 -3
  49. package/dist/{ui → features/interactive}/state/index.js +7 -7
  50. package/dist/{ui → features/interactive}/state/state-manager.js +10 -8
  51. package/dist/{ui → features/interactive}/state/theme-manager.js +7 -5
  52. package/dist/{ui → features/interactive}/themes-colors.js +3 -1
  53. package/dist/features/upgrade/index.js +8 -0
  54. package/dist/{core → features/upgrade}/package-detector.js +96 -37
  55. package/dist/{core → features/upgrade}/upgrader.js +84 -35
  56. package/dist/index.js +2 -2
  57. package/dist/{config → shared/config}/package-meta.js +1 -1
  58. package/dist/{config → shared/config}/project-config.js +10 -8
  59. package/dist/{utils/config.js → shared/config/user-config.js} +11 -11
  60. package/dist/{utils → shared}/debug-logger.js +9 -9
  61. package/dist/{utils → shared}/exec.js +4 -4
  62. package/dist/{ui/modal/package-info-sections.js → shared/fs/index.js} +4 -3
  63. package/dist/{utils/filesystem → shared/fs}/io.js +3 -4
  64. package/dist/shared/fs/paths.js +19 -0
  65. package/dist/{utils/filesystem → shared/fs}/scan.js +23 -20
  66. package/dist/{utils → shared}/git.js +3 -3
  67. package/dist/{services → shared}/http/etag-store.js +56 -4
  68. package/dist/{services → shared}/http/resizable-semaphore.js +3 -1
  69. package/dist/{utils → shared}/local-env.js +8 -8
  70. package/dist/{services/package-manager-detector.js → shared/package-manager.js} +26 -25
  71. package/dist/shared/pnpm-catalogs.js +138 -0
  72. package/dist/{services → shared/registry}/npm-registry.js +54 -33
  73. package/dist/shared/registry/registry-config.js +76 -0
  74. package/dist/{services → shared/registry}/version-checker.js +25 -26
  75. package/dist/{ui/utils → shared/terminal}/cursor.js +1 -1
  76. package/dist/{ui/utils → shared/terminal}/index.js +5 -7
  77. package/dist/{ui/utils → shared/terminal}/terminal-input.js +5 -0
  78. package/dist/shared/terminal/text.js +48 -0
  79. package/dist/shared/types/index.js +20 -0
  80. package/dist/{utils/version.js → shared/versions.js} +45 -30
  81. package/package.json +21 -8
  82. package/dist/core/index.js +0 -23
  83. package/dist/features/changelog/types/changelog.types.js +0 -3
  84. package/dist/features/debug/types/debug.types.js +0 -3
  85. package/dist/services/index.js +0 -25
  86. package/dist/ui/controllers/index.js +0 -8
  87. package/dist/ui/index.js +0 -27
  88. package/dist/ui/presenters/index.js +0 -11
  89. package/dist/ui/utils/text.js +0 -76
  90. package/dist/utils/filesystem/paths.js +0 -19
  91. package/dist/utils/filesystem.js +0 -20
  92. package/dist/utils/index.js +0 -34
  93. /package/dist/{ui/modal → features/audit}/types.js +0 -0
  94. /package/dist/features/debug/{services/performance-tracker.js → performance-tracker.js} +0 -0
  95. /package/dist/{ui → features/interactive}/keymap.js +0 -0
  96. /package/dist/{ui → features/interactive}/modal/theme-selector.js +0 -0
  97. /package/dist/{ui → features/interactive}/state/modal-manager.js +0 -0
  98. /package/dist/{ui → features/interactive}/state/navigation-manager.js +0 -0
  99. /package/dist/{ui → features/interactive}/themes.js +0 -0
  100. /package/dist/{config → shared/config}/constants.js +0 -0
  101. /package/dist/{config → shared/config}/index.js +0 -0
  102. /package/dist/{utils → shared}/engines.js +0 -0
  103. /package/dist/{services → shared}/http/adaptive-controller.js +0 -0
  104. /package/dist/{services → shared}/http/inflight.js +0 -0
  105. /package/dist/{services → shared}/http/retry.js +0 -0
  106. /package/dist/{utils → shared}/manifest.js +0 -0
  107. /package/dist/{utils → shared/terminal}/color.js +0 -0
  108. /package/dist/{types → shared/types}/domain.js +0 -0
  109. /package/dist/{types → shared/types}/streaming.js +0 -0
  110. /package/dist/{types → shared/types}/ui.js +0 -0
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.loadProjectConfig = loadProjectConfig;
4
4
  exports.isPackageIgnored = isPackageIgnored;
5
- const fs_1 = require("fs");
6
- const path_1 = require("path");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
7
  const package_meta_1 = require("./package-meta");
8
8
  const CONFIG_FILES = [
9
9
  `.${package_meta_1.PACKAGE_NAME}rc`,
@@ -16,12 +16,12 @@ const CONFIG_FILES = [
16
16
  */
17
17
  function loadProjectConfig(cwd) {
18
18
  let currentDir = cwd;
19
- while (currentDir !== '/') {
19
+ while (true) {
20
20
  for (const configFile of CONFIG_FILES) {
21
- const configPath = (0, path_1.join)(currentDir, configFile);
22
- if ((0, fs_1.existsSync)(configPath)) {
21
+ const configPath = (0, node_path_1.join)(currentDir, configFile);
22
+ if ((0, node_fs_1.existsSync)(configPath)) {
23
23
  try {
24
- const content = (0, fs_1.readFileSync)(configPath, 'utf-8');
24
+ const content = (0, node_fs_1.readFileSync)(configPath, 'utf-8');
25
25
  const config = JSON.parse(content);
26
26
  return normalizeConfig(config);
27
27
  }
@@ -31,8 +31,10 @@ function loadProjectConfig(cwd) {
31
31
  }
32
32
  }
33
33
  }
34
- // Move to parent directory
35
- const parentDir = (0, path_1.join)(currentDir, '..');
34
+ // Move to parent directory. join(root, '..') === root at the filesystem
35
+ // root on every platform ('/' on POSIX, 'C:\' on Windows), so this is the
36
+ // single, cross-platform loop terminator.
37
+ const parentDir = (0, node_path_1.join)(currentDir, '..');
36
38
  if (parentDir === currentDir)
37
39
  break;
38
40
  currentDir = parentDir;
@@ -4,29 +4,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.configManager = void 0;
7
- const fs_1 = require("fs");
8
- const path_1 = require("path");
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
9
  const env_paths_1 = __importDefault(require("env-paths"));
10
- const config_1 = require("../config");
10
+ const package_meta_1 = require("./package-meta");
11
11
  class ConfigManager {
12
12
  configDir;
13
13
  configPath;
14
14
  constructor() {
15
15
  // Use env-paths for cross-platform config directory support
16
16
  // Mac/Linux: ~/.config/inup, Windows: %APPDATA%/inup
17
- const paths = (0, env_paths_1.default)(config_1.PACKAGE_NAME);
17
+ const paths = (0, env_paths_1.default)(package_meta_1.PACKAGE_NAME);
18
18
  this.configDir = paths.config;
19
- this.configPath = (0, path_1.join)(this.configDir, 'config.json');
19
+ this.configPath = (0, node_path_1.join)(this.configDir, 'config.json');
20
20
  }
21
21
  ensureConfigDir() {
22
- if (!(0, fs_1.existsSync)(this.configDir)) {
23
- (0, fs_1.mkdirSync)(this.configDir, { recursive: true });
22
+ if (!(0, node_fs_1.existsSync)(this.configDir)) {
23
+ (0, node_fs_1.mkdirSync)(this.configDir, { recursive: true });
24
24
  }
25
25
  }
26
26
  readConfig() {
27
27
  try {
28
- if ((0, fs_1.existsSync)(this.configPath)) {
29
- const content = (0, fs_1.readFileSync)(this.configPath, 'utf-8');
28
+ if ((0, node_fs_1.existsSync)(this.configPath)) {
29
+ const content = (0, node_fs_1.readFileSync)(this.configPath, 'utf-8');
30
30
  return JSON.parse(content);
31
31
  }
32
32
  }
@@ -39,7 +39,7 @@ class ConfigManager {
39
39
  writeConfig(config) {
40
40
  try {
41
41
  this.ensureConfigDir();
42
- (0, fs_1.writeFileSync)(this.configPath, JSON.stringify(config, null, 2), 'utf-8');
42
+ (0, node_fs_1.writeFileSync)(this.configPath, JSON.stringify(config, null, 2), 'utf-8');
43
43
  }
44
44
  catch (error) {
45
45
  console.error('Error writing config:', error);
@@ -66,4 +66,4 @@ class ConfigManager {
66
66
  }
67
67
  // Export singleton instance
68
68
  exports.configManager = new ConfigManager();
69
- //# sourceMappingURL=config.js.map
69
+ //# sourceMappingURL=user-config.js.map
@@ -4,9 +4,9 @@ exports.debugLog = void 0;
4
4
  exports.enableDebugLogging = enableDebugLogging;
5
5
  exports.isDebugEnabled = isDebugEnabled;
6
6
  exports.getDebugLogPath = getDebugLogPath;
7
- const fs_1 = require("fs");
8
- const os_1 = require("os");
9
- const path_1 = require("path");
7
+ const node_fs_1 = require("node:fs");
8
+ const node_os_1 = require("node:os");
9
+ const node_path_1 = require("node:path");
10
10
  let _enabled = false;
11
11
  let _logFile = null;
12
12
  const pad = (n, width = 2) => String(n).padStart(width, '0');
@@ -21,13 +21,13 @@ function getLogFile() {
21
21
  const dateStr = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
22
22
  // Write to the OS temp dir (matches the path advertised in --help), not the
23
23
  // current working directory — a debug log must never litter the user's repo.
24
- const dir = (0, path_1.join)((0, os_1.tmpdir)(), 'inup');
25
- if (!(0, fs_1.existsSync)(dir)) {
26
- (0, fs_1.mkdirSync)(dir, { recursive: true });
24
+ const dir = (0, node_path_1.join)((0, node_os_1.tmpdir)(), 'inup');
25
+ if (!(0, node_fs_1.existsSync)(dir)) {
26
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
27
27
  }
28
- _logFile = (0, path_1.join)(dir, `inup-debug-${dateStr}.log`);
28
+ _logFile = (0, node_path_1.join)(dir, `inup-debug-${dateStr}.log`);
29
29
  // Write a header so the file is easy to identify
30
- (0, fs_1.writeFileSync)(_logFile, `=== inup debug log started at ${timestamp()} ===\n`, { flag: 'a' });
30
+ (0, node_fs_1.writeFileSync)(_logFile, `=== inup debug log started at ${timestamp()} ===\n`, { flag: 'a' });
31
31
  }
32
32
  return _logFile;
33
33
  }
@@ -69,7 +69,7 @@ function write(level, context, message, extra) {
69
69
  }
70
70
  line += '\n';
71
71
  try {
72
- (0, fs_1.appendFileSync)(getLogFile(), line);
72
+ (0, node_fs_1.appendFileSync)(getLogFile(), line);
73
73
  }
74
74
  catch {
75
75
  // Never crash the app because of debug logging
@@ -2,15 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.executeCommand = executeCommand;
4
4
  exports.executeCommandAsync = executeCommandAsync;
5
- const child_process_1 = require("child_process");
6
- const util_1 = require("util");
7
- const execAsync = (0, util_1.promisify)(child_process_1.exec);
5
+ const node_child_process_1 = require("node:child_process");
6
+ const node_util_1 = require("node:util");
7
+ const execAsync = (0, node_util_1.promisify)(node_child_process_1.exec);
8
8
  /**
9
9
  * Execute a command synchronously
10
10
  */
11
11
  function executeCommand(command, cwd) {
12
12
  try {
13
- return (0, child_process_1.execSync)(command, {
13
+ return (0, node_child_process_1.execSync)(command, {
14
14
  encoding: 'utf-8',
15
15
  stdio: 'pipe',
16
16
  cwd: cwd,
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./package-info-sections/sections"), exports);
18
- __exportStar(require("./package-info-sections/release-notes"), exports);
19
- //# sourceMappingURL=package-info-sections.js.map
17
+ __exportStar(require("./io"), exports);
18
+ __exportStar(require("./paths"), exports);
19
+ __exportStar(require("./scan"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -5,11 +5,10 @@ exports.detectJsonFormat = detectJsonFormat;
5
5
  exports.readPackageJsonAsync = readPackageJsonAsync;
6
6
  exports.collectAllDependencies = collectAllDependencies;
7
7
  exports.collectAllDependenciesAsync = collectAllDependenciesAsync;
8
- const fs_1 = require("fs");
9
- const fs_2 = require("fs");
8
+ const node_fs_1 = require("node:fs");
10
9
  function readPackageJson(path) {
11
10
  try {
12
- const content = (0, fs_1.readFileSync)(path, 'utf-8');
11
+ const content = (0, node_fs_1.readFileSync)(path, 'utf-8');
13
12
  return JSON.parse(content);
14
13
  }
15
14
  catch (error) {
@@ -33,7 +32,7 @@ function detectJsonFormat(raw) {
33
32
  }
34
33
  async function readPackageJsonAsync(path) {
35
34
  try {
36
- const content = await fs_2.promises.readFile(path, 'utf-8');
35
+ const content = await node_fs_1.promises.readFile(path, 'utf-8');
37
36
  return JSON.parse(content);
38
37
  }
39
38
  catch (error) {
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findPackageJson = findPackageJson;
4
+ exports.findWorkspaceRoot = findWorkspaceRoot;
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const package_manager_1 = require("../package-manager");
8
+ function findPackageJson(cwd = process.cwd()) {
9
+ const packageJsonPath = (0, node_path_1.join)(cwd, 'package.json');
10
+ return (0, node_fs_1.existsSync)(packageJsonPath) ? packageJsonPath : null;
11
+ }
12
+ function findWorkspaceRoot(cwd = process.cwd(), packageManager) {
13
+ if (!packageManager) {
14
+ const detected = package_manager_1.PackageManagerDetector.detect(cwd);
15
+ packageManager = detected.name;
16
+ }
17
+ return package_manager_1.PackageManagerDetector.findWorkspaceRoot(cwd, packageManager);
18
+ }
19
+ //# sourceMappingURL=paths.js.map
@@ -2,9 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.findAllPackageJsonFiles = findAllPackageJsonFiles;
4
4
  exports.findAllPackageJsonFilesAsync = findAllPackageJsonFilesAsync;
5
- const fs_1 = require("fs");
6
- const fs_2 = require("fs");
7
- const path_1 = require("path");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
8
7
  /**
9
8
  * Normalize a relative path to forward slashes before matching `.inuprc` exclude patterns.
10
9
  * On Windows `path.relative` yields backslash separators (e.g. `packages\skipme`), but users write
@@ -55,12 +54,12 @@ function classifyDirectory(name, skipSet) {
55
54
  * layout). Stays shallow (depth 1) so detecting a skip doesn't re-walk the subtree we just pruned.
56
55
  */
57
56
  function prunedDirHoldsPackage(dir) {
58
- if ((0, fs_1.existsSync)((0, path_1.join)(dir, 'package.json'))) {
57
+ if ((0, node_fs_1.existsSync)((0, node_path_1.join)(dir, 'package.json'))) {
59
58
  return true;
60
59
  }
61
60
  let entries;
62
61
  try {
63
- entries = (0, fs_1.readdirSync)(dir);
62
+ entries = (0, node_fs_1.readdirSync)(dir);
64
63
  }
65
64
  catch {
66
65
  return false;
@@ -68,9 +67,9 @@ function prunedDirHoldsPackage(dir) {
68
67
  for (const entry of entries) {
69
68
  if (entry.startsWith('.'))
70
69
  continue;
71
- const child = (0, path_1.join)(dir, entry);
70
+ const child = (0, node_path_1.join)(dir, entry);
72
71
  try {
73
- if ((0, fs_1.statSync)(child).isDirectory() && (0, fs_1.existsSync)((0, path_1.join)(child, 'package.json'))) {
72
+ if ((0, node_fs_1.statSync)(child).isDirectory() && (0, node_fs_1.existsSync)((0, node_path_1.join)(child, 'package.json'))) {
74
73
  return true;
75
74
  }
76
75
  }
@@ -117,7 +116,7 @@ function findAllPackageJsonFiles(rootDir = process.cwd(), excludePatterns = [],
117
116
  return;
118
117
  }
119
118
  lastProgressAt = now;
120
- const relativePath = (0, path_1.relative)(rootDir, currentDir) || '.';
119
+ const relativePath = (0, node_path_1.relative)(rootDir, currentDir) || '.';
121
120
  onProgress(relativePath, packageJsonFiles.length);
122
121
  }
123
122
  function traverseDirectory(dir, depth = 0) {
@@ -126,7 +125,7 @@ function findAllPackageJsonFiles(rootDir = process.cwd(), excludePatterns = [],
126
125
  }
127
126
  try {
128
127
  // Prevent symlink cycles by tracking visited real paths
129
- const realPath = (0, fs_1.realpathSync)(dir);
128
+ const realPath = (0, node_fs_1.realpathSync)(dir);
130
129
  if (visitedPaths.has(realPath)) {
131
130
  return;
132
131
  }
@@ -136,17 +135,17 @@ function findAllPackageJsonFiles(rootDir = process.cwd(), excludePatterns = [],
136
135
  if (onProgress && (directoriesScanned % 10 === 0 || directoriesScanned === 1)) {
137
136
  reportProgress(dir, true);
138
137
  }
139
- const files = (0, fs_1.readdirSync)(dir);
138
+ const files = (0, node_fs_1.readdirSync)(dir);
140
139
  for (const file of files) {
141
140
  reportProgress(dir);
142
- const fullPath = (0, path_1.join)(dir, file);
143
- const relativePath = (0, path_1.relative)(rootDir, fullPath);
141
+ const fullPath = (0, node_path_1.join)(dir, file);
142
+ const relativePath = (0, node_path_1.relative)(rootDir, fullPath);
144
143
  if (shouldExcludePath(relativePath)) {
145
144
  continue;
146
145
  }
147
146
  let stat;
148
147
  try {
149
- stat = (0, fs_1.statSync)(fullPath);
148
+ stat = (0, node_fs_1.statSync)(fullPath);
150
149
  }
151
150
  catch {
152
151
  // Skip files/dirs we can't stat (broken symlinks, permission issues)
@@ -190,7 +189,7 @@ async function findAllPackageJsonFilesAsync(rootDir = process.cwd(), excludePatt
190
189
  return;
191
190
  }
192
191
  lastProgressAt = now;
193
- const relativePath = (0, path_1.relative)(rootDir, currentDir) || '.';
192
+ const relativePath = (0, node_path_1.relative)(rootDir, currentDir) || '.';
194
193
  onProgress(relativePath, packageJsonFiles.length);
195
194
  }
196
195
  const pending = [];
@@ -217,7 +216,7 @@ async function findAllPackageJsonFilesAsync(rootDir = process.cwd(), excludePatt
217
216
  }
218
217
  let realPath;
219
218
  try {
220
- realPath = await fs_2.promises.realpath(dir);
219
+ realPath = await node_fs_1.promises.realpath(dir);
221
220
  }
222
221
  catch {
223
222
  return;
@@ -232,21 +231,21 @@ async function findAllPackageJsonFilesAsync(rootDir = process.cwd(), excludePatt
232
231
  }
233
232
  let files;
234
233
  try {
235
- files = await fs_2.promises.readdir(dir);
234
+ files = await node_fs_1.promises.readdir(dir);
236
235
  }
237
236
  catch {
238
237
  return;
239
238
  }
240
239
  for (const file of files) {
241
240
  reportProgress(dir);
242
- const fullPath = (0, path_1.join)(dir, file);
243
- const relativePath = (0, path_1.relative)(rootDir, fullPath);
241
+ const fullPath = (0, node_path_1.join)(dir, file);
242
+ const relativePath = (0, node_path_1.relative)(rootDir, fullPath);
244
243
  if (shouldExcludePath(relativePath)) {
245
244
  continue;
246
245
  }
247
246
  let stat;
248
247
  try {
249
- stat = await fs_2.promises.stat(fullPath);
248
+ stat = await node_fs_1.promises.stat(fullPath);
250
249
  }
251
250
  catch {
252
251
  continue;
@@ -262,17 +261,21 @@ async function findAllPackageJsonFilesAsync(rootDir = process.cwd(), excludePatt
262
261
  }
263
262
  }
264
263
  function pump() {
265
- while (activeTasks < concurrency && pending.length > 0 && !failedError) {
264
+ while (activeTasks < concurrency && !failedError) {
266
265
  const next = pending.shift();
267
266
  if (!next)
268
267
  break;
269
268
  activeTasks++;
270
269
  void processDirectory(next.dir, next.depth)
271
270
  .catch((error) => {
271
+ // First error wins; a second in-flight task rejecting in the same
272
+ // tick is a race window that cannot be scheduled deterministically.
273
+ /* v8 ignore start */
272
274
  if (!failedError) {
273
275
  failedError = error;
274
276
  rejectDone?.(error);
275
277
  }
278
+ /* v8 ignore stop */
276
279
  })
277
280
  .finally(() => {
278
281
  activeTasks--;
@@ -1,14 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getGitWorkingTreeState = getGitWorkingTreeState;
4
- const child_process_1 = require("child_process");
4
+ const node_child_process_1 = require("node:child_process");
5
5
  /**
6
6
  * Detect whether cwd is a git work tree and whether it has local changes.
7
7
  * Fail soft if git is unavailable or cwd is not a repository.
8
8
  */
9
9
  function getGitWorkingTreeState(cwd) {
10
10
  try {
11
- const isInsideWorkTree = (0, child_process_1.execSync)('git rev-parse --is-inside-work-tree', {
11
+ const isInsideWorkTree = (0, node_child_process_1.execSync)('git rev-parse --is-inside-work-tree', {
12
12
  cwd,
13
13
  encoding: 'utf-8',
14
14
  stdio: ['ignore', 'pipe', 'ignore'],
@@ -16,7 +16,7 @@ function getGitWorkingTreeState(cwd) {
16
16
  if (isInsideWorkTree !== 'true') {
17
17
  return { isRepo: false, isDirty: false };
18
18
  }
19
- const status = (0, child_process_1.execSync)('git status --porcelain', {
19
+ const status = (0, node_child_process_1.execSync)('git status --porcelain', {
20
20
  cwd,
21
21
  encoding: 'utf-8',
22
22
  stdio: ['ignore', 'pipe', 'ignore'],
@@ -1,34 +1,64 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.setEtagCacheEnabled = setEtagCacheEnabled;
7
+ exports.setEtagCacheRoot = setEtagCacheRoot;
4
8
  exports.readEtag = readEtag;
5
9
  exports.writeEtag = writeEtag;
6
10
  exports.etagCacheDir = etagCacheDir;
7
11
  const node_crypto_1 = require("node:crypto");
8
12
  const node_fs_1 = require("node:fs");
9
- const node_os_1 = require("node:os");
10
13
  const node_path_1 = require("node:path");
14
+ const env_paths_1 = __importDefault(require("env-paths"));
15
+ const config_1 = require("../config");
11
16
  /** Bump when the on-disk entry shape changes; old generations are ignored. */
12
17
  const SCHEMA = 'v1';
13
18
  /** Entries untouched for longer than this are swept on first access. */
14
19
  const MAX_AGE_MS = 14 * 24 * 60 * 60 * 1000; // 14 days
15
20
  let enabled = true;
16
21
  let sweptThisProcess = false;
22
+ let cacheRootOverride = null;
23
+ let resolvedSchemaDir = null;
17
24
  /** Allow tests/callers to toggle the store without touching call sites. */
18
25
  function setEtagCacheEnabled(value) {
19
26
  enabled = value;
20
27
  }
28
+ /**
29
+ * Test hook: point the store at an isolated root instead of the user's real
30
+ * cache directory (null restores the default). Tests must never wipe or race
31
+ * on the persistent per-user cache.
32
+ */
33
+ function setEtagCacheRoot(root) {
34
+ cacheRootOverride = root;
35
+ resolvedSchemaDir = null;
36
+ sweptThisProcess = false;
37
+ }
38
+ /** The root holding one subdirectory per schema generation. */
39
+ function cacheRoot() {
40
+ // Version data is not project-specific, so it lives in the per-user cache
41
+ // directory (env-paths, like the config dir), shared across every project the
42
+ // user scans. It used to live in the OS temp dir, but macOS clears that on
43
+ // reboot and Linux distros sweep it periodically — throwing the cache away
44
+ // exactly when it is most useful.
45
+ return cacheRootOverride ?? (0, node_path_1.join)((0, env_paths_1.default)(config_1.PACKAGE_NAME).cache, 'etag-cache');
46
+ }
21
47
  /** Resolve (and lazily create) the cache directory, sweeping stale entries once. */
22
48
  function cacheDir() {
23
- // Version data is not project-specific, so it lives in the OS temp area, shared
24
- // across every project the user scans.
25
- const dir = (0, node_path_1.join)((0, node_os_1.tmpdir)(), 'inup', 'etag-cache', SCHEMA);
49
+ if (resolvedSchemaDir === null) {
50
+ // The location is process-invariant; derive it once instead of running
51
+ // env-paths on every cache read/write of the registry hot path.
52
+ resolvedSchemaDir = (0, node_path_1.join)(cacheRoot(), SCHEMA);
53
+ }
54
+ const dir = resolvedSchemaDir;
26
55
  if (!(0, node_fs_1.existsSync)(dir)) {
27
56
  (0, node_fs_1.mkdirSync)(dir, { recursive: true });
28
57
  }
29
58
  if (!sweptThisProcess) {
30
59
  sweptThisProcess = true;
31
60
  sweepStale(dir);
61
+ sweepOldGenerations(cacheRoot());
32
62
  }
33
63
  return dir;
34
64
  }
@@ -51,6 +81,28 @@ function sweepStale(dir) {
51
81
  /* sweeping is optional; never fail a run over it */
52
82
  }
53
83
  }
84
+ /**
85
+ * Remove schema generations other than the active one. The cache directory is
86
+ * persistent (unlike the old tmpdir location, which the OS reclaimed), so after
87
+ * a SCHEMA bump the previous generation would otherwise live on disk forever.
88
+ */
89
+ function sweepOldGenerations(root) {
90
+ try {
91
+ for (const name of (0, node_fs_1.readdirSync)(root)) {
92
+ if (name === SCHEMA)
93
+ continue;
94
+ try {
95
+ (0, node_fs_1.rmSync)((0, node_path_1.join)(root, name), { recursive: true, force: true });
96
+ }
97
+ catch {
98
+ /* skip generations we can't remove */
99
+ }
100
+ }
101
+ }
102
+ catch {
103
+ /* sweeping is optional; never fail a run over it */
104
+ }
105
+ }
54
106
  /** Stable, filesystem-safe filename for a cache key (the registry path). */
55
107
  function fileFor(key) {
56
108
  const hash = (0, node_crypto_1.createHash)('sha1').update(key).digest('hex');
@@ -60,8 +60,10 @@ class ResizableSemaphore {
60
60
  * each as it is admitted so the count stays authoritative and synchronous.
61
61
  */
62
62
  drainWaiters() {
63
- while (this.inFlight < this.limit && this.waiters.length > 0) {
63
+ while (this.inFlight < this.limit) {
64
64
  const next = this.waiters.shift();
65
+ if (!next)
66
+ break;
65
67
  this.inFlight++;
66
68
  next();
67
69
  }
@@ -1,15 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.loadInupLocalEnv = loadInupLocalEnv;
4
- const fs_1 = require("fs");
5
- const path_1 = require("path");
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
6
  /**
7
7
  * Loads a gitignored `.env.local` from the inup repo itself (NOT the cwd), so
8
8
  * developer-only toggles can be "set once" and apply to every `inup` run in any
9
9
  * project — without committing anything or touching the shell profile.
10
10
  *
11
11
  * The repo is located by walking UP from this file's own directory until a
12
- * `.env.local` is found, so it works regardless of nesting depth (src/utils when
12
+ * `.env.local` is found, so it works regardless of nesting depth (src/shared when
13
13
  * type-stripped, dist/utils when compiled) and resolves the inup repo even when
14
14
  * the binary is linked and invoked from a different project directory.
15
15
  *
@@ -21,15 +21,15 @@ const ENV_FILE_NAME = '.env.local';
21
21
  /** Walk upward from this file's dir to find the .env.local; null if none. */
22
22
  function findEnvFile() {
23
23
  let dir = __dirname;
24
- const root = (0, path_1.parse)(dir).root;
24
+ const root = (0, node_path_1.parse)(dir).root;
25
25
  // Cap the walk so a missing file can never loop unbounded.
26
26
  for (let i = 0; i < 12; i++) {
27
- const candidate = (0, path_1.join)(dir, ENV_FILE_NAME);
28
- if ((0, fs_1.existsSync)(candidate))
27
+ const candidate = (0, node_path_1.join)(dir, ENV_FILE_NAME);
28
+ if ((0, node_fs_1.existsSync)(candidate))
29
29
  return candidate;
30
30
  if (dir === root)
31
31
  break;
32
- dir = (0, path_1.dirname)(dir);
32
+ dir = (0, node_path_1.dirname)(dir);
33
33
  }
34
34
  return null;
35
35
  }
@@ -65,7 +65,7 @@ function loadInupLocalEnv() {
65
65
  const file = findEnvFile();
66
66
  if (!file)
67
67
  return null;
68
- const parsed = parseEnv((0, fs_1.readFileSync)(file, 'utf8'));
68
+ const parsed = parseEnv((0, node_fs_1.readFileSync)(file, 'utf8'));
69
69
  for (const [key, value] of Object.entries(parsed)) {
70
70
  if (process.env[key] === undefined) {
71
71
  process.env[key] = value;