pnpm-catalog-updates 0.5.6 → 0.6.5

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 (220) hide show
  1. package/bin/pcu.js +1 -1
  2. package/dist/index.js +9559 -32
  3. package/dist/index.js.map +1 -1
  4. package/package.json +61 -103
  5. package/src/cli/commands/checkCommand.ts +227 -0
  6. package/src/cli/commands/initCommand.ts +394 -0
  7. package/src/cli/commands/securityCommand.ts +569 -0
  8. package/src/cli/commands/updateCommand.ts +245 -0
  9. package/src/cli/formatters/outputFormatter.ts +830 -0
  10. package/src/cli/formatters/progressBar.ts +700 -0
  11. package/src/cli/index.ts +565 -0
  12. package/src/cli/interactive/interactivePrompts.ts +517 -0
  13. package/src/cli/options/globalOptions.ts +380 -0
  14. package/src/cli/options/index.ts +5 -0
  15. package/src/cli/themes/colorTheme.ts +379 -0
  16. package/src/cli/validators/commandValidator.ts +395 -0
  17. package/src/cli/validators/index.ts +5 -0
  18. package/src/index.ts +4 -0
  19. package/LICENSE +0 -21
  20. package/README.ja.md +0 -582
  21. package/README.md +0 -690
  22. package/README.zh-CN.md +0 -630
  23. package/dist/application/services/CatalogUpdateService.d.ts +0 -209
  24. package/dist/application/services/CatalogUpdateService.d.ts.map +0 -1
  25. package/dist/application/services/CatalogUpdateService.js +0 -836
  26. package/dist/application/services/CatalogUpdateService.js.map +0 -1
  27. package/dist/application/services/WorkspaceService.d.ts +0 -139
  28. package/dist/application/services/WorkspaceService.d.ts.map +0 -1
  29. package/dist/application/services/WorkspaceService.js +0 -340
  30. package/dist/application/services/WorkspaceService.js.map +0 -1
  31. package/dist/cli/commands/CheckCommand.d.ts +0 -40
  32. package/dist/cli/commands/CheckCommand.d.ts.map +0 -1
  33. package/dist/cli/commands/CheckCommand.js +0 -177
  34. package/dist/cli/commands/CheckCommand.js.map +0 -1
  35. package/dist/cli/commands/InitCommand.d.ts +0 -53
  36. package/dist/cli/commands/InitCommand.d.ts.map +0 -1
  37. package/dist/cli/commands/InitCommand.js +0 -338
  38. package/dist/cli/commands/InitCommand.js.map +0 -1
  39. package/dist/cli/commands/SecurityCommand.d.ts +0 -113
  40. package/dist/cli/commands/SecurityCommand.d.ts.map +0 -1
  41. package/dist/cli/commands/SecurityCommand.js +0 -410
  42. package/dist/cli/commands/SecurityCommand.js.map +0 -1
  43. package/dist/cli/commands/UpdateCommand.d.ts +0 -44
  44. package/dist/cli/commands/UpdateCommand.d.ts.map +0 -1
  45. package/dist/cli/commands/UpdateCommand.js +0 -189
  46. package/dist/cli/commands/UpdateCommand.js.map +0 -1
  47. package/dist/cli/formatters/OutputFormatter.d.ts +0 -116
  48. package/dist/cli/formatters/OutputFormatter.d.ts.map +0 -1
  49. package/dist/cli/formatters/OutputFormatter.js +0 -664
  50. package/dist/cli/formatters/OutputFormatter.js.map +0 -1
  51. package/dist/cli/formatters/ProgressBar.d.ts +0 -195
  52. package/dist/cli/formatters/ProgressBar.d.ts.map +0 -1
  53. package/dist/cli/formatters/ProgressBar.js +0 -622
  54. package/dist/cli/formatters/ProgressBar.js.map +0 -1
  55. package/dist/cli/index.d.ts +0 -12
  56. package/dist/cli/index.d.ts.map +0 -1
  57. package/dist/cli/index.js +0 -492
  58. package/dist/cli/index.js.map +0 -1
  59. package/dist/cli/interactive/InteractivePrompts.d.ts +0 -85
  60. package/dist/cli/interactive/InteractivePrompts.d.ts.map +0 -1
  61. package/dist/cli/interactive/InteractivePrompts.js +0 -434
  62. package/dist/cli/interactive/InteractivePrompts.js.map +0 -1
  63. package/dist/cli/options/GlobalOptions.d.ts +0 -117
  64. package/dist/cli/options/GlobalOptions.d.ts.map +0 -1
  65. package/dist/cli/options/GlobalOptions.js +0 -278
  66. package/dist/cli/options/GlobalOptions.js.map +0 -1
  67. package/dist/cli/options/index.d.ts +0 -5
  68. package/dist/cli/options/index.d.ts.map +0 -1
  69. package/dist/cli/options/index.js +0 -5
  70. package/dist/cli/options/index.js.map +0 -1
  71. package/dist/cli/themes/ColorTheme.d.ts +0 -211
  72. package/dist/cli/themes/ColorTheme.d.ts.map +0 -1
  73. package/dist/cli/themes/ColorTheme.js +0 -267
  74. package/dist/cli/themes/ColorTheme.js.map +0 -1
  75. package/dist/cli/validators/CommandValidator.d.ts +0 -60
  76. package/dist/cli/validators/CommandValidator.d.ts.map +0 -1
  77. package/dist/cli/validators/CommandValidator.js +0 -319
  78. package/dist/cli/validators/CommandValidator.js.map +0 -1
  79. package/dist/cli/validators/index.d.ts +0 -5
  80. package/dist/cli/validators/index.d.ts.map +0 -1
  81. package/dist/cli/validators/index.js +0 -5
  82. package/dist/cli/validators/index.js.map +0 -1
  83. package/dist/common/config/Config.d.ts +0 -142
  84. package/dist/common/config/Config.d.ts.map +0 -1
  85. package/dist/common/config/Config.js +0 -382
  86. package/dist/common/config/Config.js.map +0 -1
  87. package/dist/common/config/ConfigLoader.d.ts +0 -49
  88. package/dist/common/config/ConfigLoader.d.ts.map +0 -1
  89. package/dist/common/config/ConfigLoader.js +0 -180
  90. package/dist/common/config/ConfigLoader.js.map +0 -1
  91. package/dist/common/config/PackageFilterConfig.d.ts +0 -56
  92. package/dist/common/config/PackageFilterConfig.d.ts.map +0 -1
  93. package/dist/common/config/PackageFilterConfig.js +0 -94
  94. package/dist/common/config/PackageFilterConfig.js.map +0 -1
  95. package/dist/common/config/index.d.ts +0 -8
  96. package/dist/common/config/index.d.ts.map +0 -1
  97. package/dist/common/config/index.js +0 -8
  98. package/dist/common/config/index.js.map +0 -1
  99. package/dist/common/error-handling/ErrorTracker.d.ts +0 -48
  100. package/dist/common/error-handling/ErrorTracker.d.ts.map +0 -1
  101. package/dist/common/error-handling/ErrorTracker.js +0 -93
  102. package/dist/common/error-handling/ErrorTracker.js.map +0 -1
  103. package/dist/common/error-handling/UserFriendlyErrorHandler.d.ts +0 -74
  104. package/dist/common/error-handling/UserFriendlyErrorHandler.d.ts.map +0 -1
  105. package/dist/common/error-handling/UserFriendlyErrorHandler.js +0 -703
  106. package/dist/common/error-handling/UserFriendlyErrorHandler.js.map +0 -1
  107. package/dist/common/error-handling/index.d.ts +0 -11
  108. package/dist/common/error-handling/index.d.ts.map +0 -1
  109. package/dist/common/error-handling/index.js +0 -9
  110. package/dist/common/error-handling/index.js.map +0 -1
  111. package/dist/common/logger/Logger.d.ts +0 -110
  112. package/dist/common/logger/Logger.d.ts.map +0 -1
  113. package/dist/common/logger/Logger.js +0 -289
  114. package/dist/common/logger/Logger.js.map +0 -1
  115. package/dist/common/logger/index.d.ts +0 -6
  116. package/dist/common/logger/index.d.ts.map +0 -1
  117. package/dist/common/logger/index.js +0 -6
  118. package/dist/common/logger/index.js.map +0 -1
  119. package/dist/common/types/cli.d.ts +0 -265
  120. package/dist/common/types/cli.d.ts.map +0 -1
  121. package/dist/common/types/cli.js +0 -5
  122. package/dist/common/types/cli.js.map +0 -1
  123. package/dist/common/types/core.d.ts +0 -270
  124. package/dist/common/types/core.d.ts.map +0 -1
  125. package/dist/common/types/core.js +0 -32
  126. package/dist/common/types/core.js.map +0 -1
  127. package/dist/common/types/index.d.ts +0 -8
  128. package/dist/common/types/index.d.ts.map +0 -1
  129. package/dist/common/types/index.js +0 -8
  130. package/dist/common/types/index.js.map +0 -1
  131. package/dist/common/utils/VersionChecker.d.ts +0 -54
  132. package/dist/common/utils/VersionChecker.d.ts.map +0 -1
  133. package/dist/common/utils/VersionChecker.js +0 -180
  134. package/dist/common/utils/VersionChecker.js.map +0 -1
  135. package/dist/common/utils/async.d.ts +0 -74
  136. package/dist/common/utils/async.d.ts.map +0 -1
  137. package/dist/common/utils/async.js +0 -228
  138. package/dist/common/utils/async.js.map +0 -1
  139. package/dist/common/utils/format.d.ts +0 -32
  140. package/dist/common/utils/format.d.ts.map +0 -1
  141. package/dist/common/utils/format.js +0 -121
  142. package/dist/common/utils/format.js.map +0 -1
  143. package/dist/common/utils/git.d.ts +0 -44
  144. package/dist/common/utils/git.d.ts.map +0 -1
  145. package/dist/common/utils/git.js +0 -147
  146. package/dist/common/utils/git.js.map +0 -1
  147. package/dist/common/utils/index.d.ts +0 -12
  148. package/dist/common/utils/index.d.ts.map +0 -1
  149. package/dist/common/utils/index.js +0 -12
  150. package/dist/common/utils/index.js.map +0 -1
  151. package/dist/common/utils/string.d.ts +0 -56
  152. package/dist/common/utils/string.d.ts.map +0 -1
  153. package/dist/common/utils/string.js +0 -134
  154. package/dist/common/utils/string.js.map +0 -1
  155. package/dist/common/utils/validation.d.ts +0 -88
  156. package/dist/common/utils/validation.d.ts.map +0 -1
  157. package/dist/common/utils/validation.js +0 -308
  158. package/dist/common/utils/validation.js.map +0 -1
  159. package/dist/domain/entities/Catalog.d.ts +0 -117
  160. package/dist/domain/entities/Catalog.d.ts.map +0 -1
  161. package/dist/domain/entities/Catalog.js +0 -240
  162. package/dist/domain/entities/Catalog.js.map +0 -1
  163. package/dist/domain/entities/Package.d.ts +0 -143
  164. package/dist/domain/entities/Package.d.ts.map +0 -1
  165. package/dist/domain/entities/Package.js +0 -272
  166. package/dist/domain/entities/Package.js.map +0 -1
  167. package/dist/domain/entities/Workspace.d.ts +0 -95
  168. package/dist/domain/entities/Workspace.d.ts.map +0 -1
  169. package/dist/domain/entities/Workspace.js +0 -173
  170. package/dist/domain/entities/Workspace.js.map +0 -1
  171. package/dist/domain/repositories/WorkspaceRepository.d.ts +0 -41
  172. package/dist/domain/repositories/WorkspaceRepository.d.ts.map +0 -1
  173. package/dist/domain/repositories/WorkspaceRepository.js +0 -8
  174. package/dist/domain/repositories/WorkspaceRepository.js.map +0 -1
  175. package/dist/domain/value-objects/CatalogCollection.d.ts +0 -106
  176. package/dist/domain/value-objects/CatalogCollection.d.ts.map +0 -1
  177. package/dist/domain/value-objects/CatalogCollection.js +0 -230
  178. package/dist/domain/value-objects/CatalogCollection.js.map +0 -1
  179. package/dist/domain/value-objects/PackageCollection.d.ts +0 -122
  180. package/dist/domain/value-objects/PackageCollection.d.ts.map +0 -1
  181. package/dist/domain/value-objects/PackageCollection.js +0 -263
  182. package/dist/domain/value-objects/PackageCollection.js.map +0 -1
  183. package/dist/domain/value-objects/Version.d.ts +0 -141
  184. package/dist/domain/value-objects/Version.d.ts.map +0 -1
  185. package/dist/domain/value-objects/Version.js +0 -268
  186. package/dist/domain/value-objects/Version.js.map +0 -1
  187. package/dist/domain/value-objects/WorkspaceConfig.d.ts +0 -144
  188. package/dist/domain/value-objects/WorkspaceConfig.d.ts.map +0 -1
  189. package/dist/domain/value-objects/WorkspaceConfig.js +0 -357
  190. package/dist/domain/value-objects/WorkspaceConfig.js.map +0 -1
  191. package/dist/domain/value-objects/WorkspaceId.d.ts +0 -51
  192. package/dist/domain/value-objects/WorkspaceId.d.ts.map +0 -1
  193. package/dist/domain/value-objects/WorkspaceId.js +0 -104
  194. package/dist/domain/value-objects/WorkspaceId.js.map +0 -1
  195. package/dist/domain/value-objects/WorkspacePath.d.ts +0 -75
  196. package/dist/domain/value-objects/WorkspacePath.d.ts.map +0 -1
  197. package/dist/domain/value-objects/WorkspacePath.js +0 -128
  198. package/dist/domain/value-objects/WorkspacePath.js.map +0 -1
  199. package/dist/index.d.ts +0 -25
  200. package/dist/index.d.ts.map +0 -1
  201. package/dist/infrastructure/cache/Cache.d.ts +0 -161
  202. package/dist/infrastructure/cache/Cache.d.ts.map +0 -1
  203. package/dist/infrastructure/cache/Cache.js +0 -398
  204. package/dist/infrastructure/cache/Cache.js.map +0 -1
  205. package/dist/infrastructure/cache/index.d.ts +0 -6
  206. package/dist/infrastructure/cache/index.d.ts.map +0 -1
  207. package/dist/infrastructure/cache/index.js +0 -6
  208. package/dist/infrastructure/cache/index.js.map +0 -1
  209. package/dist/infrastructure/external-services/NpmRegistryService.d.ts +0 -145
  210. package/dist/infrastructure/external-services/NpmRegistryService.d.ts.map +0 -1
  211. package/dist/infrastructure/external-services/NpmRegistryService.js +0 -466
  212. package/dist/infrastructure/external-services/NpmRegistryService.js.map +0 -1
  213. package/dist/infrastructure/file-system/FileSystemService.d.ts +0 -120
  214. package/dist/infrastructure/file-system/FileSystemService.d.ts.map +0 -1
  215. package/dist/infrastructure/file-system/FileSystemService.js +0 -663
  216. package/dist/infrastructure/file-system/FileSystemService.js.map +0 -1
  217. package/dist/infrastructure/repositories/FileWorkspaceRepository.d.ts +0 -57
  218. package/dist/infrastructure/repositories/FileWorkspaceRepository.d.ts.map +0 -1
  219. package/dist/infrastructure/repositories/FileWorkspaceRepository.js +0 -179
  220. package/dist/infrastructure/repositories/FileWorkspaceRepository.js.map +0 -1
@@ -0,0 +1,565 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * pnpm-catalog-updates CLI Entry Point
5
+ *
6
+ * A CLI tool for checking and updating pnpm workspace catalog dependencies.
7
+ * This is the main entry point that handles command parsing and execution.
8
+ */
9
+
10
+ import { dirname, join } from 'path';
11
+ import { OutputFormat, OutputFormatter } from './formatters/outputFormatter.js';
12
+
13
+ // Services and Dependencies
14
+ import {
15
+ CatalogUpdateService,
16
+ WorkspaceService,
17
+ NpmRegistryService,
18
+ FileSystemService,
19
+ FileWorkspaceRepository,
20
+ } from '@pcu/core';
21
+ // CLI Commands
22
+ import chalk from 'chalk';
23
+ import { Command } from 'commander';
24
+ import { readFileSync } from 'fs';
25
+ import { fileURLToPath } from 'url';
26
+ import { CheckCommand } from './commands/checkCommand.js';
27
+ import { UpdateCommand } from './commands/updateCommand.js';
28
+ import { SecurityCommand } from './commands/securityCommand.js';
29
+ import { InitCommand } from './commands/initCommand.js';
30
+ import { InteractivePrompts } from './interactive/interactivePrompts.js';
31
+ import { ThemeManager, StyledText } from './themes/colorTheme.js';
32
+ import { VersionChecker, ConfigLoader } from '@pcu/utils';
33
+
34
+ // Get package.json for version info
35
+ const __filename = fileURLToPath(import.meta.url);
36
+ const __dirname = dirname(__filename);
37
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
38
+
39
+ /**
40
+ * Create service dependencies with configuration support
41
+ */
42
+ function createServices(workspacePath?: string) {
43
+ const fileSystemService = new FileSystemService();
44
+ const workspaceRepository = new FileWorkspaceRepository(fileSystemService);
45
+ // Use factory method to create CatalogUpdateService with configuration
46
+ const catalogUpdateService = CatalogUpdateService.createWithConfig(
47
+ workspaceRepository,
48
+ workspacePath
49
+ );
50
+ const workspaceService = new WorkspaceService(workspaceRepository);
51
+
52
+ return {
53
+ fileSystemService,
54
+ workspaceRepository,
55
+ catalogUpdateService,
56
+ workspaceService,
57
+ };
58
+ }
59
+
60
+ /**
61
+ * Main CLI function
62
+ */
63
+ export async function main(): Promise<void> {
64
+ const program = new Command();
65
+
66
+ // Parse arguments first to get workspace path
67
+ let workspacePath: string | undefined;
68
+
69
+ // Extract workspace path from arguments for service creation
70
+ const workspaceIndex = process.argv.findIndex((arg) => arg === '-w' || arg === '--workspace');
71
+ if (workspaceIndex !== -1 && workspaceIndex + 1 < process.argv.length) {
72
+ workspacePath = process.argv[workspaceIndex + 1];
73
+ }
74
+
75
+ // Load configuration to check if version updates are enabled
76
+ const config = ConfigLoader.loadConfig(workspacePath || process.cwd());
77
+
78
+ // Check for version updates (skip in CI environments or if disabled)
79
+ if (VersionChecker.shouldCheckForUpdates() && config.advanced?.checkForUpdates !== false) {
80
+ try {
81
+ const versionResult = await VersionChecker.checkVersion(packageJson.version, {
82
+ skipPrompt: false,
83
+ timeout: 3000, // Short timeout to not delay CLI startup
84
+ });
85
+
86
+ if (versionResult.shouldPrompt) {
87
+ const didUpdate = await VersionChecker.promptAndUpdate(versionResult);
88
+ if (didUpdate) {
89
+ // Exit after successful update to allow user to restart with new version
90
+ console.log(chalk.blue('Please run your command again to use the updated version.'));
91
+ process.exit(0);
92
+ }
93
+ }
94
+ } catch (error) {
95
+ // Silently fail version check to not interrupt CLI usage (only show warning in verbose mode)
96
+ if (process.argv.includes('-v') || process.argv.includes('--verbose')) {
97
+ console.warn(chalk.yellow('⚠️ Could not check for updates:'), error);
98
+ }
99
+ }
100
+ }
101
+
102
+ // Create services with workspace path for configuration loading
103
+ const services = createServices(workspacePath);
104
+
105
+ // Configure the main command
106
+ program
107
+ .name('pcu')
108
+ .description('A CLI tool to check and update pnpm workspace catalog dependencies')
109
+ .option('--version', 'show version information')
110
+ .option('-v, --verbose', 'enable verbose logging')
111
+ .option('-w, --workspace <path>', 'workspace directory path')
112
+ .option('--no-color', 'disable colored output')
113
+ .option('-u, --update', 'shorthand for update command')
114
+ .option('-c, --check', 'shorthand for check command')
115
+ .option('-a, --analyze', 'shorthand for analyze command')
116
+ .option('-s, --workspace-info', 'shorthand for workspace command')
117
+ .option('-t, --theme', 'shorthand for theme command')
118
+ .option('--security-audit', 'shorthand for security command')
119
+ .option('--security-fix', 'shorthand for security --fix-vulns command');
120
+
121
+ // Check command
122
+ program
123
+ .command('check')
124
+ .alias('chk')
125
+ .description('check for outdated catalog dependencies')
126
+ .option('--catalog <name>', 'check specific catalog only')
127
+ .option('-f, --format <type>', 'output format: table, json, yaml, minimal', 'table')
128
+ .option(
129
+ '-t, --target <type>',
130
+ 'update target: latest, greatest, minor, patch, newest',
131
+ 'latest'
132
+ )
133
+ .option('--prerelease', 'include prerelease versions')
134
+ .option('--include <pattern>', 'include packages matching pattern', [])
135
+ .option('--exclude <pattern>', 'exclude packages matching pattern', [])
136
+ .action(async (options, command) => {
137
+ try {
138
+ const globalOptions = command.parent.opts();
139
+ const checkCommand = new CheckCommand(services.catalogUpdateService);
140
+
141
+ await checkCommand.execute({
142
+ workspace: globalOptions.workspace,
143
+ catalog: options.catalog,
144
+ format: options.format,
145
+ target: options.target,
146
+ prerelease: options.prerelease,
147
+ include: Array.isArray(options.include)
148
+ ? options.include
149
+ : [options.include].filter(Boolean),
150
+ exclude: Array.isArray(options.exclude)
151
+ ? options.exclude
152
+ : [options.exclude].filter(Boolean),
153
+ verbose: globalOptions.verbose,
154
+ color: !globalOptions.noColor,
155
+ });
156
+ } catch (error) {
157
+ console.error(chalk.red('❌ Error:'), error);
158
+ process.exit(1);
159
+ }
160
+ });
161
+
162
+ // Update command
163
+ program
164
+ .command('update')
165
+ .alias('u')
166
+ .description('update catalog dependencies')
167
+ .option('-i, --interactive', 'interactive mode to choose updates')
168
+ .option('-d, --dry-run', 'preview changes without writing files')
169
+ .option(
170
+ '-t, --target <type>',
171
+ 'update target: latest, greatest, minor, patch, newest',
172
+ 'latest'
173
+ )
174
+ .option('--catalog <name>', 'update specific catalog only')
175
+ .option('--include <pattern>', 'include packages matching pattern', [])
176
+ .option('--exclude <pattern>', 'exclude packages matching pattern', [])
177
+ .option('--force', 'force updates even if risky')
178
+ .option('--prerelease', 'include prerelease versions')
179
+ .option('-b, --create-backup', 'create backup files before updating')
180
+ .option('-f, --format <type>', 'output format: table, json, yaml, minimal', 'table')
181
+ .action(async (options, command) => {
182
+ try {
183
+ const globalOptions = command.parent.opts();
184
+ const updateCommand = new UpdateCommand(services.catalogUpdateService);
185
+
186
+ await updateCommand.execute({
187
+ workspace: globalOptions.workspace,
188
+ catalog: options.catalog,
189
+ format: options.format,
190
+ target: options.target,
191
+ interactive: options.interactive,
192
+ dryRun: options.dryRun,
193
+ force: options.force,
194
+ prerelease: options.prerelease,
195
+ include: Array.isArray(options.include)
196
+ ? options.include
197
+ : [options.include].filter(Boolean),
198
+ exclude: Array.isArray(options.exclude)
199
+ ? options.exclude
200
+ : [options.exclude].filter(Boolean),
201
+ createBackup: options.createBackup,
202
+ verbose: globalOptions.verbose,
203
+ color: !globalOptions.noColor,
204
+ });
205
+ } catch (error) {
206
+ console.error(chalk.red('❌ Error:'), error);
207
+ process.exit(1);
208
+ }
209
+ });
210
+
211
+ // Analyze command
212
+ program
213
+ .command('analyze')
214
+ .alias('a')
215
+ .description('analyze the impact of updating a specific dependency')
216
+ .argument('<catalog>', 'catalog name')
217
+ .argument('<package>', 'package name')
218
+ .argument('[version]', 'new version (default: latest)')
219
+ .option('-f, --format <type>', 'output format: table, json, yaml, minimal', 'table')
220
+ .action(async (catalog, packageName, version, options, command) => {
221
+ try {
222
+ const globalOptions = command.parent.opts();
223
+ const formatter = new OutputFormatter(
224
+ options.format as OutputFormat,
225
+ !globalOptions.noColor
226
+ );
227
+
228
+ // Get latest version if not specified
229
+ let targetVersion = version;
230
+ if (!targetVersion) {
231
+ // Create a temporary registry service for version fetching
232
+ const tempRegistryService = new NpmRegistryService();
233
+ targetVersion = (await tempRegistryService.getLatestVersion(packageName)).toString();
234
+ }
235
+
236
+ const analysis = await services.catalogUpdateService.analyzeImpact(
237
+ catalog,
238
+ packageName,
239
+ targetVersion,
240
+ globalOptions.workspace
241
+ );
242
+
243
+ const formattedOutput = formatter.formatImpactAnalysis(analysis);
244
+ console.log(formattedOutput);
245
+ } catch (error) {
246
+ console.error(chalk.red('❌ Error:'), error);
247
+ process.exit(1);
248
+ }
249
+ });
250
+
251
+ // Workspace command
252
+ program
253
+ .command('workspace')
254
+ .alias('w')
255
+ .description('workspace information and validation')
256
+ .option('--validate', 'validate workspace configuration')
257
+ .option('-s, --stats', 'show workspace statistics')
258
+ .option('-f, --format <type>', 'output format: table, json, yaml, minimal', 'table')
259
+ .action(async (options, command) => {
260
+ try {
261
+ const globalOptions = command.parent.opts();
262
+ const formatter = new OutputFormatter(
263
+ options.format as OutputFormat,
264
+ !globalOptions.noColor
265
+ );
266
+
267
+ if (options.validate) {
268
+ const report = await services.workspaceService.validateWorkspace(globalOptions.workspace);
269
+ const formattedOutput = formatter.formatValidationReport(report);
270
+ console.log(formattedOutput);
271
+ process.exit(report.isValid ? 0 : 1);
272
+ } else if (options.stats) {
273
+ const stats = await services.workspaceService.getWorkspaceStats(globalOptions.workspace);
274
+ const formattedOutput = formatter.formatWorkspaceStats(stats);
275
+ console.log(formattedOutput);
276
+ } else {
277
+ const info = await services.workspaceService.getWorkspaceInfo(globalOptions.workspace);
278
+ console.log(formatter.formatMessage(`Workspace: ${info.name}`, 'info'));
279
+ console.log(formatter.formatMessage(`Path: ${info.path}`, 'info'));
280
+ console.log(formatter.formatMessage(`Packages: ${info.packageCount}`, 'info'));
281
+ console.log(formatter.formatMessage(`Catalogs: ${info.catalogCount}`, 'info'));
282
+
283
+ if (info.catalogNames.length > 0) {
284
+ console.log(
285
+ formatter.formatMessage(`Catalog names: ${info.catalogNames.join(', ')}`, 'info')
286
+ );
287
+ }
288
+ }
289
+ } catch (error) {
290
+ console.error(chalk.red('❌ Error:'), error);
291
+ process.exit(1);
292
+ }
293
+ });
294
+
295
+ // Theme command
296
+ program
297
+ .command('theme')
298
+ .alias('t')
299
+ .description('configure color theme')
300
+ .option('-s, --set <theme>', 'set theme: default, modern, minimal, neon')
301
+ .option('-l, --list', 'list available themes')
302
+ .option('-i, --interactive', 'interactive theme selection')
303
+ .action(async (options, _command) => {
304
+ try {
305
+ if (options.list) {
306
+ const themes = ThemeManager.listThemes();
307
+ console.log(StyledText.iconInfo('Available themes:'));
308
+ themes.forEach((theme) => {
309
+ console.log(` • ${theme}`);
310
+ });
311
+ return;
312
+ }
313
+
314
+ if (options.set) {
315
+ const themes = ThemeManager.listThemes();
316
+ if (!themes.includes(options.set)) {
317
+ console.error(StyledText.iconError(`Invalid theme: ${options.set}`));
318
+ console.log(StyledText.muted(`Available themes: ${themes.join(', ')}`));
319
+ process.exit(1);
320
+ }
321
+
322
+ ThemeManager.setTheme(options.set);
323
+ console.log(StyledText.iconSuccess(`Theme set to: ${options.set}`));
324
+
325
+ // Show a preview
326
+ console.log('\nTheme preview:');
327
+ const theme = ThemeManager.getTheme();
328
+ console.log(` ${theme.success('✓ Success message')}`);
329
+ console.log(` ${theme.warning('⚠ Warning message')}`);
330
+ console.log(` ${theme.error('✗ Error message')}`);
331
+ console.log(` ${theme.info('ℹ Info message')}`);
332
+ console.log(
333
+ ` ${theme.major('Major update')} | ${theme.minor('Minor update')} | ${theme.patch('Patch update')}`
334
+ );
335
+ return;
336
+ }
337
+
338
+ if (options.interactive) {
339
+ const interactivePrompts = new InteractivePrompts();
340
+ const config = await interactivePrompts.configurationWizard();
341
+
342
+ if (config.theme) {
343
+ ThemeManager.setTheme(config.theme);
344
+ console.log(StyledText.iconSuccess(`Theme configured: ${config.theme}`));
345
+ }
346
+ return;
347
+ }
348
+
349
+ // Default: show current theme and list
350
+ const currentTheme = ThemeManager.getTheme();
351
+ console.log(StyledText.iconInfo('Current theme settings:'));
352
+ console.log(` Theme: ${currentTheme ? 'custom' : 'default'}`);
353
+ console.log('\nAvailable themes:');
354
+ ThemeManager.listThemes().forEach((theme) => {
355
+ console.log(` • ${theme}`);
356
+ });
357
+ console.log(
358
+ StyledText.muted('\nUse --set <theme> to change theme or --interactive for guided setup')
359
+ );
360
+ } catch (error) {
361
+ console.error(StyledText.iconError('Error configuring theme:'), error);
362
+ process.exit(1);
363
+ }
364
+ });
365
+
366
+ // Security command
367
+ program
368
+ .command('security')
369
+ .alias('sec')
370
+ .description('security vulnerability scanning and automated fixes')
371
+ .option('-f, --format <type>', 'output format: table, json, yaml, minimal', 'table')
372
+ .option('--audit', 'perform npm audit scan (default: true)', true)
373
+ .option('--fix-vulns', 'automatically fix vulnerabilities')
374
+ .option('--severity <level>', 'filter by severity: low, moderate, high, critical')
375
+ .option('--include-dev', 'include dev dependencies in scan')
376
+ .option('--snyk', 'include Snyk scan (requires snyk CLI)')
377
+ .action(async (options, command) => {
378
+ try {
379
+ const globalOptions = command.parent.opts();
380
+ const formatter = new OutputFormatter(
381
+ options.format as OutputFormat,
382
+ !globalOptions.noColor
383
+ );
384
+
385
+ const securityCommand = new SecurityCommand(formatter);
386
+
387
+ await securityCommand.execute({
388
+ workspace: globalOptions.workspace,
389
+ format: options.format,
390
+ audit: options.audit,
391
+ fixVulns: options.fixVulns,
392
+ severity: options.severity,
393
+ includeDev: options.includeDev,
394
+ snyk: options.snyk,
395
+ verbose: globalOptions.verbose,
396
+ color: !globalOptions.noColor,
397
+ });
398
+ } catch (error) {
399
+ console.error(chalk.red('❌ Error:'), error);
400
+ process.exit(1);
401
+ }
402
+ });
403
+
404
+ // Init command
405
+ program
406
+ .command('init')
407
+ .alias('i')
408
+ .description('initialize PCU configuration and PNPM workspace')
409
+ .option('--force', 'overwrite existing configuration file')
410
+ .option('--full', 'generate full configuration with all options')
411
+ .option(
412
+ '--create-workspace',
413
+ 'create PNPM workspace structure if missing (default: true)',
414
+ true
415
+ )
416
+ .option('--no-create-workspace', 'skip creating PNPM workspace structure')
417
+ .option('-f, --format <type>', 'output format: table, json, yaml, minimal', 'table')
418
+ .action(async (options, command) => {
419
+ try {
420
+ const globalOptions = command.parent.opts();
421
+ const initCommand = new InitCommand();
422
+
423
+ await initCommand.execute({
424
+ workspace: globalOptions.workspace,
425
+ force: options.force,
426
+ full: options.full,
427
+ createWorkspace: options.createWorkspace,
428
+ verbose: globalOptions.verbose,
429
+ color: !globalOptions.noColor,
430
+ });
431
+ } catch (error) {
432
+ console.error(chalk.red('❌ Error:'), error);
433
+ process.exit(1);
434
+ }
435
+ });
436
+
437
+ // Add help command
438
+ program
439
+ .command('help')
440
+ .alias('h')
441
+ .argument('[command]', 'command to get help for')
442
+ .description('display help for command')
443
+ .action((command) => {
444
+ if (command) {
445
+ const cmd = program.commands.find((c) => c.name() === command);
446
+ if (cmd) {
447
+ cmd.help();
448
+ } else {
449
+ console.log(chalk.red(`Unknown command: ${command}`));
450
+ }
451
+ } else {
452
+ program.help();
453
+ }
454
+ });
455
+
456
+ // Let commander handle help and version normally
457
+ // program.exitOverride() removed to fix help/version output
458
+
459
+ // Handle shorthand options and single-letter commands by rewriting arguments
460
+ const args = [...process.argv];
461
+ // Map single-letter command 'i' -> init (changed from interactive mode)
462
+ if (
463
+ args.includes('i') &&
464
+ !args.some(
465
+ (a) =>
466
+ a === 'init' ||
467
+ a === 'update' ||
468
+ a === '-u' ||
469
+ a === '--update' ||
470
+ a === '-i' ||
471
+ a === '--interactive'
472
+ )
473
+ ) {
474
+ const index = args.findIndex((arg) => arg === 'i');
475
+ args.splice(index, 1, 'init');
476
+ }
477
+
478
+ if (args.includes('-u') || args.includes('--update')) {
479
+ const index = args.findIndex((arg) => arg === '-u' || arg === '--update');
480
+ args.splice(index, 1, 'update');
481
+ } else if (
482
+ (args.includes('-i') || args.includes('--interactive')) &&
483
+ !args.some((a) => a === 'update' || a === '-u' || a === '--update')
484
+ ) {
485
+ // Map standalone -i to `update -i`
486
+ const index = args.findIndex((arg) => arg === '-i' || arg === '--interactive');
487
+ // Replace the flag position with 'update' and keep the flag after it
488
+ args.splice(index, 1, 'update', '-i');
489
+ } else if (args.includes('-c') || args.includes('--check')) {
490
+ const index = args.findIndex((arg) => arg === '-c' || arg === '--check');
491
+ args.splice(index, 1, 'check');
492
+ } else if (args.includes('-a') || args.includes('--analyze')) {
493
+ const index = args.findIndex((arg) => arg === '-a' || arg === '--analyze');
494
+ args.splice(index, 1, 'analyze');
495
+ } else if (args.includes('-s') || args.includes('--workspace-info')) {
496
+ const index = args.findIndex((arg) => arg === '-s' || arg === '--workspace-info');
497
+ args.splice(index, 1, 'workspace');
498
+ } else if (args.includes('-t') || args.includes('--theme')) {
499
+ const index = args.findIndex((arg) => arg === '-t' || arg === '--theme');
500
+ args.splice(index, 1, 'theme');
501
+ } else if (args.includes('--security-audit')) {
502
+ const index = args.findIndex((arg) => arg === '--security-audit');
503
+ args.splice(index, 1, 'security');
504
+ } else if (args.includes('--security-fix')) {
505
+ const index = args.findIndex((arg) => arg === '--security-fix');
506
+ args.splice(index, 1, 'security', '--fix-vulns');
507
+ }
508
+
509
+ // Show help if no arguments provided
510
+ if (args.length <= 2) {
511
+ program.help();
512
+ }
513
+
514
+ // Handle custom --version with update checking
515
+ if (args.includes('--version')) {
516
+ console.log(packageJson.version);
517
+
518
+ // Check for updates if not in CI and enabled in config
519
+ if (VersionChecker.shouldCheckForUpdates() && config.advanced?.checkForUpdates !== false) {
520
+ try {
521
+ console.log(chalk.gray('Checking for updates...'));
522
+ const versionResult = await VersionChecker.checkVersion(packageJson.version, {
523
+ skipPrompt: false,
524
+ timeout: 5000, // Longer timeout for explicit version check
525
+ });
526
+
527
+ if (versionResult.shouldPrompt) {
528
+ const didUpdate = await VersionChecker.promptAndUpdate(versionResult);
529
+ if (didUpdate) {
530
+ console.log(chalk.blue('Please run your command again to use the updated version.'));
531
+ process.exit(0);
532
+ }
533
+ } else if (versionResult.isLatest) {
534
+ console.log(chalk.green('You are using the latest version!'));
535
+ }
536
+ } catch (error) {
537
+ // Silently fail update check for version command
538
+ if (args.includes('-v') || args.includes('--verbose')) {
539
+ console.warn(chalk.yellow('⚠️ Could not check for updates:'), error);
540
+ }
541
+ }
542
+ }
543
+
544
+ process.exit(0);
545
+ }
546
+
547
+ // Parse command line arguments
548
+ try {
549
+ await program.parseAsync(args);
550
+ } catch (error) {
551
+ console.error(chalk.red('❌ Unexpected error:'), error);
552
+ if (error instanceof Error && error.stack) {
553
+ console.error(chalk.gray(error.stack));
554
+ }
555
+ process.exit(1);
556
+ }
557
+ }
558
+
559
+ // Run the CLI if this file is executed directly
560
+ if (import.meta.url === `file://${process.argv[1]}`) {
561
+ main().catch((error) => {
562
+ console.error(chalk.red('❌ Fatal error:'), error);
563
+ process.exit(1);
564
+ });
565
+ }