specweave 0.26.14 → 0.28.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 (167) hide show
  1. package/CLAUDE.md +73 -1
  2. package/README.md +245 -446
  3. package/dist/plugins/specweave-jira/lib/setup-wizard.d.ts.map +1 -1
  4. package/dist/plugins/specweave-jira/lib/setup-wizard.js +57 -78
  5. package/dist/plugins/specweave-jira/lib/setup-wizard.js.map +1 -1
  6. package/dist/src/cli/commands/import-docs.d.ts.map +1 -1
  7. package/dist/src/cli/commands/import-docs.js +23 -31
  8. package/dist/src/cli/commands/import-docs.js.map +1 -1
  9. package/dist/src/cli/commands/import-external.d.ts.map +1 -1
  10. package/dist/src/cli/commands/import-external.js +6 -10
  11. package/dist/src/cli/commands/import-external.js.map +1 -1
  12. package/dist/src/cli/commands/init-multiproject.d.ts.map +1 -1
  13. package/dist/src/cli/commands/init-multiproject.js +58 -73
  14. package/dist/src/cli/commands/init-multiproject.js.map +1 -1
  15. package/dist/src/cli/commands/init.d.ts +17 -11
  16. package/dist/src/cli/commands/init.d.ts.map +1 -1
  17. package/dist/src/cli/commands/init.js +221 -1874
  18. package/dist/src/cli/commands/init.js.map +1 -1
  19. package/dist/src/cli/commands/install.d.ts.map +1 -1
  20. package/dist/src/cli/commands/install.js +14 -22
  21. package/dist/src/cli/commands/install.js.map +1 -1
  22. package/dist/src/cli/commands/migrate-config.d.ts.map +1 -1
  23. package/dist/src/cli/commands/migrate-config.js +6 -10
  24. package/dist/src/cli/commands/migrate-config.js.map +1 -1
  25. package/dist/src/cli/commands/switch-project.d.ts.map +1 -1
  26. package/dist/src/cli/commands/switch-project.js.map +1 -1
  27. package/dist/src/cli/helpers/ado-area-path-mapper.d.ts.map +1 -1
  28. package/dist/src/cli/helpers/ado-area-path-mapper.js +36 -49
  29. package/dist/src/cli/helpers/ado-area-path-mapper.js.map +1 -1
  30. package/dist/src/cli/helpers/github/increment-profile-selector.d.ts.map +1 -1
  31. package/dist/src/cli/helpers/github/increment-profile-selector.js.map +1 -1
  32. package/dist/src/cli/helpers/github/profile-manager.d.ts.map +1 -1
  33. package/dist/src/cli/helpers/github/profile-manager.js +8 -11
  34. package/dist/src/cli/helpers/github/profile-manager.js.map +1 -1
  35. package/dist/src/cli/helpers/github-repo-selector.d.ts.map +1 -1
  36. package/dist/src/cli/helpers/github-repo-selector.js +26 -50
  37. package/dist/src/cli/helpers/github-repo-selector.js.map +1 -1
  38. package/dist/src/cli/helpers/import-strategy-prompter.d.ts.map +1 -1
  39. package/dist/src/cli/helpers/import-strategy-prompter.js +39 -52
  40. package/dist/src/cli/helpers/import-strategy-prompter.js.map +1 -1
  41. package/dist/src/cli/helpers/init/config-detection.d.ts +40 -0
  42. package/dist/src/cli/helpers/init/config-detection.d.ts.map +1 -0
  43. package/dist/src/cli/helpers/init/config-detection.js +125 -0
  44. package/dist/src/cli/helpers/init/config-detection.js.map +1 -0
  45. package/dist/src/cli/helpers/init/directory-structure.d.ts +26 -0
  46. package/dist/src/cli/helpers/init/directory-structure.d.ts.map +1 -0
  47. package/dist/src/cli/helpers/init/directory-structure.js +190 -0
  48. package/dist/src/cli/helpers/init/directory-structure.js.map +1 -0
  49. package/dist/src/cli/helpers/init/external-import.d.ts +15 -0
  50. package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -0
  51. package/dist/src/cli/helpers/init/external-import.js +251 -0
  52. package/dist/src/cli/helpers/init/external-import.js.map +1 -0
  53. package/dist/src/cli/helpers/init/index.d.ts +15 -0
  54. package/dist/src/cli/helpers/init/index.d.ts.map +1 -0
  55. package/dist/src/cli/helpers/init/index.js +26 -0
  56. package/dist/src/cli/helpers/init/index.js.map +1 -0
  57. package/dist/src/cli/helpers/init/next-steps.d.ts +15 -0
  58. package/dist/src/cli/helpers/init/next-steps.d.ts.map +1 -0
  59. package/dist/src/cli/helpers/init/next-steps.js +72 -0
  60. package/dist/src/cli/helpers/init/next-steps.js.map +1 -0
  61. package/dist/src/cli/helpers/init/path-utils.d.ts +41 -0
  62. package/dist/src/cli/helpers/init/path-utils.d.ts.map +1 -0
  63. package/dist/src/cli/helpers/init/path-utils.js +146 -0
  64. package/dist/src/cli/helpers/init/path-utils.js.map +1 -0
  65. package/dist/src/cli/helpers/init/plugin-installer.d.ts +28 -0
  66. package/dist/src/cli/helpers/init/plugin-installer.d.ts.map +1 -0
  67. package/dist/src/cli/helpers/init/plugin-installer.js +238 -0
  68. package/dist/src/cli/helpers/init/plugin-installer.js.map +1 -0
  69. package/dist/src/cli/helpers/init/repository-setup.d.ts +28 -0
  70. package/dist/src/cli/helpers/init/repository-setup.d.ts.map +1 -0
  71. package/dist/src/cli/helpers/init/repository-setup.js +78 -0
  72. package/dist/src/cli/helpers/init/repository-setup.js.map +1 -0
  73. package/dist/src/cli/helpers/init/smart-reinit.d.ts +30 -0
  74. package/dist/src/cli/helpers/init/smart-reinit.d.ts.map +1 -0
  75. package/dist/src/cli/helpers/init/smart-reinit.js +140 -0
  76. package/dist/src/cli/helpers/init/smart-reinit.js.map +1 -0
  77. package/dist/src/cli/helpers/init/testing-config.d.ts +27 -0
  78. package/dist/src/cli/helpers/init/testing-config.d.ts.map +1 -0
  79. package/dist/src/cli/helpers/init/testing-config.js +131 -0
  80. package/dist/src/cli/helpers/init/testing-config.js.map +1 -0
  81. package/dist/src/cli/helpers/init/types.d.ts +86 -0
  82. package/dist/src/cli/helpers/init/types.d.ts.map +1 -0
  83. package/dist/src/cli/helpers/init/types.js +5 -0
  84. package/dist/src/cli/helpers/init/types.js.map +1 -0
  85. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts.map +1 -1
  86. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js +10 -12
  87. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js.map +1 -1
  88. package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
  89. package/dist/src/cli/helpers/issue-tracker/ado.js +43 -60
  90. package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
  91. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
  92. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +193 -230
  93. package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
  94. package/dist/src/cli/helpers/issue-tracker/github.d.ts.map +1 -1
  95. package/dist/src/cli/helpers/issue-tracker/github.js +43 -54
  96. package/dist/src/cli/helpers/issue-tracker/github.js.map +1 -1
  97. package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
  98. package/dist/src/cli/helpers/issue-tracker/index.js +27 -40
  99. package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
  100. package/dist/src/cli/helpers/issue-tracker/jira.d.ts.map +1 -1
  101. package/dist/src/cli/helpers/issue-tracker/jira.js +54 -70
  102. package/dist/src/cli/helpers/issue-tracker/jira.js.map +1 -1
  103. package/dist/src/cli/helpers/smart-filter.d.ts.map +1 -1
  104. package/dist/src/cli/helpers/smart-filter.js +62 -85
  105. package/dist/src/cli/helpers/smart-filter.js.map +1 -1
  106. package/dist/src/core/increment/auto-transition-manager.d.ts +12 -0
  107. package/dist/src/core/increment/auto-transition-manager.d.ts.map +1 -1
  108. package/dist/src/core/increment/auto-transition-manager.js +45 -0
  109. package/dist/src/core/increment/auto-transition-manager.js.map +1 -1
  110. package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
  111. package/dist/src/core/increment/metadata-manager.js +46 -0
  112. package/dist/src/core/increment/metadata-manager.js.map +1 -1
  113. package/dist/src/core/increment/status-change-sync-trigger.d.ts +12 -0
  114. package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
  115. package/dist/src/core/increment/status-change-sync-trigger.js +48 -2
  116. package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
  117. package/dist/src/core/living-docs/living-docs-sync.d.ts +13 -0
  118. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  119. package/dist/src/core/living-docs/living-docs-sync.js +40 -0
  120. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  121. package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts +5 -1
  122. package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts.map +1 -1
  123. package/dist/src/core/repo-structure/repo-bulk-discovery.js +68 -86
  124. package/dist/src/core/repo-structure/repo-bulk-discovery.js.map +1 -1
  125. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  126. package/dist/src/core/repo-structure/repo-structure-manager.js +345 -425
  127. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  128. package/dist/src/core/sync/bidirectional-engine.d.ts.map +1 -1
  129. package/dist/src/core/sync/bidirectional-engine.js +21 -29
  130. package/dist/src/core/sync/bidirectional-engine.js.map +1 -1
  131. package/dist/src/init/InitFlow.js +15 -19
  132. package/dist/src/init/InitFlow.js.map +1 -1
  133. package/dist/src/init/repo/types.d.ts +1 -1
  134. package/dist/src/integrations/ado/area-path-mapper.d.ts.map +1 -1
  135. package/dist/src/integrations/ado/area-path-mapper.js +19 -23
  136. package/dist/src/integrations/ado/area-path-mapper.js.map +1 -1
  137. package/dist/src/utils/external-resource-validator.d.ts.map +1 -1
  138. package/dist/src/utils/external-resource-validator.js +41 -65
  139. package/dist/src/utils/external-resource-validator.js.map +1 -1
  140. package/dist/src/utils/project-detection.d.ts.map +1 -1
  141. package/dist/src/utils/project-detection.js +19 -21
  142. package/dist/src/utils/project-detection.js.map +1 -1
  143. package/dist/src/utils/project-validator.d.ts.map +1 -1
  144. package/dist/src/utils/project-validator.js +5 -7
  145. package/dist/src/utils/project-validator.js.map +1 -1
  146. package/package.json +2 -3
  147. package/plugins/specweave/agents/tech-lead/AGENT.md +9 -0
  148. package/plugins/specweave/hooks/post-edit-write-consolidated.sh +87 -0
  149. package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.d.ts +12 -0
  150. package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js +45 -0
  151. package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js.map +1 -1
  152. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +46 -0
  153. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
  154. package/plugins/specweave/skills/increment-planner/SKILL.md +10 -5
  155. package/plugins/specweave/skills/specweave-framework/SKILL.md +6 -4
  156. package/plugins/specweave/templates/coding-standards.md.template +36 -0
  157. package/plugins/specweave-ado/lib/project-selector.js +56 -67
  158. package/plugins/specweave-ado/lib/project-selector.ts +72 -85
  159. package/plugins/specweave-github/lib/repo-selector.js +55 -66
  160. package/plugins/specweave-github/lib/repo-selector.ts +73 -84
  161. package/plugins/specweave-jira/commands/import-projects.js +3 -5
  162. package/plugins/specweave-jira/commands/import-projects.ts +3 -5
  163. package/plugins/specweave-jira/lib/project-selector.js +60 -71
  164. package/plugins/specweave-jira/lib/project-selector.ts +78 -91
  165. package/plugins/specweave-jira/lib/setup-wizard.js +51 -72
  166. package/plugins/specweave-jira/lib/setup-wizard.ts +56 -74
  167. package/src/templates/CLAUDE.md.template +14 -0
@@ -17,7 +17,7 @@
17
17
  import { existsSync, mkdirSync, writeFileSync } from 'fs';
18
18
  import path from 'path';
19
19
  import chalk from 'chalk';
20
- import inquirer from 'inquirer';
20
+ import { select, input, confirm, number } from '@inquirer/prompts';
21
21
  import ora from 'ora';
22
22
  import { execSync } from 'child_process';
23
23
  import { execFileNoThrowSync } from '../../utils/execFileNoThrow.js';
@@ -54,12 +54,10 @@ export class RepoStructureManager {
54
54
  console.log(chalk.yellow('\nāøļø Detected interrupted setup!'));
55
55
  console.log(chalk.gray(` Last step: ${resumedState.currentStep}`));
56
56
  console.log(chalk.gray(` Time: ${new Date(resumedState.timestamp).toLocaleString()}\n`));
57
- const { shouldResume } = await inquirer.prompt([{
58
- type: 'confirm',
59
- name: 'shouldResume',
60
- message: 'Resume previous setup?',
61
- default: true
62
- }]);
57
+ const shouldResume = await confirm({
58
+ message: 'Resume previous setup?',
59
+ default: true
60
+ });
63
61
  if (shouldResume) {
64
62
  return this.resumeSetup(resumedState);
65
63
  }
@@ -78,38 +76,31 @@ export class RepoStructureManager {
78
76
  else {
79
77
  // Ask user for architecture choice
80
78
  const promptData = getArchitecturePrompt();
81
- const result = await inquirer.prompt([{
82
- type: 'select',
83
- name: 'architecture',
84
- message: promptData.question,
85
- choices: promptData.options.map(opt => ({
86
- name: `${opt.label}\n${chalk.gray(opt.description)}\n${chalk.dim(opt.example)}`,
87
- value: opt.value,
88
- short: opt.label
89
- })),
90
- default: 'single'
91
- }]);
92
- architecture = result.architecture;
79
+ architecture = await select({
80
+ message: promptData.question,
81
+ choices: promptData.options.map(opt => ({
82
+ name: `${opt.label}\n${chalk.gray(opt.description)}\n${chalk.dim(opt.example)}`,
83
+ value: opt.value
84
+ })),
85
+ default: 'single'
86
+ });
93
87
  }
94
88
  // Step 2: Ask about Git hosting platform
95
89
  const registry = getPlatformRegistry();
96
90
  const platformOptions = registry.getPlatformOptions(true); // Include unsupported platforms
97
91
  const platformPromptData = getPlatformSelectionPrompt();
98
92
  console.log(chalk.cyan('\n' + platformPromptData.message));
99
- const { platform } = await inquirer.prompt([{
100
- type: 'select',
101
- name: 'platform',
102
- message: platformPromptData.question,
103
- choices: platformOptions.map(opt => ({
104
- name: opt.disabled
105
- ? `${opt.name}\n${chalk.gray(opt.description)}\n${chalk.yellow('āš ļø ' + opt.disabled)}`
106
- : `${opt.name}\n${chalk.gray(opt.description)}`,
107
- value: opt.value,
108
- short: opt.name,
109
- disabled: opt.disabled ? opt.disabled : false
110
- })),
111
- default: 'github'
112
- }]);
93
+ const platform = await select({
94
+ message: platformPromptData.question,
95
+ choices: platformOptions.map(opt => ({
96
+ name: opt.disabled
97
+ ? `${opt.name}\n${chalk.gray(opt.description)}\n${chalk.yellow('āš ļø ' + opt.disabled)}`
98
+ : `${opt.name}\n${chalk.gray(opt.description)}`,
99
+ value: opt.value,
100
+ disabled: opt.disabled ? opt.disabled : false
101
+ })),
102
+ default: 'github'
103
+ });
113
104
  // Get provider instance
114
105
  const provider = registry.getProvider(platform);
115
106
  if (!provider) {
@@ -118,17 +109,14 @@ export class RepoStructureManager {
118
109
  console.log(chalk.green(`\nāœ“ Using ${provider.config.name} as Git hosting platform\n`));
119
110
  // Step 3: Ask about Git remote URL format (SSH vs HTTPS)
120
111
  const urlTypePromptData = getUrlTypePrompt();
121
- const { urlType } = await inquirer.prompt([{
122
- type: 'select',
123
- name: 'urlType',
124
- message: urlTypePromptData.question,
125
- choices: urlTypePromptData.options.map(opt => ({
126
- name: `${opt.label}\n${chalk.gray(opt.description)}`,
127
- value: opt.value,
128
- short: opt.label
129
- })),
130
- default: urlTypePromptData.default
131
- }]);
112
+ const urlType = await select({
113
+ message: urlTypePromptData.question,
114
+ choices: urlTypePromptData.options.map(opt => ({
115
+ name: `${opt.label}\n${chalk.gray(opt.description)}`,
116
+ value: opt.value
117
+ })),
118
+ default: urlTypePromptData.default
119
+ });
132
120
  console.log(chalk.green(`\nāœ“ Using ${urlType.toUpperCase()} remote URLs\n`));
133
121
  // Map ArchitectureChoice to internal architecture
134
122
  const mappedArch = this.mapArchitectureChoice(architecture);
@@ -222,12 +210,10 @@ export class RepoStructureManager {
222
210
  const owner = match[1];
223
211
  const repo = match[2];
224
212
  console.log(chalk.green(`āœ“ Existing repository detected: ${owner}/${repo}`));
225
- const { useExisting } = await inquirer.prompt([{
226
- type: 'confirm',
227
- name: 'useExisting',
228
- message: 'Use existing repository?',
229
- default: true
230
- }]);
213
+ const useExisting = await confirm({
214
+ message: 'Use existing repository?',
215
+ default: true
216
+ });
231
217
  if (useExisting) {
232
218
  // Fetch description and visibility from GitHub API
233
219
  let description = `${repo} - SpecWeave project`;
@@ -274,49 +260,41 @@ export class RepoStructureManager {
274
260
  }
275
261
  }
276
262
  // Manual configuration
277
- const answers = await inquirer.prompt([
278
- {
279
- type: 'input',
280
- name: 'owner',
281
- message: 'GitHub owner/organization:',
282
- validate: (input) => !!input.trim() || 'Owner is required'
283
- },
284
- {
285
- type: 'input',
286
- name: 'repo',
287
- message: 'Repository name:',
288
- default: path.basename(this.projectPath),
289
- validate: (input) => !!input.trim() || 'Repository name is required'
290
- },
291
- {
292
- type: 'input',
293
- name: 'description',
294
- message: 'Repository description:',
295
- default: 'My SpecWeave project'
296
- },
297
- {
298
- type: 'confirm',
299
- name: 'createOnGitHub',
300
- message: 'Create repository on GitHub?',
301
- default: !hasGit
302
- }
303
- ]);
263
+ const ownerAnswer = await input({
264
+ message: 'GitHub owner/organization:',
265
+ validate: (val) => !!val.trim() || 'Owner is required'
266
+ });
267
+ const repoAnswer = await input({
268
+ message: 'Repository name:',
269
+ default: path.basename(this.projectPath),
270
+ validate: (val) => !!val.trim() || 'Repository name is required'
271
+ });
272
+ const descriptionAnswer = await input({
273
+ message: 'Repository description:',
274
+ default: 'My SpecWeave project'
275
+ });
276
+ const createOnGitHubAnswer = await confirm({
277
+ message: 'Create repository on GitHub?',
278
+ default: !hasGit
279
+ });
280
+ const answers = {
281
+ owner: ownerAnswer,
282
+ repo: repoAnswer,
283
+ description: descriptionAnswer,
284
+ createOnGitHub: createOnGitHubAnswer
285
+ };
304
286
  // Ask about visibility only if creating a new repository
305
287
  let visibility = 'private';
306
288
  if (answers.createOnGitHub) {
307
289
  const visibilityPrompt = getVisibilityPrompt(answers.repo);
308
- const result = await inquirer.prompt([{
309
- type: 'select',
310
- name: 'visibility',
311
- message: visibilityPrompt.question,
312
- choices: visibilityPrompt.options.map(opt => ({
313
- name: `${opt.label}\n${chalk.gray(opt.description)}`,
314
- value: opt.value,
315
- short: opt.label
316
- })),
317
- default: visibilityPrompt.default
318
- }]);
319
- visibility = result.visibility;
290
+ visibility = await select({
291
+ message: visibilityPrompt.question,
292
+ choices: visibilityPrompt.options.map(opt => ({
293
+ name: `${opt.label}\n${chalk.gray(opt.description)}`,
294
+ value: opt.value
295
+ })),
296
+ default: visibilityPrompt.default
297
+ });
320
298
  }
321
299
  return {
322
300
  architecture: 'single',
@@ -380,72 +358,62 @@ export class RepoStructureManager {
380
358
  if (!isLocalParent && this.githubToken && useParent) {
381
359
  console.log(chalk.cyan('\nšŸš€ Repository Discovery\n'));
382
360
  console.log(chalk.gray('You\'re setting up multiple repositories. We can discover them automatically!\n'));
383
- const { configMethod } = await inquirer.prompt([
384
- {
385
- type: 'select',
386
- name: 'configMethod',
387
- message: 'How do you want to configure repositories?',
388
- choices: [
389
- {
390
- name: [
391
- chalk.bold.green('šŸŽÆ Bulk Discovery (RECOMMENDED)'),
392
- chalk.gray(' Automatically discover repos from ' + provider.config.name),
393
- chalk.gray(' • Select parent from discovered list'),
394
- chalk.gray(' • Auto-configure implementation repos'),
395
- chalk.gray(' • Supports: all, pattern, regex filtering'),
396
- ''
397
- ].join('\n'),
398
- value: 'bulk-discovery',
399
- short: 'Bulk Discovery'
400
- },
401
- {
402
- name: [
403
- chalk.bold('āœļø Manual Entry'),
404
- chalk.gray(' Enter each repository manually'),
405
- chalk.gray(' • Full control over settings'),
406
- chalk.gray(' • Best for new repos or custom setup'),
407
- ''
408
- ].join('\n'),
409
- value: 'manual',
410
- short: 'Manual'
411
- }
412
- ],
413
- default: 'bulk-discovery' // Make bulk discovery the default!
414
- }
415
- ]);
361
+ const configMethod = await select({
362
+ message: 'How do you want to configure repositories?',
363
+ choices: [
364
+ {
365
+ name: [
366
+ chalk.bold.green('šŸŽÆ Bulk Discovery (RECOMMENDED)'),
367
+ chalk.gray(' Automatically discover repos from ' + provider.config.name),
368
+ chalk.gray(' • Select parent from discovered list'),
369
+ chalk.gray(' • Auto-configure implementation repos'),
370
+ chalk.gray(' • Supports: all, pattern, regex filtering'),
371
+ ''
372
+ ].join('\n'),
373
+ value: 'bulk-discovery'
374
+ },
375
+ {
376
+ name: [
377
+ chalk.bold('āœļø Manual Entry'),
378
+ chalk.gray(' Enter each repository manually'),
379
+ chalk.gray(' • Full control over settings'),
380
+ chalk.gray(' • Best for new repos or custom setup'),
381
+ ''
382
+ ].join('\n'),
383
+ value: 'manual'
384
+ }
385
+ ],
386
+ default: 'bulk-discovery'
387
+ });
416
388
  discoveryStrategy = configMethod;
417
389
  }
418
390
  // Step 2: If bulk discovery, discover repos FIRST, then ask which is parent
419
391
  if (discoveryStrategy === 'bulk-discovery') {
420
392
  // Get owner FIRST (needed for discovery)
421
393
  console.log(chalk.cyan('\nšŸ‘¤ Repository Owner\n'));
422
- const ownerPrompt = await inquirer.prompt([
423
- {
424
- type: 'input',
425
- name: 'owner',
426
- message: `${provider.config.name} owner/organization:`,
427
- validate: async (input) => {
428
- if (!input.trim())
429
- return 'Owner is required';
430
- // Validate owner exists on the platform
431
- if (this.githubToken) {
432
- const result = await provider.validateOwner(input, this.githubToken);
433
- if (!result.valid) {
434
- return result.error || `Invalid ${provider.config.name} owner`;
435
- }
394
+ owner = await input({
395
+ message: `${provider.config.name} owner/organization:`,
396
+ validate: async (val) => {
397
+ if (!val.trim())
398
+ return 'Owner is required';
399
+ // Validate owner exists on the platform
400
+ if (this.githubToken) {
401
+ const result = await provider.validateOwner(val, this.githubToken);
402
+ if (!result.valid) {
403
+ return result.error || `Invalid ${provider.config.name} owner`;
436
404
  }
437
- return true;
438
405
  }
406
+ return true;
439
407
  }
440
- ]);
441
- owner = ownerPrompt.owner;
408
+ });
442
409
  // Discover repositories via pattern matching
443
410
  const octokit = new Octokit({ auth: this.githubToken });
444
411
  const isOrg = await provider.isOrganization(owner, this.githubToken);
445
412
  // Retry loop for pattern adjustment
446
413
  let discoveryResult = null;
447
414
  while (discoveryResult === null) {
448
- discoveryResult = await discoverRepositories(octokit, owner, isOrg, 0); // Pass 0, we'll count later
415
+ // Discovery-first flow: skip count validation since user discovers THEN selects
416
+ discoveryResult = await discoverRepositories(octokit, owner, isOrg, 0, { skipValidation: true });
449
417
  // If null, user selected "go back and adjust pattern", loop will retry
450
418
  // If user selected "manual", discoveryResult will be { repositories: [], strategy: 'manual' }
451
419
  }
@@ -466,15 +434,11 @@ export class RepoStructureManager {
466
434
  short: 'Enter manually'
467
435
  }
468
436
  ];
469
- const { parentSelection } = await inquirer.prompt([
470
- {
471
- type: 'select',
472
- name: 'parentSelection',
473
- message: 'Which repository is the parent?',
474
- choices: parentChoices,
475
- pageSize: 15
476
- }
477
- ]);
437
+ const parentSelection = await select({
438
+ message: 'Which repository is the parent?',
439
+ choices: parentChoices,
440
+ pageSize: 15
441
+ });
478
442
  if (parentSelection === 'manual') {
479
443
  // User wants to enter parent manually - fall back to old flow
480
444
  discoveryStrategy = 'manual';
@@ -541,106 +505,92 @@ export class RepoStructureManager {
541
505
  // Local parent: Skip GitHub questions, just ask for folder name
542
506
  console.log(chalk.blue('\nšŸ’” Local Parent Folder Setup'));
543
507
  console.log(chalk.gray('This folder will contain .specweave/ but will NOT be pushed to GitHub.\n'));
544
- parentAnswers = await inquirer.prompt([
545
- {
546
- type: 'input',
547
- name: 'parentName',
548
- message: 'Parent folder name:',
549
- default: `${path.basename(this.projectPath)}`,
550
- validate: (input) => {
551
- if (!input.trim())
552
- return 'Folder name is required';
553
- return true;
554
- }
555
- },
556
- {
557
- type: 'input',
558
- name: 'owner',
559
- message: `${provider.config.name} owner/organization for IMPLEMENTATION repos:`,
560
- validate: async (input) => {
561
- if (!input.trim())
562
- return 'Owner is required';
563
- // Validate owner exists on the platform
564
- if (this.githubToken) {
565
- const result = await provider.validateOwner(input, this.githubToken);
566
- if (!result.valid) {
567
- return result.error || `Invalid ${provider.config.name} owner`;
568
- }
508
+ const parentNameAnswer = await input({
509
+ message: 'Parent folder name:',
510
+ default: `${path.basename(this.projectPath)}`,
511
+ validate: (val) => {
512
+ if (!val.trim())
513
+ return 'Folder name is required';
514
+ return true;
515
+ }
516
+ });
517
+ const ownerForLocalAnswer = await input({
518
+ message: `${provider.config.name} owner/organization for IMPLEMENTATION repos:`,
519
+ validate: async (val) => {
520
+ if (!val.trim())
521
+ return 'Owner is required';
522
+ // Validate owner exists on the platform
523
+ if (this.githubToken) {
524
+ const result = await provider.validateOwner(val, this.githubToken);
525
+ if (!result.valid) {
526
+ return result.error || `Invalid ${provider.config.name} owner`;
569
527
  }
570
- return true;
571
528
  }
529
+ return true;
572
530
  }
573
- ]);
531
+ });
532
+ parentAnswers = {
533
+ parentName: parentNameAnswer,
534
+ owner: ownerForLocalAnswer
535
+ };
574
536
  // Set defaults for local parent
575
537
  parentAnswers.description = 'Local parent folder (not synced to GitHub)';
576
538
  parentAnswers.createOnGitHub = false; // Never create GitHub repo for local parent
577
539
  }
578
540
  else {
579
541
  // GitHub parent: First ask if using existing or creating new
580
- const { parentChoice } = await inquirer.prompt([
581
- {
582
- type: 'select',
583
- name: 'parentChoice',
584
- message: 'Parent repository setup:',
585
- choices: [
586
- {
587
- name: `${chalk.green('Use existing parent repository')}\n${chalk.gray('Connect to an existing GitHub repo that already has .specweave/ structure')}`,
588
- value: 'existing',
589
- short: 'Use existing'
590
- },
591
- {
592
- name: `${chalk.blue('Create new parent repository')}\n${chalk.gray('Create a new GitHub repo for specs, docs, and architecture')}`,
593
- value: 'new',
594
- short: 'Create new'
595
- }
596
- ],
597
- default: 'new'
598
- }
599
- ]);
542
+ const parentChoice = await select({
543
+ message: 'Parent repository setup:',
544
+ choices: [
545
+ {
546
+ name: `${chalk.green('Use existing parent repository')}\n${chalk.gray('Connect to an existing GitHub repo that already has .specweave/ structure')}`,
547
+ value: 'existing'
548
+ },
549
+ {
550
+ name: `${chalk.blue('Create new parent repository')}\n${chalk.gray('Create a new GitHub repo for specs, docs, and architecture')}`,
551
+ value: 'new'
552
+ }
553
+ ],
554
+ default: 'new'
555
+ });
600
556
  if (parentChoice === 'existing') {
601
557
  // Using existing parent repository
602
558
  console.log(chalk.cyan('\nšŸ“‹ Existing Parent Repository\n'));
603
559
  // Ask for owner first
604
- const ownerPrompt = await inquirer.prompt([
605
- {
606
- type: 'input',
607
- name: 'owner',
608
- message: `${provider.config.name} owner/organization:`,
609
- validate: async (input) => {
610
- if (!input.trim())
611
- return 'Owner is required';
612
- // Validate owner exists on the platform
613
- if (this.githubToken) {
614
- const result = await provider.validateOwner(input, this.githubToken);
615
- if (!result.valid) {
616
- return result.error || `Invalid ${provider.config.name} owner`;
617
- }
560
+ const existingOwner = await input({
561
+ message: `${provider.config.name} owner/organization:`,
562
+ validate: async (val) => {
563
+ if (!val.trim())
564
+ return 'Owner is required';
565
+ // Validate owner exists on the platform
566
+ if (this.githubToken) {
567
+ const result = await provider.validateOwner(val, this.githubToken);
568
+ if (!result.valid) {
569
+ return result.error || `Invalid ${provider.config.name} owner`;
618
570
  }
619
- return true;
620
571
  }
572
+ return true;
621
573
  }
622
- ]);
574
+ });
575
+ const ownerPrompt = { owner: existingOwner };
623
576
  // Ask for existing repo name
624
- const repoPrompt = await inquirer.prompt([
625
- {
626
- type: 'input',
627
- name: 'parentName',
628
- message: 'Existing parent repository name:',
629
- default: `${path.basename(this.projectPath)}-parent`,
630
- validate: async (input) => {
631
- if (!input.trim())
632
- return 'Repository name is required';
633
- // Validate repository EXISTS on the platform
634
- if (this.githubToken && ownerPrompt.owner) {
635
- const result = await provider.validateRepository(ownerPrompt.owner, input, this.githubToken);
636
- if (!result.exists) {
637
- return `Repository ${ownerPrompt.owner}/${input} not found on ${provider.config.name}. Please check the name or choose 'Create new'.`;
638
- }
577
+ const existingParentName = await input({
578
+ message: 'Existing parent repository name:',
579
+ default: `${path.basename(this.projectPath)}-parent`,
580
+ validate: async (val) => {
581
+ if (!val.trim())
582
+ return 'Repository name is required';
583
+ // Validate repository EXISTS on the platform
584
+ if (this.githubToken && ownerPrompt.owner) {
585
+ const result = await provider.validateRepository(ownerPrompt.owner, val, this.githubToken);
586
+ if (!result.exists) {
587
+ return `Repository ${ownerPrompt.owner}/${val} not found on ${provider.config.name}. Please check the name or choose 'Create new'.`;
639
588
  }
640
- return true;
641
589
  }
590
+ return true;
642
591
  }
643
- ]);
592
+ });
593
+ const repoPrompt = { parentName: existingParentName };
644
594
  // Fetch description and visibility from GitHub API (or use defaults)
645
595
  let description = 'SpecWeave parent repository - specs, docs, and architecture';
646
596
  let existingVisibility = 'private';
@@ -675,60 +625,54 @@ export class RepoStructureManager {
675
625
  // Creating new parent repository
676
626
  console.log(chalk.cyan('\n✨ New Parent Repository\n'));
677
627
  // Ask for owner (separate prompt to avoid validator issues)
678
- const ownerPrompt = await inquirer.prompt([
679
- {
680
- type: 'input',
681
- name: 'owner',
682
- message: `${provider.config.name} owner/organization for ALL repos:`,
683
- validate: async (input) => {
684
- if (!input.trim())
685
- return 'Owner is required';
686
- // Validate owner exists on the platform
687
- if (this.githubToken) {
688
- const result = await provider.validateOwner(input, this.githubToken);
689
- if (!result.valid) {
690
- return result.error || `Invalid ${provider.config.name} owner`;
691
- }
628
+ const newOwner = await input({
629
+ message: `${provider.config.name} owner/organization for ALL repos:`,
630
+ validate: async (val) => {
631
+ if (!val.trim())
632
+ return 'Owner is required';
633
+ // Validate owner exists on the platform
634
+ if (this.githubToken) {
635
+ const result = await provider.validateOwner(val, this.githubToken);
636
+ if (!result.valid) {
637
+ return result.error || `Invalid ${provider.config.name} owner`;
692
638
  }
693
- return true;
694
639
  }
640
+ return true;
695
641
  }
696
- ]);
642
+ });
643
+ const ownerPrompt = { owner: newOwner };
697
644
  // Now ask remaining questions, using the owner value
698
- const remainingAnswers = await inquirer.prompt([
699
- {
700
- type: 'input',
701
- name: 'parentName',
702
- message: 'Parent repository name:',
703
- default: `${path.basename(this.projectPath)}-parent`,
704
- validate: async (input) => {
705
- if (!input.trim())
706
- return 'Repository name is required';
707
- // Validate repository DOESN'T exist
708
- if (this.githubToken && ownerPrompt.owner) {
709
- const result = await provider.validateRepository(ownerPrompt.owner, input, this.githubToken);
710
- if (result.exists) {
711
- return `Repository ${ownerPrompt.owner}/${input} already exists at ${result.url}. Please choose 'Use existing' or pick a different name.`;
712
- }
645
+ const newParentName = await input({
646
+ message: 'Parent repository name:',
647
+ default: `${path.basename(this.projectPath)}-parent`,
648
+ validate: async (val) => {
649
+ if (!val.trim())
650
+ return 'Repository name is required';
651
+ // Validate repository DOESN'T exist
652
+ if (this.githubToken && ownerPrompt.owner) {
653
+ const result = await provider.validateRepository(ownerPrompt.owner, val, this.githubToken);
654
+ if (result.exists) {
655
+ return `Repository ${ownerPrompt.owner}/${val} already exists at ${result.url}. Please choose 'Use existing' or pick a different name.`;
713
656
  }
714
- return true;
715
657
  }
716
- },
717
- {
718
- type: 'input',
719
- name: 'description',
720
- message: 'Parent repository description:',
721
- default: 'SpecWeave parent repository - specs, docs, and architecture'
722
- },
723
- {
724
- type: 'confirm',
725
- name: 'createOnGitHub',
726
- message: 'Create parent repository on GitHub?',
727
- default: true
658
+ return true;
728
659
  }
729
- ]);
660
+ });
661
+ const newParentDesc = await input({
662
+ message: 'Parent repository description:',
663
+ default: 'SpecWeave parent repository - specs, docs, and architecture'
664
+ });
665
+ const createParentOnGitHub = await confirm({
666
+ message: 'Create parent repository on GitHub?',
667
+ default: true
668
+ });
730
669
  // Merge the answers
731
- parentAnswers = { ...ownerPrompt, ...remainingAnswers };
670
+ parentAnswers = {
671
+ ...ownerPrompt,
672
+ parentName: newParentName,
673
+ description: newParentDesc,
674
+ createOnGitHub: createParentOnGitHub
675
+ };
732
676
  }
733
677
  }
734
678
  // Ask about visibility for parent repo (only if creating NEW repo on GitHub)
@@ -736,18 +680,14 @@ export class RepoStructureManager {
736
680
  if (!isLocalParent && parentAnswers.createOnGitHub) {
737
681
  // Only prompt for visibility when creating a NEW repository
738
682
  const parentVisibilityPrompt = getVisibilityPrompt(parentAnswers.parentName);
739
- const result = await inquirer.prompt([{
740
- type: 'select',
741
- name: 'parentVisibility',
742
- message: parentVisibilityPrompt.question,
743
- choices: parentVisibilityPrompt.options.map(opt => ({
744
- name: `${opt.label}\n${chalk.gray(opt.description)}`,
745
- value: opt.value,
746
- short: opt.label
747
- })),
748
- default: parentVisibilityPrompt.default
749
- }]);
750
- parentVisibility = result.parentVisibility;
683
+ parentVisibility = await select({
684
+ message: parentVisibilityPrompt.question,
685
+ choices: parentVisibilityPrompt.options.map(opt => ({
686
+ name: `${opt.label}\n${chalk.gray(opt.description)}`,
687
+ value: opt.value
688
+ })),
689
+ default: parentVisibilityPrompt.default
690
+ });
751
691
  }
752
692
  else if (!isLocalParent && parentAnswers.visibility) {
753
693
  // Use existing repository's visibility (fetched from GitHub API)
@@ -803,24 +743,22 @@ export class RepoStructureManager {
803
743
  console.log(chalk.gray('\nNext question asks for: IMPLEMENTATION repositories ONLY (not counting parent)\n'));
804
744
  }
805
745
  // Ask how many implementation repositories
806
- const promptResult = await inquirer.prompt([{
807
- type: 'number',
808
- name: 'repoCount',
809
- message: useParent
810
- ? 'šŸ“¦ How many IMPLEMENTATION repositories? (not counting parent)'
811
- : 'How many repositories?',
812
- default: hints.suggestedCount, // Use auto-detected count
813
- validate: (input) => {
814
- if (input < 1)
815
- return useParent
816
- ? 'Need at least 1 implementation repository'
817
- : 'Need at least 2 repositories';
818
- if (input > 10)
819
- return 'Maximum 10 repositories supported';
820
- return true;
821
- }
822
- }]);
823
- repoCount = promptResult.repoCount;
746
+ const repoCountAnswer = await number({
747
+ message: useParent
748
+ ? 'šŸ“¦ How many IMPLEMENTATION repositories? (not counting parent)'
749
+ : 'How many repositories?',
750
+ default: hints.suggestedCount, // Use auto-detected count
751
+ validate: (val) => {
752
+ if (val === undefined || val < 1)
753
+ return useParent
754
+ ? 'Need at least 1 implementation repository'
755
+ : 'Need at least 2 repositories';
756
+ if (val > 10)
757
+ return 'Maximum 10 repositories supported';
758
+ return true;
759
+ }
760
+ });
761
+ repoCount = repoCountAnswer ?? hints.suggestedCount;
824
762
  // Show summary AFTER for confirmation
825
763
  if (useParent && config.parentRepo) {
826
764
  if (isLocalParent) {
@@ -873,12 +811,10 @@ export class RepoStructureManager {
873
811
  console.log(chalk.green(` āœ“ Discovered: ${chalk.bold(discoveredRepo.name)}`));
874
812
  console.log(chalk.gray(` Description: ${discoveredRepo.description || '(none)'}`));
875
813
  console.log(chalk.gray(` Visibility: ${discoveredRepo.private ? 'Private' : 'Public'}`));
876
- const { confirmDiscovered } = await inquirer.prompt([{
877
- type: 'confirm',
878
- name: 'confirmDiscovered',
879
- message: 'Use this repository configuration?',
880
- default: true
881
- }]);
814
+ const confirmDiscovered = await confirm({
815
+ message: 'Use this repository configuration?',
816
+ default: true
817
+ });
882
818
  if (!confirmDiscovered) {
883
819
  // Allow manual override
884
820
  console.log(chalk.yellow(` → Switching to manual entry for this repository\n`));
@@ -904,38 +840,39 @@ export class RepoStructureManager {
904
840
  }
905
841
  }
906
842
  // Manual entry (original behavior)
907
- const repoAnswers = await inquirer.prompt([
908
- {
909
- type: 'input',
910
- name: 'name',
911
- message: 'Repository name:',
912
- default: suggestedName,
913
- validate: async (input) => {
914
- if (!input.trim())
915
- return 'Repository name is required';
916
- // Validate repository doesn't exist (skip for discovered repos)
917
- if (!isDiscovered && this.githubToken && config.parentRepo) {
918
- const result = await provider.validateRepository(config.parentRepo.owner, input, this.githubToken);
919
- if (result.exists) {
920
- return `Repository ${config.parentRepo.owner}/${input} already exists at ${result.url}`;
921
- }
843
+ const repoName = await input({
844
+ message: 'Repository name:',
845
+ default: suggestedName,
846
+ validate: async (val) => {
847
+ if (!val.trim())
848
+ return 'Repository name is required';
849
+ // Validate repository doesn't exist (skip for discovered repos)
850
+ if (!isDiscovered && this.githubToken && config.parentRepo) {
851
+ const result = await provider.validateRepository(config.parentRepo.owner, val, this.githubToken);
852
+ if (result.exists) {
853
+ return `Repository ${config.parentRepo.owner}/${val} already exists at ${result.url}`;
922
854
  }
923
- return true;
924
855
  }
925
- },
926
- {
927
- type: 'input',
928
- name: 'description',
929
- message: 'Repository description:',
930
- default: (answers) => `${path.basename(answers.name)} service`
931
- },
932
- {
933
- type: 'confirm',
934
- name: 'createOnGitHub',
935
- message: 'Create this repository on GitHub?',
936
- default: !isDiscovered // Default to true for new repos, false for discovered
856
+ return true;
937
857
  }
938
- ]);
858
+ });
859
+ const repoDescription = await input({
860
+ message: 'Repository description:',
861
+ default: `${path.basename(repoName)} service`
862
+ });
863
+ // Skip "Create on GitHub?" for discovered repos - they already exist!
864
+ let repoCreateOnGitHub = false;
865
+ if (!isDiscovered) {
866
+ repoCreateOnGitHub = await confirm({
867
+ message: 'Create this repository on GitHub?',
868
+ default: true
869
+ });
870
+ }
871
+ const repoAnswers = {
872
+ name: repoName,
873
+ description: repoDescription,
874
+ createOnGitHub: repoCreateOnGitHub
875
+ };
939
876
  // Smart auto-generate ID from repository name (context-aware)
940
877
  const smartId = generateRepoIdSmart(repoAnswers.name, configuredRepoNames);
941
878
  const { id: suggestedId, wasModified } = ensureUniqueId(smartId, usedIds);
@@ -945,31 +882,27 @@ export class RepoStructureManager {
945
882
  if (wasModified) {
946
883
  console.log(chalk.yellow(` āš ļø ID conflict detected: "${smartId}" already used`));
947
884
  console.log(chalk.gray(` → Suggested unique ID: "${suggestedId}"`));
948
- const { confirmId } = await inquirer.prompt([{
949
- type: 'confirm',
950
- name: 'confirmId',
951
- message: `Use "${suggestedId}" as repository ID?`,
952
- default: true
953
- }]);
954
- if (!confirmId) {
955
- const { customId } = await inquirer.prompt([{
956
- type: 'input',
957
- name: 'customId',
958
- message: 'Enter custom repository ID:',
959
- default: suggestedId,
960
- validate: (input) => {
961
- // Validate format
962
- const validation = validateRepoId(input);
963
- if (!validation.valid) {
964
- return validation.error || 'Invalid repository ID';
965
- }
966
- // Validate uniqueness
967
- if (usedIds.has(input)) {
968
- return 'Repository ID must be unique';
969
- }
970
- return true;
885
+ const confirmIdAnswer = await confirm({
886
+ message: `Use "${suggestedId}" as repository ID?`,
887
+ default: true
888
+ });
889
+ if (!confirmIdAnswer) {
890
+ const customId = await input({
891
+ message: 'Enter custom repository ID:',
892
+ default: suggestedId,
893
+ validate: (val) => {
894
+ // Validate format
895
+ const validation = validateRepoId(val);
896
+ if (!validation.valid) {
897
+ return validation.error || 'Invalid repository ID';
898
+ }
899
+ // Validate uniqueness
900
+ if (usedIds.has(val)) {
901
+ return 'Repository ID must be unique';
971
902
  }
972
- }]);
903
+ return true;
904
+ }
905
+ });
973
906
  id = customId;
974
907
  }
975
908
  }
@@ -983,18 +916,14 @@ export class RepoStructureManager {
983
916
  let visibility = 'private';
984
917
  if (repoAnswers.createOnGitHub) {
985
918
  const visibilityPrompt = getVisibilityPrompt(repoAnswers.name);
986
- const result = await inquirer.prompt([{
987
- type: 'select',
988
- name: 'visibility',
989
- message: visibilityPrompt.question,
990
- choices: visibilityPrompt.options.map(opt => ({
991
- name: `${opt.label}\n${chalk.gray(opt.description)}`,
992
- value: opt.value,
993
- short: opt.label
994
- })),
995
- default: visibilityPrompt.default
996
- }]);
997
- visibility = result.visibility;
919
+ visibility = await select({
920
+ message: visibilityPrompt.question,
921
+ choices: visibilityPrompt.options.map(opt => ({
922
+ name: `${opt.label}\n${chalk.gray(opt.description)}`,
923
+ value: opt.value
924
+ })),
925
+ default: visibilityPrompt.default
926
+ });
998
927
  }
999
928
  config.repositories.push({
1000
929
  id: id,
@@ -1044,61 +973,52 @@ export class RepoStructureManager {
1044
973
  async configureMonorepo(urlType = 'ssh', platform = 'github', provider) {
1045
974
  console.log(chalk.cyan('\nšŸ“š Monorepo Configuration\n'));
1046
975
  console.log(chalk.gray('Single repository with multiple projects/packages.\n'));
1047
- const answers = await inquirer.prompt([
1048
- {
1049
- type: 'input',
1050
- name: 'owner',
1051
- message: 'GitHub owner/organization:',
1052
- validate: (input) => !!input.trim() || 'Owner is required'
1053
- },
1054
- {
1055
- type: 'input',
1056
- name: 'repo',
1057
- message: 'Repository name:',
1058
- default: path.basename(this.projectPath),
1059
- validate: (input) => !!input.trim() || 'Repository name is required'
1060
- },
1061
- {
1062
- type: 'input',
1063
- name: 'description',
1064
- message: 'Repository description:',
1065
- default: 'Monorepo project'
1066
- },
1067
- {
1068
- type: 'input',
1069
- name: 'projects',
1070
- message: 'Project names (comma-separated, e.g., frontend,backend,shared):',
1071
- validate: (input) => {
1072
- const projects = input.split(',').map(p => p.trim()).filter(Boolean);
1073
- if (projects.length < 2) {
1074
- return 'Monorepo should have at least 2 projects';
1075
- }
1076
- return true;
976
+ const monoOwner = await input({
977
+ message: 'GitHub owner/organization:',
978
+ validate: (val) => !!val.trim() || 'Owner is required'
979
+ });
980
+ const monoRepo = await input({
981
+ message: 'Repository name:',
982
+ default: path.basename(this.projectPath),
983
+ validate: (val) => !!val.trim() || 'Repository name is required'
984
+ });
985
+ const monoDescription = await input({
986
+ message: 'Repository description:',
987
+ default: 'Monorepo project'
988
+ });
989
+ const monoProjects = await input({
990
+ message: 'Project names (comma-separated, e.g., frontend,backend,shared):',
991
+ validate: (val) => {
992
+ const projects = val.split(',').map(p => p.trim()).filter(Boolean);
993
+ if (projects.length < 2) {
994
+ return 'Monorepo should have at least 2 projects';
1077
995
  }
1078
- },
1079
- {
1080
- type: 'confirm',
1081
- name: 'createOnGitHub',
1082
- message: 'Create repository on GitHub?',
1083
- default: !existsSync(path.join(this.projectPath, '.git'))
996
+ return true;
1084
997
  }
1085
- ]);
998
+ });
999
+ const monoCreateOnGitHub = await confirm({
1000
+ message: 'Create repository on GitHub?',
1001
+ default: !existsSync(path.join(this.projectPath, '.git'))
1002
+ });
1003
+ const answers = {
1004
+ owner: monoOwner,
1005
+ repo: monoRepo,
1006
+ description: monoDescription,
1007
+ projects: monoProjects,
1008
+ createOnGitHub: monoCreateOnGitHub
1009
+ };
1086
1010
  // Ask about visibility only if creating a new repository
1087
1011
  let visibility = 'private';
1088
1012
  if (answers.createOnGitHub) {
1089
1013
  const visibilityPrompt = getVisibilityPrompt(answers.repo);
1090
- const result = await inquirer.prompt([{
1091
- type: 'select',
1092
- name: 'visibility',
1093
- message: visibilityPrompt.question,
1094
- choices: visibilityPrompt.options.map(opt => ({
1095
- name: `${opt.label}\n${chalk.gray(opt.description)}`,
1096
- value: opt.value,
1097
- short: opt.label
1098
- })),
1099
- default: visibilityPrompt.default
1100
- }]);
1101
- visibility = result.visibility;
1014
+ visibility = await select({
1015
+ message: visibilityPrompt.question,
1016
+ choices: visibilityPrompt.options.map(opt => ({
1017
+ name: `${opt.label}\n${chalk.gray(opt.description)}`,
1018
+ value: opt.value
1019
+ })),
1020
+ default: visibilityPrompt.default
1021
+ });
1102
1022
  }
1103
1023
  const projects = answers.projects.split(',').map((p) => p.trim());
1104
1024
  return {