pnpm-catalog-updates 0.7.19 → 1.0.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.
- package/dist/index.js +10212 -6761
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
- package/src/cli/commands/checkCommand.ts +62 -62
- package/src/cli/commands/initCommand.ts +90 -90
- package/src/cli/commands/securityCommand.ts +172 -172
- package/src/cli/commands/updateCommand.ts +227 -68
- package/src/cli/formatters/outputFormatter.ts +500 -280
- package/src/cli/formatters/progressBar.ts +228 -228
- package/src/cli/index.ts +407 -167
- package/src/cli/interactive/interactivePrompts.ts +100 -98
- package/src/cli/options/globalOptions.ts +143 -86
- package/src/cli/options/index.ts +1 -1
- package/src/cli/themes/colorTheme.ts +70 -70
- package/src/cli/validators/commandValidator.ts +118 -122
- package/src/cli/validators/index.ts +1 -1
- package/src/index.ts +1 -1
package/src/cli/index.ts
CHANGED
|
@@ -7,73 +7,90 @@
|
|
|
7
7
|
* This is the main entry point that handles command parsing and execution.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
10
|
+
import { readFileSync } from 'node:fs'
|
|
11
|
+
import { dirname, join } from 'node:path'
|
|
12
|
+
import { fileURLToPath } from 'node:url'
|
|
13
13
|
// Services and Dependencies
|
|
14
|
+
import type { AnalysisType } from '@pcu/core'
|
|
14
15
|
import {
|
|
16
|
+
AIAnalysisService,
|
|
17
|
+
AIDetector,
|
|
15
18
|
CatalogUpdateService,
|
|
16
19
|
FileSystemService,
|
|
17
20
|
FileWorkspaceRepository,
|
|
18
21
|
NpmRegistryService,
|
|
19
22
|
WorkspaceService,
|
|
20
|
-
} from '@pcu/core'
|
|
23
|
+
} from '@pcu/core'
|
|
21
24
|
// CLI Commands
|
|
22
|
-
import { ConfigLoader, VersionChecker } from '@pcu/utils'
|
|
23
|
-
import chalk from 'chalk'
|
|
24
|
-
import { Command } from 'commander'
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import { StyledText, ThemeManager } from './themes/colorTheme.js';
|
|
25
|
+
import { ConfigLoader, VersionChecker } from '@pcu/utils'
|
|
26
|
+
import chalk from 'chalk'
|
|
27
|
+
import { Command } from 'commander'
|
|
28
|
+
import { CheckCommand } from './commands/checkCommand.js'
|
|
29
|
+
import { InitCommand } from './commands/initCommand.js'
|
|
30
|
+
import { SecurityCommand } from './commands/securityCommand.js'
|
|
31
|
+
import { UpdateCommand } from './commands/updateCommand.js'
|
|
32
|
+
import { type OutputFormat, OutputFormatter } from './formatters/outputFormatter.js'
|
|
33
|
+
import { InteractivePrompts } from './interactive/interactivePrompts.js'
|
|
34
|
+
import { StyledText, ThemeManager } from './themes/colorTheme.js'
|
|
33
35
|
|
|
34
36
|
// 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'))
|
|
37
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
38
|
+
const __dirname = dirname(__filename)
|
|
39
|
+
const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'))
|
|
38
40
|
|
|
39
41
|
/**
|
|
40
42
|
* Create service dependencies with configuration support
|
|
41
43
|
*/
|
|
42
44
|
function createServices(workspacePath?: string) {
|
|
43
|
-
const fileSystemService = new FileSystemService()
|
|
44
|
-
const workspaceRepository = new FileWorkspaceRepository(fileSystemService)
|
|
45
|
+
const fileSystemService = new FileSystemService()
|
|
46
|
+
const workspaceRepository = new FileWorkspaceRepository(fileSystemService)
|
|
45
47
|
// Use factory method to create CatalogUpdateService with configuration
|
|
46
48
|
const catalogUpdateService = CatalogUpdateService.createWithConfig(
|
|
47
49
|
workspaceRepository,
|
|
48
50
|
workspacePath
|
|
49
|
-
)
|
|
50
|
-
const workspaceService = new WorkspaceService(workspaceRepository)
|
|
51
|
+
)
|
|
52
|
+
const workspaceService = new WorkspaceService(workspaceRepository)
|
|
51
53
|
|
|
52
54
|
return {
|
|
53
55
|
fileSystemService,
|
|
54
56
|
workspaceRepository,
|
|
55
57
|
catalogUpdateService,
|
|
56
58
|
workspaceService,
|
|
57
|
-
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function parseBooleanFlag(value: unknown): boolean {
|
|
63
|
+
if (value === undefined || value === null) return false
|
|
64
|
+
if (typeof value === 'boolean') return value
|
|
65
|
+
if (typeof value === 'number') return value !== 0
|
|
66
|
+
if (typeof value === 'string') {
|
|
67
|
+
const normalized = value.trim().toLowerCase()
|
|
68
|
+
if (normalized === '') return false
|
|
69
|
+
if (['false', '0', 'no', 'off', 'n'].includes(normalized)) return false
|
|
70
|
+
if (['true', '1', 'yes', 'on', 'y'].includes(normalized)) return true
|
|
71
|
+
// Commander env() 会把任意非空字符串塞进来;未知字符串按“启用”处理
|
|
72
|
+
return true
|
|
73
|
+
}
|
|
74
|
+
return Boolean(value)
|
|
58
75
|
}
|
|
59
76
|
|
|
60
77
|
/**
|
|
61
78
|
* Main CLI function
|
|
62
79
|
*/
|
|
63
80
|
export async function main(): Promise<void> {
|
|
64
|
-
const program = new Command()
|
|
81
|
+
const program = new Command()
|
|
65
82
|
|
|
66
83
|
// Parse arguments first to get workspace path
|
|
67
|
-
let workspacePath: string | undefined
|
|
84
|
+
let workspacePath: string | undefined
|
|
68
85
|
|
|
69
86
|
// Extract workspace path from arguments for service creation
|
|
70
|
-
const workspaceIndex = process.argv.findIndex((arg) => arg === '-w' || arg === '--workspace')
|
|
87
|
+
const workspaceIndex = process.argv.findIndex((arg) => arg === '-w' || arg === '--workspace')
|
|
71
88
|
if (workspaceIndex !== -1 && workspaceIndex + 1 < process.argv.length) {
|
|
72
|
-
workspacePath = process.argv[workspaceIndex + 1]
|
|
89
|
+
workspacePath = process.argv[workspaceIndex + 1]
|
|
73
90
|
}
|
|
74
91
|
|
|
75
92
|
// Load configuration to check if version updates are enabled
|
|
76
|
-
const config = ConfigLoader.loadConfig(workspacePath || process.cwd())
|
|
93
|
+
const config = ConfigLoader.loadConfig(workspacePath || process.cwd())
|
|
77
94
|
|
|
78
95
|
// Check for version updates (skip in CI environments or if disabled)
|
|
79
96
|
if (VersionChecker.shouldCheckForUpdates() && config.advanced?.checkForUpdates !== false) {
|
|
@@ -81,26 +98,26 @@ export async function main(): Promise<void> {
|
|
|
81
98
|
const versionResult = await VersionChecker.checkVersion(packageJson.version, {
|
|
82
99
|
skipPrompt: false,
|
|
83
100
|
timeout: 3000, // Short timeout to not delay CLI startup
|
|
84
|
-
})
|
|
101
|
+
})
|
|
85
102
|
|
|
86
103
|
if (versionResult.shouldPrompt) {
|
|
87
|
-
const didUpdate = await VersionChecker.promptAndUpdate(versionResult)
|
|
104
|
+
const didUpdate = await VersionChecker.promptAndUpdate(versionResult)
|
|
88
105
|
if (didUpdate) {
|
|
89
106
|
// 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)
|
|
107
|
+
console.log(chalk.blue('Please run your command again to use the updated version.'))
|
|
108
|
+
process.exit(0)
|
|
92
109
|
}
|
|
93
110
|
}
|
|
94
111
|
} catch (error) {
|
|
95
112
|
// Silently fail version check to not interrupt CLI usage (only show warning in verbose mode)
|
|
96
113
|
if (process.argv.includes('-v') || process.argv.includes('--verbose')) {
|
|
97
|
-
console.warn(chalk.yellow('⚠️ Could not check for updates:'), error)
|
|
114
|
+
console.warn(chalk.yellow('⚠️ Could not check for updates:'), error)
|
|
98
115
|
}
|
|
99
116
|
}
|
|
100
117
|
}
|
|
101
118
|
|
|
102
119
|
// Create services with workspace path for configuration loading
|
|
103
|
-
const services = createServices(workspacePath)
|
|
120
|
+
const services = createServices(workspacePath)
|
|
104
121
|
|
|
105
122
|
// Configure the main command
|
|
106
123
|
program
|
|
@@ -116,7 +133,7 @@ export async function main(): Promise<void> {
|
|
|
116
133
|
.option('-s, --workspace-info', 'shorthand for workspace command')
|
|
117
134
|
.option('-t, --theme', 'shorthand for theme command')
|
|
118
135
|
.option('--security-audit', 'shorthand for security command')
|
|
119
|
-
.option('--security-fix', 'shorthand for security --fix-vulns command')
|
|
136
|
+
.option('--security-fix', 'shorthand for security --fix-vulns command')
|
|
120
137
|
|
|
121
138
|
// Check command
|
|
122
139
|
program
|
|
@@ -135,8 +152,8 @@ export async function main(): Promise<void> {
|
|
|
135
152
|
.option('--exclude <pattern>', 'exclude packages matching pattern', [])
|
|
136
153
|
.action(async (options, command) => {
|
|
137
154
|
try {
|
|
138
|
-
const globalOptions = command.parent.opts()
|
|
139
|
-
const checkCommand = new CheckCommand(services.catalogUpdateService)
|
|
155
|
+
const globalOptions = command.parent.opts()
|
|
156
|
+
const checkCommand = new CheckCommand(services.catalogUpdateService)
|
|
140
157
|
|
|
141
158
|
await checkCommand.execute({
|
|
142
159
|
workspace: globalOptions.workspace,
|
|
@@ -152,12 +169,13 @@ export async function main(): Promise<void> {
|
|
|
152
169
|
: [options.exclude].filter(Boolean),
|
|
153
170
|
verbose: globalOptions.verbose,
|
|
154
171
|
color: !globalOptions.noColor,
|
|
155
|
-
})
|
|
172
|
+
})
|
|
173
|
+
process.exit(0)
|
|
156
174
|
} catch (error) {
|
|
157
|
-
console.error(chalk.red('❌ Error:'), error)
|
|
158
|
-
process.exit(1)
|
|
175
|
+
console.error(chalk.red('❌ Error:'), error)
|
|
176
|
+
process.exit(1)
|
|
159
177
|
}
|
|
160
|
-
})
|
|
178
|
+
})
|
|
161
179
|
|
|
162
180
|
// Update command
|
|
163
181
|
program
|
|
@@ -178,10 +196,18 @@ export async function main(): Promise<void> {
|
|
|
178
196
|
.option('--prerelease', 'include prerelease versions')
|
|
179
197
|
.option('-b, --create-backup', 'create backup files before updating')
|
|
180
198
|
.option('-f, --format <type>', 'output format: table, json, yaml, minimal', 'table')
|
|
199
|
+
.option('--ai', 'enable AI-powered batch analysis for all updates')
|
|
200
|
+
.option('--provider <name>', 'AI provider: auto, claude, gemini, codex', 'auto')
|
|
201
|
+
.option(
|
|
202
|
+
'--analysis-type <type>',
|
|
203
|
+
'AI analysis type: impact, security, compatibility, recommend',
|
|
204
|
+
'impact'
|
|
205
|
+
)
|
|
206
|
+
.option('--skip-cache', 'skip AI analysis cache')
|
|
181
207
|
.action(async (options, command) => {
|
|
182
208
|
try {
|
|
183
|
-
const globalOptions = command.parent.opts()
|
|
184
|
-
const updateCommand = new UpdateCommand(services.catalogUpdateService)
|
|
209
|
+
const globalOptions = command.parent.opts()
|
|
210
|
+
const updateCommand = new UpdateCommand(services.catalogUpdateService)
|
|
185
211
|
|
|
186
212
|
await updateCommand.execute({
|
|
187
213
|
workspace: globalOptions.workspace,
|
|
@@ -201,52 +227,142 @@ export async function main(): Promise<void> {
|
|
|
201
227
|
createBackup: options.createBackup,
|
|
202
228
|
verbose: globalOptions.verbose,
|
|
203
229
|
color: !globalOptions.noColor,
|
|
204
|
-
|
|
230
|
+
// AI batch analysis options
|
|
231
|
+
ai: parseBooleanFlag(options.ai),
|
|
232
|
+
provider: options.provider,
|
|
233
|
+
analysisType: options.analysisType as AnalysisType,
|
|
234
|
+
skipCache: parseBooleanFlag(options.skipCache),
|
|
235
|
+
})
|
|
236
|
+
process.exit(0)
|
|
205
237
|
} catch (error) {
|
|
206
|
-
console.error(chalk.red('❌ Error:'), error)
|
|
207
|
-
process.exit(1)
|
|
238
|
+
console.error(chalk.red('❌ Error:'), error)
|
|
239
|
+
process.exit(1)
|
|
208
240
|
}
|
|
209
|
-
})
|
|
241
|
+
})
|
|
210
242
|
|
|
211
243
|
// Analyze command
|
|
212
244
|
program
|
|
213
245
|
.command('analyze')
|
|
214
246
|
.alias('a')
|
|
215
247
|
.description('analyze the impact of updating a specific dependency')
|
|
216
|
-
.argument('<catalog>', 'catalog name')
|
|
217
248
|
.argument('<package>', 'package name')
|
|
218
249
|
.argument('[version]', 'new version (default: latest)')
|
|
250
|
+
.option('--catalog <name>', 'catalog name (auto-detected if not specified)')
|
|
219
251
|
.option('-f, --format <type>', 'output format: table, json, yaml, minimal', 'table')
|
|
220
|
-
.
|
|
252
|
+
.option('--no-ai', 'disable AI-powered analysis')
|
|
253
|
+
.option('--provider <name>', 'AI provider: auto, claude, gemini, codex', 'auto')
|
|
254
|
+
.option(
|
|
255
|
+
'--analysis-type <type>',
|
|
256
|
+
'AI analysis type: impact, security, compatibility, recommend',
|
|
257
|
+
'impact'
|
|
258
|
+
)
|
|
259
|
+
.option('--skip-cache', 'skip AI analysis cache')
|
|
260
|
+
.action(async (packageName, version, options, command) => {
|
|
221
261
|
try {
|
|
222
|
-
const globalOptions = command.parent.opts()
|
|
262
|
+
const globalOptions = command.parent.opts()
|
|
223
263
|
const formatter = new OutputFormatter(
|
|
224
264
|
options.format as OutputFormat,
|
|
225
265
|
!globalOptions.noColor
|
|
226
|
-
)
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
// Auto-detect catalog if not specified
|
|
269
|
+
let catalog = options.catalog
|
|
270
|
+
if (!catalog) {
|
|
271
|
+
console.log(chalk.gray(`🔍 Auto-detecting catalog for ${packageName}...`))
|
|
272
|
+
catalog = await services.catalogUpdateService.findCatalogForPackage(
|
|
273
|
+
packageName,
|
|
274
|
+
globalOptions.workspace
|
|
275
|
+
)
|
|
276
|
+
if (!catalog) {
|
|
277
|
+
console.error(chalk.red(`❌ Package "${packageName}" not found in any catalog`))
|
|
278
|
+
console.log(chalk.gray('Use --catalog <name> to specify the catalog manually'))
|
|
279
|
+
process.exit(1)
|
|
280
|
+
}
|
|
281
|
+
console.log(chalk.gray(` Found in catalog: ${catalog}`))
|
|
282
|
+
}
|
|
227
283
|
|
|
228
284
|
// Get latest version if not specified
|
|
229
|
-
let targetVersion = version
|
|
285
|
+
let targetVersion = version
|
|
230
286
|
if (!targetVersion) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
targetVersion = (await tempRegistryService.getLatestVersion(packageName)).toString();
|
|
287
|
+
const tempRegistryService = new NpmRegistryService()
|
|
288
|
+
targetVersion = (await tempRegistryService.getLatestVersion(packageName)).toString()
|
|
234
289
|
}
|
|
235
290
|
|
|
291
|
+
// Get basic impact analysis first
|
|
236
292
|
const analysis = await services.catalogUpdateService.analyzeImpact(
|
|
237
293
|
catalog,
|
|
238
294
|
packageName,
|
|
239
295
|
targetVersion,
|
|
240
296
|
globalOptions.workspace
|
|
241
|
-
)
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
// AI analysis is enabled by default (use --no-ai to disable)
|
|
300
|
+
const aiEnabled = options.ai !== false
|
|
301
|
+
|
|
302
|
+
if (aiEnabled) {
|
|
303
|
+
console.log(chalk.blue('🤖 Running AI-powered analysis...'))
|
|
304
|
+
|
|
305
|
+
const aiService = new AIAnalysisService({
|
|
306
|
+
config: {
|
|
307
|
+
preferredProvider: options.provider === 'auto' ? 'auto' : options.provider,
|
|
308
|
+
cache: { enabled: !parseBooleanFlag(options.skipCache), ttl: 3600 },
|
|
309
|
+
fallback: { enabled: true, useRuleEngine: true },
|
|
310
|
+
},
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
// Get workspace info
|
|
314
|
+
const workspaceInfo = await services.workspaceService.getWorkspaceInfo(
|
|
315
|
+
globalOptions.workspace
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
// Build packages info for AI analysis
|
|
319
|
+
const packages = [
|
|
320
|
+
{
|
|
321
|
+
name: packageName,
|
|
322
|
+
currentVersion: analysis.currentVersion,
|
|
323
|
+
targetVersion: analysis.proposedVersion,
|
|
324
|
+
updateType: analysis.updateType,
|
|
325
|
+
},
|
|
326
|
+
]
|
|
327
|
+
|
|
328
|
+
// Build workspace info for AI
|
|
329
|
+
const wsInfo = {
|
|
330
|
+
name: workspaceInfo.name,
|
|
331
|
+
path: workspaceInfo.path,
|
|
332
|
+
packageCount: workspaceInfo.packageCount,
|
|
333
|
+
catalogCount: workspaceInfo.catalogCount,
|
|
334
|
+
}
|
|
242
335
|
|
|
243
|
-
|
|
244
|
-
|
|
336
|
+
try {
|
|
337
|
+
const aiResult = await aiService.analyzeUpdates(packages, wsInfo, {
|
|
338
|
+
analysisType: options.analysisType as AnalysisType,
|
|
339
|
+
skipCache: parseBooleanFlag(options.skipCache),
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
// Format and display AI analysis result
|
|
343
|
+
const aiOutput = formatter.formatAIAnalysis(aiResult, analysis)
|
|
344
|
+
console.log(aiOutput)
|
|
345
|
+
process.exit(0)
|
|
346
|
+
} catch (aiError) {
|
|
347
|
+
console.warn(chalk.yellow('⚠️ AI analysis failed, showing basic analysis:'))
|
|
348
|
+
if (globalOptions.verbose) {
|
|
349
|
+
console.warn(chalk.gray(String(aiError)))
|
|
350
|
+
}
|
|
351
|
+
// Fall back to basic analysis
|
|
352
|
+
const formattedOutput = formatter.formatImpactAnalysis(analysis)
|
|
353
|
+
console.log(formattedOutput)
|
|
354
|
+
process.exit(0)
|
|
355
|
+
}
|
|
356
|
+
} else {
|
|
357
|
+
// Standard analysis without AI
|
|
358
|
+
const formattedOutput = formatter.formatImpactAnalysis(analysis)
|
|
359
|
+
console.log(formattedOutput)
|
|
360
|
+
}
|
|
245
361
|
} catch (error) {
|
|
246
|
-
console.error(chalk.red('❌ Error:'), error)
|
|
247
|
-
process.exit(1)
|
|
362
|
+
console.error(chalk.red('❌ Error:'), error)
|
|
363
|
+
process.exit(1)
|
|
248
364
|
}
|
|
249
|
-
})
|
|
365
|
+
})
|
|
250
366
|
|
|
251
367
|
// Workspace command
|
|
252
368
|
program
|
|
@@ -258,39 +374,44 @@ export async function main(): Promise<void> {
|
|
|
258
374
|
.option('-f, --format <type>', 'output format: table, json, yaml, minimal', 'table')
|
|
259
375
|
.action(async (options, command) => {
|
|
260
376
|
try {
|
|
261
|
-
const globalOptions = command.parent.opts()
|
|
377
|
+
const globalOptions = command.parent.opts()
|
|
262
378
|
const formatter = new OutputFormatter(
|
|
263
379
|
options.format as OutputFormat,
|
|
264
380
|
!globalOptions.noColor
|
|
265
|
-
)
|
|
381
|
+
)
|
|
266
382
|
|
|
267
383
|
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(
|
|
384
|
+
const report = await services.workspaceService.validateWorkspace(globalOptions.workspace)
|
|
385
|
+
const formattedOutput = formatter.formatValidationReport(report)
|
|
386
|
+
console.log(formattedOutput)
|
|
387
|
+
process.exit(0)
|
|
388
|
+
if (!report.isValid) {
|
|
389
|
+
process.exit(1)
|
|
390
|
+
}
|
|
272
391
|
} else if (options.stats) {
|
|
273
|
-
const stats = await services.workspaceService.getWorkspaceStats(globalOptions.workspace)
|
|
274
|
-
const formattedOutput = formatter.formatWorkspaceStats(stats)
|
|
275
|
-
console.log(formattedOutput)
|
|
392
|
+
const stats = await services.workspaceService.getWorkspaceStats(globalOptions.workspace)
|
|
393
|
+
const formattedOutput = formatter.formatWorkspaceStats(stats)
|
|
394
|
+
console.log(formattedOutput)
|
|
395
|
+
process.exit(0)
|
|
276
396
|
} 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'))
|
|
397
|
+
const info = await services.workspaceService.getWorkspaceInfo(globalOptions.workspace)
|
|
398
|
+
console.log(formatter.formatMessage(`Workspace: ${info.name}`, 'info'))
|
|
399
|
+
console.log(formatter.formatMessage(`Path: ${info.path}`, 'info'))
|
|
400
|
+
console.log(formatter.formatMessage(`Packages: ${info.packageCount}`, 'info'))
|
|
401
|
+
console.log(formatter.formatMessage(`Catalogs: ${info.catalogCount}`, 'info'))
|
|
282
402
|
|
|
283
403
|
if (info.catalogNames.length > 0) {
|
|
284
404
|
console.log(
|
|
285
405
|
formatter.formatMessage(`Catalog names: ${info.catalogNames.join(', ')}`, 'info')
|
|
286
|
-
)
|
|
406
|
+
)
|
|
287
407
|
}
|
|
408
|
+
process.exit(0)
|
|
288
409
|
}
|
|
289
410
|
} catch (error) {
|
|
290
|
-
console.error(chalk.red('❌ Error:'), error)
|
|
291
|
-
process.exit(1)
|
|
411
|
+
console.error(chalk.red('❌ Error:'), error)
|
|
412
|
+
process.exit(1)
|
|
292
413
|
}
|
|
293
|
-
})
|
|
414
|
+
})
|
|
294
415
|
|
|
295
416
|
// Theme command
|
|
296
417
|
program
|
|
@@ -303,65 +424,65 @@ export async function main(): Promise<void> {
|
|
|
303
424
|
.action(async (options, _command) => {
|
|
304
425
|
try {
|
|
305
426
|
if (options.list) {
|
|
306
|
-
const themes = ThemeManager.listThemes()
|
|
307
|
-
console.log(StyledText.iconInfo('Available themes:'))
|
|
427
|
+
const themes = ThemeManager.listThemes()
|
|
428
|
+
console.log(StyledText.iconInfo('Available themes:'))
|
|
308
429
|
themes.forEach((theme) => {
|
|
309
|
-
console.log(` • ${theme}`)
|
|
310
|
-
})
|
|
311
|
-
return
|
|
430
|
+
console.log(` • ${theme}`)
|
|
431
|
+
})
|
|
432
|
+
return
|
|
312
433
|
}
|
|
313
434
|
|
|
314
435
|
if (options.set) {
|
|
315
|
-
const themes = ThemeManager.listThemes()
|
|
436
|
+
const themes = ThemeManager.listThemes()
|
|
316
437
|
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)
|
|
438
|
+
console.error(StyledText.iconError(`Invalid theme: ${options.set}`))
|
|
439
|
+
console.log(StyledText.muted(`Available themes: ${themes.join(', ')}`))
|
|
440
|
+
process.exit(1)
|
|
320
441
|
}
|
|
321
442
|
|
|
322
|
-
ThemeManager.setTheme(options.set)
|
|
323
|
-
console.log(StyledText.iconSuccess(`Theme set to: ${options.set}`))
|
|
443
|
+
ThemeManager.setTheme(options.set)
|
|
444
|
+
console.log(StyledText.iconSuccess(`Theme set to: ${options.set}`))
|
|
324
445
|
|
|
325
446
|
// 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')}`)
|
|
447
|
+
console.log('\nTheme preview:')
|
|
448
|
+
const theme = ThemeManager.getTheme()
|
|
449
|
+
console.log(` ${theme.success('✓ Success message')}`)
|
|
450
|
+
console.log(` ${theme.warning('⚠ Warning message')}`)
|
|
451
|
+
console.log(` ${theme.error('✗ Error message')}`)
|
|
452
|
+
console.log(` ${theme.info('ℹ Info message')}`)
|
|
332
453
|
console.log(
|
|
333
454
|
` ${theme.major('Major update')} | ${theme.minor('Minor update')} | ${theme.patch('Patch update')}`
|
|
334
|
-
)
|
|
335
|
-
return
|
|
455
|
+
)
|
|
456
|
+
return
|
|
336
457
|
}
|
|
337
458
|
|
|
338
459
|
if (options.interactive) {
|
|
339
|
-
const interactivePrompts = new InteractivePrompts()
|
|
340
|
-
const config = await interactivePrompts.configurationWizard()
|
|
460
|
+
const interactivePrompts = new InteractivePrompts()
|
|
461
|
+
const config = await interactivePrompts.configurationWizard()
|
|
341
462
|
|
|
342
463
|
if (config.theme) {
|
|
343
|
-
ThemeManager.setTheme(config.theme)
|
|
344
|
-
console.log(StyledText.iconSuccess(`Theme configured: ${config.theme}`))
|
|
464
|
+
ThemeManager.setTheme(config.theme)
|
|
465
|
+
console.log(StyledText.iconSuccess(`Theme configured: ${config.theme}`))
|
|
345
466
|
}
|
|
346
|
-
return
|
|
467
|
+
return
|
|
347
468
|
}
|
|
348
469
|
|
|
349
470
|
// 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:')
|
|
471
|
+
const currentTheme = ThemeManager.getTheme()
|
|
472
|
+
console.log(StyledText.iconInfo('Current theme settings:'))
|
|
473
|
+
console.log(` Theme: ${currentTheme ? 'custom' : 'default'}`)
|
|
474
|
+
console.log('\nAvailable themes:')
|
|
354
475
|
ThemeManager.listThemes().forEach((theme) => {
|
|
355
|
-
console.log(` • ${theme}`)
|
|
356
|
-
})
|
|
476
|
+
console.log(` • ${theme}`)
|
|
477
|
+
})
|
|
357
478
|
console.log(
|
|
358
479
|
StyledText.muted('\nUse --set <theme> to change theme or --interactive for guided setup')
|
|
359
|
-
)
|
|
480
|
+
)
|
|
360
481
|
} catch (error) {
|
|
361
|
-
console.error(StyledText.iconError('Error configuring theme:'), error)
|
|
362
|
-
process.exit(1)
|
|
482
|
+
console.error(StyledText.iconError('Error configuring theme:'), error)
|
|
483
|
+
process.exit(1)
|
|
363
484
|
}
|
|
364
|
-
})
|
|
485
|
+
})
|
|
365
486
|
|
|
366
487
|
// Security command
|
|
367
488
|
program
|
|
@@ -376,13 +497,13 @@ export async function main(): Promise<void> {
|
|
|
376
497
|
.option('--snyk', 'include Snyk scan (requires snyk CLI)')
|
|
377
498
|
.action(async (options, command) => {
|
|
378
499
|
try {
|
|
379
|
-
const globalOptions = command.parent.opts()
|
|
500
|
+
const globalOptions = command.parent.opts()
|
|
380
501
|
const formatter = new OutputFormatter(
|
|
381
502
|
options.format as OutputFormat,
|
|
382
503
|
!globalOptions.noColor
|
|
383
|
-
)
|
|
504
|
+
)
|
|
384
505
|
|
|
385
|
-
const securityCommand = new SecurityCommand(formatter)
|
|
506
|
+
const securityCommand = new SecurityCommand(formatter)
|
|
386
507
|
|
|
387
508
|
await securityCommand.execute({
|
|
388
509
|
workspace: globalOptions.workspace,
|
|
@@ -394,12 +515,13 @@ export async function main(): Promise<void> {
|
|
|
394
515
|
snyk: options.snyk,
|
|
395
516
|
verbose: globalOptions.verbose,
|
|
396
517
|
color: !globalOptions.noColor,
|
|
397
|
-
})
|
|
518
|
+
})
|
|
519
|
+
process.exit(0)
|
|
398
520
|
} catch (error) {
|
|
399
|
-
console.error(chalk.red('❌ Error:'), error)
|
|
400
|
-
process.exit(1)
|
|
521
|
+
console.error(chalk.red('❌ Error:'), error)
|
|
522
|
+
process.exit(1)
|
|
401
523
|
}
|
|
402
|
-
})
|
|
524
|
+
})
|
|
403
525
|
|
|
404
526
|
// Init command
|
|
405
527
|
program
|
|
@@ -417,8 +539,8 @@ export async function main(): Promise<void> {
|
|
|
417
539
|
.option('-f, --format <type>', 'output format: table, json, yaml, minimal', 'table')
|
|
418
540
|
.action(async (options, command) => {
|
|
419
541
|
try {
|
|
420
|
-
const globalOptions = command.parent.opts()
|
|
421
|
-
const initCommand = new InitCommand()
|
|
542
|
+
const globalOptions = command.parent.opts()
|
|
543
|
+
const initCommand = new InitCommand()
|
|
422
544
|
|
|
423
545
|
await initCommand.execute({
|
|
424
546
|
workspace: globalOptions.workspace,
|
|
@@ -427,12 +549,130 @@ export async function main(): Promise<void> {
|
|
|
427
549
|
createWorkspace: options.createWorkspace,
|
|
428
550
|
verbose: globalOptions.verbose,
|
|
429
551
|
color: !globalOptions.noColor,
|
|
430
|
-
})
|
|
552
|
+
})
|
|
553
|
+
process.exit(0)
|
|
554
|
+
} catch (error) {
|
|
555
|
+
console.error(chalk.red('❌ Error:'), error)
|
|
556
|
+
process.exit(1)
|
|
557
|
+
}
|
|
558
|
+
})
|
|
559
|
+
|
|
560
|
+
// AI command - check AI provider status and availability
|
|
561
|
+
program
|
|
562
|
+
.command('ai')
|
|
563
|
+
.description('check AI provider status and availability')
|
|
564
|
+
.option('--status', 'show status of all AI providers (default)')
|
|
565
|
+
.option('--test', 'test AI analysis with a sample request')
|
|
566
|
+
.option('--cache-stats', 'show AI analysis cache statistics')
|
|
567
|
+
.option('--clear-cache', 'clear AI analysis cache')
|
|
568
|
+
.action(async (options) => {
|
|
569
|
+
try {
|
|
570
|
+
const aiDetector = new AIDetector()
|
|
571
|
+
|
|
572
|
+
if (options.clearCache) {
|
|
573
|
+
// Import the cache singleton
|
|
574
|
+
const { analysisCache } = await import('@pcu/core')
|
|
575
|
+
analysisCache.clear()
|
|
576
|
+
console.log(chalk.green('✅ AI analysis cache cleared'))
|
|
577
|
+
process.exit(0)
|
|
578
|
+
return
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (options.cacheStats) {
|
|
582
|
+
const { analysisCache } = await import('@pcu/core')
|
|
583
|
+
const stats = analysisCache.getStats()
|
|
584
|
+
console.log(chalk.blue('📊 AI Analysis Cache Statistics'))
|
|
585
|
+
console.log(chalk.gray('─────────────────────────────────'))
|
|
586
|
+
console.log(` Total entries: ${chalk.cyan(stats.totalEntries)}`)
|
|
587
|
+
console.log(` Cache hits: ${chalk.green(stats.hits)}`)
|
|
588
|
+
console.log(` Cache misses: ${chalk.yellow(stats.misses)}`)
|
|
589
|
+
console.log(` Hit rate: ${chalk.cyan(`${(stats.hitRate * 100).toFixed(1)}%`)}`)
|
|
590
|
+
process.exit(0)
|
|
591
|
+
return
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
if (options.test) {
|
|
595
|
+
console.log(chalk.blue('🧪 Testing AI analysis...'))
|
|
596
|
+
|
|
597
|
+
const aiService = new AIAnalysisService({
|
|
598
|
+
config: {
|
|
599
|
+
fallback: { enabled: true, useRuleEngine: true },
|
|
600
|
+
},
|
|
601
|
+
})
|
|
602
|
+
|
|
603
|
+
const testPackages = [
|
|
604
|
+
{
|
|
605
|
+
name: 'lodash',
|
|
606
|
+
currentVersion: '4.17.20',
|
|
607
|
+
targetVersion: '4.17.21',
|
|
608
|
+
updateType: 'patch' as const,
|
|
609
|
+
},
|
|
610
|
+
]
|
|
611
|
+
|
|
612
|
+
const testWorkspaceInfo = {
|
|
613
|
+
name: 'test-workspace',
|
|
614
|
+
path: process.cwd(),
|
|
615
|
+
packageCount: 1,
|
|
616
|
+
catalogCount: 1,
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
try {
|
|
620
|
+
const result = await aiService.analyzeUpdates(testPackages, testWorkspaceInfo, {
|
|
621
|
+
analysisType: 'impact',
|
|
622
|
+
})
|
|
623
|
+
console.log(chalk.green('✅ AI analysis test successful!'))
|
|
624
|
+
console.log(chalk.gray('─────────────────────────────────'))
|
|
625
|
+
console.log(` Provider: ${chalk.cyan(result.provider)}`)
|
|
626
|
+
console.log(` Confidence: ${chalk.cyan(`${(result.confidence * 100).toFixed(0)}%`)}`)
|
|
627
|
+
console.log(` Summary: ${result.summary}`)
|
|
628
|
+
} catch (error) {
|
|
629
|
+
console.log(chalk.yellow('⚠️ AI analysis test failed:'))
|
|
630
|
+
console.log(chalk.gray(String(error)))
|
|
631
|
+
}
|
|
632
|
+
process.exit(0)
|
|
633
|
+
return
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Default: show status
|
|
637
|
+
console.log(chalk.blue('🤖 AI Provider Status'))
|
|
638
|
+
console.log(chalk.gray('─────────────────────────────────'))
|
|
639
|
+
|
|
640
|
+
const summary = await aiDetector.getDetectionSummary()
|
|
641
|
+
console.log(summary)
|
|
642
|
+
|
|
643
|
+
const providers = await aiDetector.detectAvailableProviders()
|
|
644
|
+
console.log('')
|
|
645
|
+
console.log(chalk.blue('📋 Provider Details'))
|
|
646
|
+
console.log(chalk.gray('─────────────────────────────────'))
|
|
647
|
+
|
|
648
|
+
for (const provider of providers) {
|
|
649
|
+
const statusIcon = provider.available ? chalk.green('✓') : chalk.red('✗')
|
|
650
|
+
const statusText = provider.available ? chalk.green('Available') : chalk.gray('Not found')
|
|
651
|
+
const priorityText = chalk.gray(`(priority: ${provider.priority})`)
|
|
652
|
+
|
|
653
|
+
console.log(
|
|
654
|
+
` ${statusIcon} ${chalk.cyan(provider.name)} - ${statusText} ${priorityText}`
|
|
655
|
+
)
|
|
656
|
+
|
|
657
|
+
if (provider.available && provider.path) {
|
|
658
|
+
console.log(chalk.gray(` Path: ${provider.path}`))
|
|
659
|
+
}
|
|
660
|
+
if (provider.available && provider.version) {
|
|
661
|
+
console.log(chalk.gray(` Version: ${provider.version}`))
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
const best = await aiDetector.getBestProvider()
|
|
666
|
+
if (best) {
|
|
667
|
+
console.log('')
|
|
668
|
+
console.log(chalk.green(`✨ Best available provider: ${best.name}`))
|
|
669
|
+
}
|
|
670
|
+
process.exit(0)
|
|
431
671
|
} catch (error) {
|
|
432
|
-
console.error(chalk.red('❌ Error:'), error)
|
|
433
|
-
process.exit(1)
|
|
672
|
+
console.error(chalk.red('❌ Error:'), error)
|
|
673
|
+
process.exit(1)
|
|
434
674
|
}
|
|
435
|
-
})
|
|
675
|
+
})
|
|
436
676
|
|
|
437
677
|
// Add help command
|
|
438
678
|
program
|
|
@@ -442,22 +682,22 @@ export async function main(): Promise<void> {
|
|
|
442
682
|
.description('display help for command')
|
|
443
683
|
.action((command) => {
|
|
444
684
|
if (command) {
|
|
445
|
-
const cmd = program.commands.find((c) => c.name() === command)
|
|
685
|
+
const cmd = program.commands.find((c) => c.name() === command)
|
|
446
686
|
if (cmd) {
|
|
447
|
-
cmd.help()
|
|
687
|
+
cmd.help()
|
|
448
688
|
} else {
|
|
449
|
-
console.log(chalk.red(`Unknown command: ${command}`))
|
|
689
|
+
console.log(chalk.red(`Unknown command: ${command}`))
|
|
450
690
|
}
|
|
451
691
|
} else {
|
|
452
|
-
program.help()
|
|
692
|
+
program.help()
|
|
453
693
|
}
|
|
454
|
-
})
|
|
694
|
+
})
|
|
455
695
|
|
|
456
696
|
// Let commander handle help and version normally
|
|
457
697
|
// program.exitOverride() removed to fix help/version output
|
|
458
698
|
|
|
459
699
|
// Handle shorthand options and single-letter commands by rewriting arguments
|
|
460
|
-
const args = [...process.argv]
|
|
700
|
+
const args = [...process.argv]
|
|
461
701
|
// Map single-letter command 'i' -> init (changed from interactive mode)
|
|
462
702
|
if (
|
|
463
703
|
args.includes('i') &&
|
|
@@ -471,95 +711,95 @@ export async function main(): Promise<void> {
|
|
|
471
711
|
a === '--interactive'
|
|
472
712
|
)
|
|
473
713
|
) {
|
|
474
|
-
const index = args.
|
|
475
|
-
args.splice(index, 1, 'init')
|
|
714
|
+
const index = args.indexOf('i')
|
|
715
|
+
args.splice(index, 1, 'init')
|
|
476
716
|
}
|
|
477
717
|
|
|
478
718
|
if (args.includes('-u') || args.includes('--update')) {
|
|
479
|
-
const index = args.findIndex((arg) => arg === '-u' || arg === '--update')
|
|
480
|
-
args.splice(index, 1, 'update')
|
|
719
|
+
const index = args.findIndex((arg) => arg === '-u' || arg === '--update')
|
|
720
|
+
args.splice(index, 1, 'update')
|
|
481
721
|
} else if (
|
|
482
722
|
(args.includes('-i') || args.includes('--interactive')) &&
|
|
483
723
|
!args.some((a) => a === 'update' || a === '-u' || a === '--update')
|
|
484
724
|
) {
|
|
485
725
|
// Map standalone -i to `update -i`
|
|
486
|
-
const index = args.findIndex((arg) => arg === '-i' || arg === '--interactive')
|
|
726
|
+
const index = args.findIndex((arg) => arg === '-i' || arg === '--interactive')
|
|
487
727
|
// Replace the flag position with 'update' and keep the flag after it
|
|
488
|
-
args.splice(index, 1, 'update', '-i')
|
|
728
|
+
args.splice(index, 1, 'update', '-i')
|
|
489
729
|
} else if (args.includes('-c') || args.includes('--check')) {
|
|
490
|
-
const index = args.findIndex((arg) => arg === '-c' || arg === '--check')
|
|
491
|
-
args.splice(index, 1, 'check')
|
|
730
|
+
const index = args.findIndex((arg) => arg === '-c' || arg === '--check')
|
|
731
|
+
args.splice(index, 1, 'check')
|
|
492
732
|
} else if (args.includes('-a') || args.includes('--analyze')) {
|
|
493
|
-
const index = args.findIndex((arg) => arg === '-a' || arg === '--analyze')
|
|
494
|
-
args.splice(index, 1, 'analyze')
|
|
733
|
+
const index = args.findIndex((arg) => arg === '-a' || arg === '--analyze')
|
|
734
|
+
args.splice(index, 1, 'analyze')
|
|
495
735
|
} 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')
|
|
736
|
+
const index = args.findIndex((arg) => arg === '-s' || arg === '--workspace-info')
|
|
737
|
+
args.splice(index, 1, 'workspace')
|
|
498
738
|
} else if (args.includes('-t') || args.includes('--theme')) {
|
|
499
|
-
const index = args.findIndex((arg) => arg === '-t' || arg === '--theme')
|
|
500
|
-
args.splice(index, 1, 'theme')
|
|
739
|
+
const index = args.findIndex((arg) => arg === '-t' || arg === '--theme')
|
|
740
|
+
args.splice(index, 1, 'theme')
|
|
501
741
|
} else if (args.includes('--security-audit')) {
|
|
502
|
-
const index = args.
|
|
503
|
-
args.splice(index, 1, 'security')
|
|
742
|
+
const index = args.indexOf('--security-audit')
|
|
743
|
+
args.splice(index, 1, 'security')
|
|
504
744
|
} else if (args.includes('--security-fix')) {
|
|
505
|
-
const index = args.
|
|
506
|
-
args.splice(index, 1, 'security', '--fix-vulns')
|
|
745
|
+
const index = args.indexOf('--security-fix')
|
|
746
|
+
args.splice(index, 1, 'security', '--fix-vulns')
|
|
507
747
|
}
|
|
508
748
|
|
|
509
749
|
// Show help if no arguments provided
|
|
510
750
|
if (args.length <= 2) {
|
|
511
|
-
program.help()
|
|
751
|
+
program.help()
|
|
512
752
|
}
|
|
513
753
|
|
|
514
754
|
// Handle custom --version with update checking
|
|
515
755
|
if (args.includes('--version')) {
|
|
516
|
-
console.log(packageJson.version)
|
|
756
|
+
console.log(packageJson.version)
|
|
517
757
|
|
|
518
758
|
// Check for updates if not in CI and enabled in config
|
|
519
759
|
if (VersionChecker.shouldCheckForUpdates() && config.advanced?.checkForUpdates !== false) {
|
|
520
760
|
try {
|
|
521
|
-
console.log(chalk.gray('Checking for updates...'))
|
|
761
|
+
console.log(chalk.gray('Checking for updates...'))
|
|
522
762
|
const versionResult = await VersionChecker.checkVersion(packageJson.version, {
|
|
523
763
|
skipPrompt: false,
|
|
524
764
|
timeout: 5000, // Longer timeout for explicit version check
|
|
525
|
-
})
|
|
765
|
+
})
|
|
526
766
|
|
|
527
767
|
if (versionResult.shouldPrompt) {
|
|
528
|
-
const didUpdate = await VersionChecker.promptAndUpdate(versionResult)
|
|
768
|
+
const didUpdate = await VersionChecker.promptAndUpdate(versionResult)
|
|
529
769
|
if (didUpdate) {
|
|
530
|
-
console.log(chalk.blue('Please run your command again to use the updated version.'))
|
|
531
|
-
process.exit(0)
|
|
770
|
+
console.log(chalk.blue('Please run your command again to use the updated version.'))
|
|
771
|
+
process.exit(0)
|
|
532
772
|
}
|
|
533
773
|
} else if (versionResult.isLatest) {
|
|
534
|
-
console.log(chalk.green('You are using the latest version!'))
|
|
774
|
+
console.log(chalk.green('You are using the latest version!'))
|
|
535
775
|
}
|
|
536
776
|
} catch (error) {
|
|
537
777
|
// Silently fail update check for version command
|
|
538
778
|
if (args.includes('-v') || args.includes('--verbose')) {
|
|
539
|
-
console.warn(chalk.yellow('⚠️ Could not check for updates:'), error)
|
|
779
|
+
console.warn(chalk.yellow('⚠️ Could not check for updates:'), error)
|
|
540
780
|
}
|
|
541
781
|
}
|
|
542
782
|
}
|
|
543
783
|
|
|
544
|
-
process.exit(0)
|
|
784
|
+
process.exit(0)
|
|
545
785
|
}
|
|
546
786
|
|
|
547
787
|
// Parse command line arguments
|
|
548
788
|
try {
|
|
549
|
-
await program.parseAsync(args)
|
|
789
|
+
await program.parseAsync(args)
|
|
550
790
|
} catch (error) {
|
|
551
|
-
console.error(chalk.red('❌ Unexpected error:'), error)
|
|
791
|
+
console.error(chalk.red('❌ Unexpected error:'), error)
|
|
552
792
|
if (error instanceof Error && error.stack) {
|
|
553
|
-
console.error(chalk.gray(error.stack))
|
|
793
|
+
console.error(chalk.gray(error.stack))
|
|
554
794
|
}
|
|
555
|
-
process.exit(1)
|
|
795
|
+
process.exit(1)
|
|
556
796
|
}
|
|
557
797
|
}
|
|
558
798
|
|
|
559
799
|
// Run the CLI if this file is executed directly
|
|
560
800
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
561
801
|
main().catch((error) => {
|
|
562
|
-
console.error(chalk.red('❌ Fatal error:'), error)
|
|
563
|
-
process.exit(1)
|
|
564
|
-
})
|
|
802
|
+
console.error(chalk.red('❌ Fatal error:'), error)
|
|
803
|
+
process.exit(1)
|
|
804
|
+
})
|
|
565
805
|
}
|