@dimensional-innovations/tool-config 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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +646 -0
  3. package/bin/setup-tool-config.js +675 -0
  4. package/package.json +168 -0
  5. package/src/detectors.js +261 -0
  6. package/src/index.js +64 -0
  7. package/src/tools/eslint/index.js +287 -0
  8. package/src/tools/eslint/presets/base.js +82 -0
  9. package/src/tools/eslint/presets/environments/browser.js +16 -0
  10. package/src/tools/eslint/presets/environments/node.js +21 -0
  11. package/src/tools/eslint/presets/environments/universal.js +18 -0
  12. package/src/tools/eslint/presets/frameworks/angular.js +74 -0
  13. package/src/tools/eslint/presets/frameworks/astro.js +38 -0
  14. package/src/tools/eslint/presets/frameworks/node.js +57 -0
  15. package/src/tools/eslint/presets/frameworks/react.js +76 -0
  16. package/src/tools/eslint/presets/frameworks/solid.js +45 -0
  17. package/src/tools/eslint/presets/frameworks/svelte.js +78 -0
  18. package/src/tools/eslint/presets/frameworks/vanilla.js +16 -0
  19. package/src/tools/eslint/presets/frameworks/vue.js +125 -0
  20. package/src/tools/eslint/presets/imports.js +41 -0
  21. package/src/tools/eslint/presets/typescript.js +131 -0
  22. package/src/tools/prettier/README.md +398 -0
  23. package/src/tools/prettier/index.js +114 -0
  24. package/src/tools/prettier/presets/base.js +36 -0
  25. package/src/tools/prettier/presets/frameworks/astro.js +15 -0
  26. package/src/tools/prettier/presets/frameworks/react.js +15 -0
  27. package/src/tools/prettier/presets/frameworks/svelte.js +22 -0
  28. package/src/tools/prettier/presets/frameworks/vanilla.js +13 -0
  29. package/src/tools/prettier/presets/frameworks/vue.js +20 -0
  30. package/src/tools/prettier/presets/prettierignore.js +56 -0
  31. package/src/tools/semantic-release/CI_SETUP.md +66 -0
  32. package/src/tools/semantic-release/README.md +533 -0
  33. package/src/tools/semantic-release/index.js +130 -0
  34. package/src/tools/semantic-release/presets/default.js +37 -0
  35. package/src/tools/semantic-release/presets/library.js +58 -0
  36. package/src/tools/semantic-release/presets/monorepo.js +48 -0
  37. package/src/tools/semantic-release/templates/.gitlab-ci.yml +85 -0
  38. package/src/tools/semantic-release/templates/bitbucket-pipelines.yml +100 -0
  39. package/src/tools/semantic-release/templates/github-workflow.yml +107 -0
  40. package/src/tools/stylelint/README.md +425 -0
  41. package/src/tools/stylelint/index.js +191 -0
  42. package/src/tools/stylelint/presets/base.js +50 -0
  43. package/src/tools/stylelint/presets/css-modules.js +43 -0
  44. package/src/tools/stylelint/presets/frameworks/react.js +18 -0
  45. package/src/tools/stylelint/presets/frameworks/svelte.js +28 -0
  46. package/src/tools/stylelint/presets/frameworks/vanilla.js +14 -0
  47. package/src/tools/stylelint/presets/frameworks/vue.js +38 -0
  48. package/src/tools/stylelint/presets/scss.js +83 -0
  49. package/src/tools/stylelint/presets/tailwind.js +49 -0
  50. package/src/utils/package-reader.js +42 -0
@@ -0,0 +1,675 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @dimensional-innovations/tool-config CLI Setup Tool
5
+ *
6
+ * Interactive configuration generator for ESLint, Prettier, Stylelint, and semantic-release
7
+ */
8
+
9
+ import { writeFileSync, existsSync, readFileSync, mkdirSync, copyFileSync } from 'fs'
10
+ import { join, dirname } from 'path'
11
+ import { fileURLToPath } from 'url'
12
+
13
+ import prompts from 'prompts'
14
+
15
+ import { autoDetect } from '../src/detectors.js'
16
+ import { prettierIgnoreContent } from '../src/tools/prettier/index.js'
17
+
18
+ const __filename = fileURLToPath(import.meta.url)
19
+ const __dirname = dirname(__filename)
20
+
21
+ const VERSION = '0.0.0-development'
22
+
23
+ // Parse CLI arguments
24
+ const args = process.argv.slice(2)
25
+ const flags = {
26
+ help: args.includes('--help') || args.includes('-h'),
27
+ version: args.includes('--version') || args.includes('-v'),
28
+ dryRun: args.includes('--dry-run') || args.includes('-d'),
29
+ all: args.includes('--all') || args.includes('-a'),
30
+ setupCI: args.includes('--setup-ci')
31
+ }
32
+
33
+ // Check for --ci flag with optional provider
34
+ const ciIndex = args.indexOf('--ci')
35
+ const ciProvider =
36
+ ciIndex !== -1 && args[ciIndex + 1] && !args[ciIndex + 1].startsWith('-')
37
+ ? args[ciIndex + 1]
38
+ : null
39
+ const hasCI = args.includes('--ci')
40
+
41
+ // Single tool mode: setup-tool-config eslint (but not --ci provider value)
42
+ const singleTool = args.find(arg => !arg.startsWith('-') && arg !== ciProvider)
43
+
44
+ /**
45
+ * Show help message
46
+ */
47
+ function showHelp() {
48
+ console.log(`
49
+ đŸ“Ļ @dimensional-innovations/tool-config Setup Tool
50
+
51
+ Usage:
52
+ setup-tool-config [tool] [options]
53
+
54
+ Tools:
55
+ eslint Setup ESLint only
56
+ prettier Setup Prettier only
57
+ stylelint Setup Stylelint only
58
+ semantic-release Setup semantic-release only
59
+
60
+ Options:
61
+ --all, -a Setup all tools (non-interactive)
62
+ --ci [provider] Setup CI/CD pipeline (gitlab, github, bitbucket)
63
+ --setup-ci Interactive CI/CD setup
64
+ --dry-run, -d Preview changes without writing files
65
+ --help, -h Show this help message
66
+ --version, -v Show version number
67
+
68
+ Examples:
69
+ setup-tool-config # Interactive mode
70
+ setup-tool-config eslint # Setup ESLint only
71
+ setup-tool-config --all # Setup all tools
72
+ setup-tool-config --dry-run # Preview without changes
73
+ setup-tool-config --ci gitlab # Setup GitLab CI/CD
74
+ setup-tool-config --ci github # Setup GitHub Actions
75
+ setup-tool-config --setup-ci # Interactive CI setup
76
+ setup-tool-config semantic-release --ci # Setup release + CI
77
+
78
+ For more information, visit:
79
+ https://gitlab.com/dimensional-innovations/tool-config
80
+ `)
81
+ }
82
+
83
+ /**
84
+ * Show version
85
+ */
86
+ function showVersion() {
87
+ console.log(`@dimensional-innovations/tool-config v${VERSION}`)
88
+ }
89
+
90
+ /**
91
+ * Generate config file content for a tool
92
+ */
93
+ function generateConfigContent(tool) {
94
+ const configs = {
95
+ eslint: `import { createConfig } from '@dimensional-innovations/tool-config'
96
+
97
+ export default await createConfig('eslint')
98
+ `,
99
+ prettier: `import { createConfig } from '@dimensional-innovations/tool-config'
100
+
101
+ export default createConfig('prettier')
102
+ `,
103
+ stylelint: `import { createConfig } from '@dimensional-innovations/tool-config'
104
+
105
+ export default createConfig('stylelint')
106
+ `,
107
+ 'semantic-release': `import { createConfig } from '@dimensional-innovations/tool-config'
108
+
109
+ export default createConfig('semantic-release')
110
+ `
111
+ }
112
+
113
+ return configs[tool] || ''
114
+ }
115
+
116
+ /**
117
+ * Get config filename for a tool
118
+ */
119
+ function getConfigFilename(tool) {
120
+ const filenames = {
121
+ eslint: 'eslint.config.js',
122
+ prettier: 'prettier.config.js',
123
+ stylelint: 'stylelint.config.js',
124
+ 'semantic-release': 'release.config.js'
125
+ }
126
+
127
+ return filenames[tool] || `${tool}.config.js`
128
+ }
129
+
130
+ /**
131
+ * Get npm scripts for a tool
132
+ */
133
+ function getToolScripts(tool) {
134
+ const scripts = {
135
+ eslint: {
136
+ lint: 'eslint .',
137
+ 'lint:fix': 'eslint --fix .'
138
+ },
139
+ prettier: {
140
+ 'prettier:fix': 'prettier --write .',
141
+ prettier: 'prettier --check .'
142
+ },
143
+ stylelint: {
144
+ style: 'stylelint "**/*.css"',
145
+ 'style:fix': 'stylelint "**/*.css" --fix'
146
+ },
147
+ 'semantic-release': {
148
+ release: 'semantic-release'
149
+ }
150
+ }
151
+
152
+ return scripts[tool] || {}
153
+ }
154
+
155
+ /**
156
+ * Write config file
157
+ */
158
+ function writeConfigFile(tool, cwd, dryRun = false) {
159
+ const filename = getConfigFilename(tool)
160
+ const filepath = join(cwd, filename)
161
+ const content = generateConfigContent(tool)
162
+
163
+ if (existsSync(filepath)) {
164
+ console.log(` âš ī¸ ${filename} already exists - skipping`)
165
+ return false
166
+ }
167
+
168
+ if (dryRun) {
169
+ console.log(` 📄 Would create: ${filename}`)
170
+
171
+ // Prettier also creates .prettierignore
172
+ if (tool === 'prettier') {
173
+ const ignoreFile = '.prettierignore'
174
+ const ignoreExists = existsSync(join(cwd, ignoreFile))
175
+ if (!ignoreExists) {
176
+ console.log(` 📄 Would create: ${ignoreFile}`)
177
+ }
178
+ }
179
+
180
+ return true
181
+ }
182
+
183
+ try {
184
+ writeFileSync(filepath, content, 'utf8')
185
+ console.log(` ✅ Created: ${filename}`)
186
+
187
+ // Prettier also creates .prettierignore
188
+ if (tool === 'prettier') {
189
+ const ignoreFile = '.prettierignore'
190
+ const ignorePath = join(cwd, ignoreFile)
191
+
192
+ if (!existsSync(ignorePath)) {
193
+ writeFileSync(ignorePath, prettierIgnoreContent, 'utf8')
194
+ console.log(` ✅ Created: ${ignoreFile}`)
195
+ } else {
196
+ console.log(` âš ī¸ ${ignoreFile} already exists - skipping`)
197
+ }
198
+ }
199
+
200
+ return true
201
+ } catch (error) {
202
+ console.error(` ❌ Failed to create ${filename}:`, error.message)
203
+ return false
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Update package.json with scripts
209
+ */
210
+ function updatePackageJsonScripts(tools, cwd, dryRun = false) {
211
+ const packageJsonPath = join(cwd, 'package.json')
212
+
213
+ if (!existsSync(packageJsonPath)) {
214
+ console.log(' âš ī¸ No package.json found - skipping script injection')
215
+ return
216
+ }
217
+
218
+ try {
219
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
220
+
221
+ if (!packageJson.scripts) {
222
+ packageJson.scripts = {}
223
+ }
224
+
225
+ const scriptsToAdd = {}
226
+ for (const tool of tools) {
227
+ const toolScripts = getToolScripts(tool)
228
+ for (const [name, command] of Object.entries(toolScripts)) {
229
+ if (!packageJson.scripts[name]) {
230
+ scriptsToAdd[name] = command
231
+ }
232
+ }
233
+ }
234
+
235
+ if (Object.keys(scriptsToAdd).length === 0) {
236
+ console.log(' â„šī¸ All scripts already exist in package.json')
237
+ return
238
+ }
239
+
240
+ if (dryRun) {
241
+ console.log(' 📝 Would add scripts to package.json:')
242
+ for (const [name, command] of Object.entries(scriptsToAdd)) {
243
+ console.log(` "${name}": "${command}"`)
244
+ }
245
+ return
246
+ }
247
+
248
+ Object.assign(packageJson.scripts, scriptsToAdd)
249
+
250
+ writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, 'utf8')
251
+
252
+ console.log(' ✅ Updated package.json with scripts:')
253
+ for (const name of Object.keys(scriptsToAdd)) {
254
+ console.log(` - ${name}`)
255
+ }
256
+ } catch (error) {
257
+ console.error(' ❌ Failed to update package.json:', error.message)
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Get CI filename and path for a git provider
263
+ */
264
+ function getCIFileInfo(provider) {
265
+ const ciFiles = {
266
+ gitlab: {
267
+ filename: '.gitlab-ci.yml',
268
+ destination: '.gitlab-ci.yml',
269
+ template: '.gitlab-ci.yml'
270
+ },
271
+ github: {
272
+ filename: 'ci.yml',
273
+ destination: '.github/workflows/ci.yml',
274
+ template: 'github-workflow.yml',
275
+ needsDir: true
276
+ },
277
+ bitbucket: {
278
+ filename: 'bitbucket-pipelines.yml',
279
+ destination: 'bitbucket-pipelines.yml',
280
+ template: 'bitbucket-pipelines.yml'
281
+ }
282
+ }
283
+
284
+ return ciFiles[provider] || null
285
+ }
286
+
287
+ /**
288
+ * Get environment variable instructions for a git provider
289
+ */
290
+ function getCIInstructions(provider) {
291
+ const instructions = {
292
+ gitlab: `
293
+ âš ī¸ Configuration Required:
294
+ Add these CI/CD variables in GitLab Settings > CI/CD > Variables:
295
+ - GL_TOKEN: GitLab Personal Access Token (with api scope)
296
+ - NPM_TOKEN: npm authentication token
297
+
298
+ Then push to main branch to trigger automated releases.`,
299
+ github: `
300
+ âš ī¸ Configuration Required:
301
+ Add these secrets in GitHub Settings > Secrets and variables > Actions:
302
+ - GITHUB_TOKEN: Automatically provided by GitHub Actions
303
+ - NPM_TOKEN: npm authentication token
304
+
305
+ Then push to main branch to trigger automated releases.`,
306
+ bitbucket: `
307
+ âš ī¸ Configuration Required:
308
+ Add this repository variable in Bitbucket Settings > Pipelines > Repository variables:
309
+ - NPM_TOKEN: npm authentication token
310
+
311
+ Then push to main branch to trigger automated releases.`
312
+ }
313
+
314
+ return instructions[provider] || ''
315
+ }
316
+
317
+ /**
318
+ * Copy CI/CD template
319
+ */
320
+ function copyCITemplate(provider, cwd, dryRun = false) {
321
+ if (!provider || provider === 'unknown') {
322
+ console.log(' âš ī¸ Could not detect git provider - skipping CI setup')
323
+ console.log(' 💡 You can manually copy templates from:')
324
+ console.log(
325
+ ' node_modules/@dimensional-innovations/tool-config/src/tools/semantic-release/templates/'
326
+ )
327
+ return false
328
+ }
329
+
330
+ const ciInfo = getCIFileInfo(provider)
331
+
332
+ if (!ciInfo) {
333
+ console.log(` âš ī¸ Unsupported git provider: ${provider}`)
334
+ return false
335
+ }
336
+
337
+ const destPath = join(cwd, ciInfo.destination)
338
+ const destDir = dirname(destPath)
339
+
340
+ // Check if CI file already exists
341
+ if (existsSync(destPath)) {
342
+ console.log(` âš ī¸ ${ciInfo.destination} already exists - skipping`)
343
+ return false
344
+ }
345
+
346
+ if (dryRun) {
347
+ console.log(` 📄 Would create: ${ciInfo.destination}`)
348
+ if (ciInfo.needsDir && !existsSync(destDir)) {
349
+ console.log(` 📁 Would create directory: ${dirname(ciInfo.destination)}`)
350
+ }
351
+ return true
352
+ }
353
+
354
+ try {
355
+ // Create directory if needed
356
+ if (ciInfo.needsDir && !existsSync(destDir)) {
357
+ mkdirSync(destDir, { recursive: true })
358
+ console.log(` ✅ Created directory: ${dirname(ciInfo.destination)}`)
359
+ }
360
+
361
+ // Copy template
362
+ const templatePath = join(
363
+ __dirname,
364
+ '..',
365
+ 'src',
366
+ 'tools',
367
+ 'semantic-release',
368
+ 'templates',
369
+ ciInfo.template
370
+ )
371
+ copyFileSync(templatePath, destPath)
372
+ console.log(` ✅ Created: ${ciInfo.destination}`)
373
+
374
+ // Show configuration instructions
375
+ console.log(getCIInstructions(provider))
376
+
377
+ console.log('\n 📖 For more details, see:')
378
+ console.log(
379
+ ' node_modules/@dimensional-innovations/tool-config/src/tools/semantic-release/CI_SETUP.md'
380
+ )
381
+
382
+ return true
383
+ } catch (error) {
384
+ console.error(` ❌ Failed to copy CI template:`, error.message)
385
+ return false
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Setup tools
391
+ */
392
+ function setupTools(tools, cwd, dryRun = false) {
393
+ console.log('')
394
+ console.log('📝 Generating configuration files...')
395
+ console.log('')
396
+
397
+ for (const tool of tools) {
398
+ console.log(`${tool}:`)
399
+ writeConfigFile(tool, cwd, dryRun)
400
+ }
401
+
402
+ console.log('')
403
+ console.log('đŸ“Ļ Updating package.json scripts...')
404
+ console.log('')
405
+ updatePackageJsonScripts(tools, cwd, dryRun)
406
+ }
407
+
408
+ /**
409
+ * Main CLI function
410
+ */
411
+ async function main() {
412
+ // Handle flags
413
+ if (flags.help) {
414
+ showHelp()
415
+ process.exit(0)
416
+ }
417
+
418
+ if (flags.version) {
419
+ showVersion()
420
+ process.exit(0)
421
+ }
422
+
423
+ const cwd = process.cwd()
424
+
425
+ // Show banner
426
+ console.log('')
427
+ console.log('đŸ“Ļ @dimensional-innovations/tool-config Setup')
428
+ console.log('━'.repeat(50))
429
+ console.log('')
430
+
431
+ // Auto-detect project
432
+ const detected = autoDetect(cwd)
433
+ console.log('🔍 Detected project configuration:')
434
+ console.log(` Framework: ${detected.framework}`)
435
+ console.log(` Environment: ${detected.environment}`)
436
+ console.log(` TypeScript: ${detected.typescript ? 'Yes' : 'No'}`)
437
+ console.log(` Git Provider: ${detected.gitProvider || 'Unknown'}`)
438
+ console.log('')
439
+
440
+ // Handle standalone --setup-ci flag
441
+ if (flags.setupCI) {
442
+ console.log('🚀 CI/CD Pipeline Setup')
443
+ console.log('')
444
+
445
+ let provider = detected.gitProvider
446
+
447
+ // If provider not detected or unknown, prompt for it
448
+ if (!provider || provider === 'unknown') {
449
+ const providerResponse = await prompts({
450
+ type: 'select',
451
+ name: 'provider',
452
+ message: 'Which CI/CD platform would you like to use?',
453
+ choices: [
454
+ { title: 'GitLab CI', value: 'gitlab' },
455
+ { title: 'GitHub Actions', value: 'github' },
456
+ { title: 'Bitbucket Pipelines', value: 'bitbucket' }
457
+ ]
458
+ })
459
+
460
+ if (!providerResponse.provider) {
461
+ console.log('❌ No provider selected. Exiting.')
462
+ process.exit(0)
463
+ }
464
+
465
+ provider = providerResponse.provider
466
+ }
467
+
468
+ console.log('📝 Setting up CI/CD...')
469
+ console.log('')
470
+ copyCITemplate(provider, cwd, flags.dryRun)
471
+
472
+ console.log('')
473
+ if (flags.dryRun) {
474
+ console.log('â„šī¸ Dry run mode - no files were modified')
475
+ } else {
476
+ console.log('✅ CI/CD setup complete!')
477
+ }
478
+ console.log('')
479
+ process.exit(0)
480
+ }
481
+
482
+ // Handle --ci flag with provider
483
+ if (hasCI && ciProvider) {
484
+ const validProviders = ['gitlab', 'github', 'bitbucket']
485
+
486
+ if (!validProviders.includes(ciProvider)) {
487
+ console.error(`❌ Unknown provider: ${ciProvider}`)
488
+ console.error(`Valid providers: ${validProviders.join(', ')}`)
489
+ process.exit(1)
490
+ }
491
+
492
+ console.log('🚀 CI/CD Pipeline Setup')
493
+ console.log('')
494
+ console.log('📝 Setting up CI/CD...')
495
+ console.log('')
496
+ copyCITemplate(ciProvider, cwd, flags.dryRun)
497
+
498
+ console.log('')
499
+ if (flags.dryRun) {
500
+ console.log('â„šī¸ Dry run mode - no files were modified')
501
+ } else {
502
+ console.log('✅ CI/CD setup complete!')
503
+ }
504
+ console.log('')
505
+ process.exit(0)
506
+ }
507
+
508
+ // Handle --all flag
509
+ if (flags.all) {
510
+ const tools = ['eslint', 'prettier', 'stylelint', 'semantic-release']
511
+ setupTools(tools, cwd, flags.dryRun)
512
+ console.log('')
513
+ if (flags.dryRun) {
514
+ console.log('â„šī¸ Dry run mode - no files were modified')
515
+ console.log('Run without --dry-run to apply changes')
516
+ } else {
517
+ console.log('✅ Setup complete!')
518
+ }
519
+ console.log('')
520
+ process.exit(0)
521
+ }
522
+
523
+ // Handle single tool mode
524
+ if (singleTool) {
525
+ const validTools = ['eslint', 'prettier', 'stylelint', 'semantic-release']
526
+
527
+ if (!validTools.includes(singleTool)) {
528
+ console.error(`❌ Unknown tool: ${singleTool}`)
529
+ console.error(`Valid tools: ${validTools.join(', ')}`)
530
+ process.exit(1)
531
+ }
532
+
533
+ setupTools([singleTool], cwd, flags.dryRun)
534
+
535
+ // If semantic-release + --ci flag, setup CI
536
+ if (singleTool === 'semantic-release' && hasCI) {
537
+ console.log('')
538
+ console.log('🚀 CI/CD Pipeline Setup')
539
+ console.log('')
540
+
541
+ let provider = ciProvider || detected.gitProvider
542
+
543
+ // If no provider specified and can't detect, prompt
544
+ if (!provider || provider === 'unknown') {
545
+ const providerResponse = await prompts({
546
+ type: 'select',
547
+ name: 'provider',
548
+ message: 'Which CI/CD platform would you like to use?',
549
+ choices: [
550
+ { title: 'GitLab CI', value: 'gitlab' },
551
+ { title: 'GitHub Actions', value: 'github' },
552
+ { title: 'Bitbucket Pipelines', value: 'bitbucket' }
553
+ ]
554
+ })
555
+
556
+ if (!providerResponse.provider) {
557
+ console.log('âš ī¸ Skipping CI/CD setup.')
558
+ console.log('')
559
+ process.exit(0)
560
+ }
561
+
562
+ provider = providerResponse.provider
563
+ }
564
+
565
+ console.log('📝 Setting up CI/CD...')
566
+ console.log('')
567
+ copyCITemplate(provider, cwd, flags.dryRun)
568
+ }
569
+
570
+ console.log('')
571
+ if (flags.dryRun) {
572
+ console.log('â„šī¸ Dry run mode - no files were modified')
573
+ console.log('Run without --dry-run to apply changes')
574
+ } else {
575
+ console.log('✅ Setup complete!')
576
+ }
577
+ console.log('')
578
+ process.exit(0)
579
+ }
580
+
581
+ // Interactive mode
582
+ const response = await prompts([
583
+ {
584
+ type: 'multiselect',
585
+ name: 'tools',
586
+ message: 'Which tools would you like to setup?',
587
+ choices: [
588
+ { title: 'ESLint (JavaScript/TypeScript linting)', value: 'eslint', selected: true },
589
+ { title: 'Prettier (Code formatting)', value: 'prettier', selected: true },
590
+ { title: 'Stylelint (CSS/style linting)', value: 'stylelint', selected: false },
591
+ {
592
+ title: 'semantic-release (Automated versioning)',
593
+ value: 'semantic-release',
594
+ selected: false
595
+ }
596
+ ],
597
+ hint: '- Space to select. Return to submit'
598
+ }
599
+ ])
600
+
601
+ if (!response.tools || response.tools.length === 0) {
602
+ console.log('')
603
+ console.log('❌ No tools selected. Exiting.')
604
+ process.exit(0)
605
+ }
606
+
607
+ setupTools(response.tools, cwd, flags.dryRun)
608
+
609
+ // If semantic-release selected, prompt for CI setup
610
+ if (response.tools.includes('semantic-release')) {
611
+ console.log('')
612
+ console.log('🚀 CI/CD Pipeline Setup')
613
+ console.log('')
614
+
615
+ const ciResponse = await prompts({
616
+ type: 'confirm',
617
+ name: 'setupCI',
618
+ message: 'Setup CI/CD pipeline for automated releases?',
619
+ initial: true
620
+ })
621
+
622
+ if (ciResponse.setupCI) {
623
+ let provider = detected.gitProvider
624
+
625
+ // If provider not detected or unknown, prompt for it
626
+ if (!provider || provider === 'unknown') {
627
+ const providerResponse = await prompts({
628
+ type: 'select',
629
+ name: 'provider',
630
+ message: 'Which CI/CD platform would you like to use?',
631
+ choices: [
632
+ { title: 'GitLab CI', value: 'gitlab' },
633
+ { title: 'GitHub Actions', value: 'github' },
634
+ { title: 'Bitbucket Pipelines', value: 'bitbucket' }
635
+ ]
636
+ })
637
+
638
+ if (!providerResponse.provider) {
639
+ console.log('âš ī¸ Skipping CI/CD setup.')
640
+ } else {
641
+ provider = providerResponse.provider
642
+ console.log('📝 Setting up CI/CD...')
643
+ console.log('')
644
+ copyCITemplate(provider, cwd, flags.dryRun)
645
+ }
646
+ } else {
647
+ console.log('📝 Setting up CI/CD...')
648
+ console.log('')
649
+ copyCITemplate(provider, cwd, flags.dryRun)
650
+ }
651
+ }
652
+ }
653
+
654
+ console.log('')
655
+ if (flags.dryRun) {
656
+ console.log('â„šī¸ Dry run mode - no files were modified')
657
+ console.log('Run without --dry-run to apply changes')
658
+ } else {
659
+ console.log('✅ Setup complete!')
660
+ console.log('')
661
+ console.log('Next steps:')
662
+ console.log(' 1. Review the generated config files')
663
+ console.log(' 2. Install peer dependencies if needed')
664
+ console.log(' 3. Run: npm run lint (or other added scripts)')
665
+ }
666
+ console.log('')
667
+ }
668
+
669
+ // Run CLI
670
+ main().catch(error => {
671
+ console.error('')
672
+ console.error('❌ Error:', error.message)
673
+ console.error('')
674
+ process.exit(1)
675
+ })