specweave 0.26.13 → 0.27.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 (176) hide show
  1. package/CLAUDE.md +73 -1
  2. package/README.md +111 -466
  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.map +1 -1
  122. package/dist/src/core/repo-structure/repo-bulk-discovery.js +63 -83
  123. package/dist/src/core/repo-structure/repo-bulk-discovery.js.map +1 -1
  124. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  125. package/dist/src/core/repo-structure/repo-structure-manager.js +339 -424
  126. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  127. package/dist/src/core/sync/bidirectional-engine.d.ts.map +1 -1
  128. package/dist/src/core/sync/bidirectional-engine.js +21 -29
  129. package/dist/src/core/sync/bidirectional-engine.js.map +1 -1
  130. package/dist/src/init/InitFlow.js +15 -19
  131. package/dist/src/init/InitFlow.js.map +1 -1
  132. package/dist/src/init/repo/types.d.ts +1 -1
  133. package/dist/src/integrations/ado/area-path-mapper.d.ts.map +1 -1
  134. package/dist/src/integrations/ado/area-path-mapper.js +19 -23
  135. package/dist/src/integrations/ado/area-path-mapper.js.map +1 -1
  136. package/dist/src/utils/external-resource-validator.d.ts.map +1 -1
  137. package/dist/src/utils/external-resource-validator.js +41 -65
  138. package/dist/src/utils/external-resource-validator.js.map +1 -1
  139. package/dist/src/utils/project-detection.d.ts.map +1 -1
  140. package/dist/src/utils/project-detection.js +19 -21
  141. package/dist/src/utils/project-detection.js.map +1 -1
  142. package/dist/src/utils/project-validator.d.ts.map +1 -1
  143. package/dist/src/utils/project-validator.js +5 -7
  144. package/dist/src/utils/project-validator.js.map +1 -1
  145. package/package.json +2 -3
  146. package/plugins/PLUGINS-INDEX.md +120 -0
  147. package/plugins/specweave/agents/tech-lead/AGENT.md +9 -0
  148. package/plugins/specweave/commands/specweave-increment.md +1 -1
  149. package/plugins/specweave/commands/specweave-update-scope.md +2 -2
  150. package/plugins/specweave/hooks/post-user-story-complete.sh +86 -35
  151. package/plugins/specweave/lib/hooks/us-completion-orchestrator.js +62 -1
  152. package/plugins/specweave/lib/hooks/us-completion-orchestrator.ts +106 -3
  153. package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.d.ts +12 -0
  154. package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js +45 -0
  155. package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js.map +1 -1
  156. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +46 -0
  157. package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
  158. package/plugins/specweave/skills/SKILLS-INDEX.md +69 -225
  159. package/plugins/specweave/skills/increment-planner/SKILL.md +10 -5
  160. package/plugins/specweave/skills/specweave-framework/SKILL.md +6 -4
  161. package/plugins/specweave/templates/coding-standards.md.template +36 -0
  162. package/plugins/specweave-ado/commands/specweave-ado-import-projects.md +1 -1
  163. package/plugins/specweave-ado/lib/project-selector.js +56 -67
  164. package/plugins/specweave-ado/lib/project-selector.ts +72 -85
  165. package/plugins/specweave-ado/skills/ado-resource-validator/SKILL.md +1 -1
  166. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +6 -0
  167. package/plugins/specweave-github/lib/repo-selector.js +55 -66
  168. package/plugins/specweave-github/lib/repo-selector.ts +73 -84
  169. package/plugins/specweave-jira/commands/import-projects.js +3 -5
  170. package/plugins/specweave-jira/commands/import-projects.ts +3 -5
  171. package/plugins/specweave-jira/lib/project-selector.js +60 -71
  172. package/plugins/specweave-jira/lib/project-selector.ts +78 -91
  173. package/plugins/specweave-jira/lib/setup-wizard.js +51 -72
  174. package/plugins/specweave-jira/lib/setup-wizard.ts +56 -74
  175. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +9 -0
  176. package/src/templates/CLAUDE.md.template +14 -0
@@ -1,4 +1,4 @@
1
- import inquirer from "inquirer";
1
+ import { select, checkbox, input, Separator } from "@inquirer/prompts";
2
2
  async function fetchAllAdoProjects(client) {
3
3
  console.log("\u{1F50D} Fetching Azure DevOps projects...");
4
4
  try {
@@ -31,29 +31,25 @@ async function selectAdoProjects(client, options = {}) {
31
31
  console.log("\u{1F4CB} Available Azure DevOps Projects:\n");
32
32
  console.log(` Total: ${allProjects.length} projects
33
33
  `);
34
- const { selectionMethod } = await inquirer.prompt([
35
- {
36
- type: "list",
37
- name: "selectionMethod",
38
- message: "How would you like to select projects?",
39
- choices: [
40
- {
41
- name: `\u{1F4CB} Interactive (browse and select from ${allProjects.length} projects)`,
42
- value: "interactive"
43
- },
34
+ const selectionMethod = await select({
35
+ message: "How would you like to select projects?",
36
+ choices: [
37
+ {
38
+ name: `\u{1F4CB} Interactive (browse and select from ${allProjects.length} projects)`,
39
+ value: "interactive"
40
+ },
41
+ {
42
+ name: "\u270F\uFE0F Manual entry (type project names)",
43
+ value: "manual"
44
+ },
45
+ ...allowSelectAll ? [
44
46
  {
45
- name: "\u270F\uFE0F Manual entry (type project names)",
46
- value: "manual"
47
- },
48
- ...allowSelectAll ? [
49
- {
50
- name: `\u2728 Select all (${allProjects.length} projects)`,
51
- value: "all"
52
- }
53
- ] : []
54
- ]
55
- }
56
- ]);
47
+ name: `\u2728 Select all (${allProjects.length} projects)`,
48
+ value: "all"
49
+ }
50
+ ] : []
51
+ ]
52
+ });
57
53
  if (selectionMethod === "all") {
58
54
  return {
59
55
  selectedNames: allProjects.map((p) => p.name),
@@ -73,39 +69,36 @@ async function selectAdoProjects(client, options = {}) {
73
69
  }
74
70
  async function interactiveProjectSelection(allProjects, preSelected, minSelection, maxSelection, pageSize) {
75
71
  console.log("\u{1F4A1} Use <space> to select, <a> to toggle all, <i> to invert\n");
76
- const choices = allProjects.map((p) => ({
77
- name: formatProjectChoice(p),
78
- value: p.name,
79
- checked: preSelected.includes(p.name)
80
- }));
81
- choices.push(
82
- new inquirer.Separator(),
72
+ const choices = [
73
+ ...allProjects.map((p) => ({
74
+ name: formatProjectChoice(p),
75
+ value: p.name,
76
+ checked: preSelected.includes(p.name)
77
+ })),
78
+ // Add separator and manual entry option at the end
79
+ new Separator(),
83
80
  {
84
81
  name: "\u270F\uFE0F Enter project names manually instead",
85
82
  value: "__MANUAL__",
86
83
  checked: false
87
84
  }
88
- );
89
- const { selectedNames } = await inquirer.prompt([
90
- {
91
- type: "checkbox",
92
- name: "selectedNames",
93
- message: `Select Azure DevOps projects (${minSelection}${maxSelection ? `-${maxSelection}` : "+"} required):`,
94
- choices,
95
- pageSize,
96
- loop: false,
97
- validate: (selected) => {
98
- const actualSelected = selected.filter((k) => k !== "__MANUAL__");
99
- if (actualSelected.length < minSelection) {
100
- return `Please select at least ${minSelection} project(s)`;
101
- }
102
- if (maxSelection && actualSelected.length > maxSelection) {
103
- return `Please select at most ${maxSelection} project(s)`;
104
- }
105
- return true;
85
+ ];
86
+ const selectedNames = await checkbox({
87
+ message: `Select Azure DevOps projects (${minSelection}${maxSelection ? `-${maxSelection}` : "+"} required):`,
88
+ choices,
89
+ pageSize,
90
+ loop: false,
91
+ validate: (selected) => {
92
+ const actualSelected = selected.filter((k) => k !== "__MANUAL__");
93
+ if (actualSelected.length < minSelection) {
94
+ return `Please select at least ${minSelection} project(s)`;
106
95
  }
96
+ if (maxSelection && actualSelected.length > maxSelection) {
97
+ return `Please select at most ${maxSelection} project(s)`;
98
+ }
99
+ return true;
107
100
  }
108
- ]);
101
+ });
109
102
  if (selectedNames.includes("__MANUAL__")) {
110
103
  return await manualProjectEntry(allProjects, minSelection, maxSelection);
111
104
  }
@@ -127,26 +120,22 @@ async function manualProjectEntry(allProjects, minSelection, maxSelection) {
127
120
  );
128
121
  console.log("");
129
122
  }
130
- const { manualNames } = await inquirer.prompt([
131
- {
132
- type: "input",
133
- name: "manualNames",
134
- message: "Project names:",
135
- validate: (input) => {
136
- if (!input.trim()) {
137
- return "Please enter at least one project name";
138
- }
139
- const names = input.split(",").map((n) => n.trim()).filter((n) => n.length > 0);
140
- if (names.length < minSelection) {
141
- return `Please enter at least ${minSelection} project name(s)`;
142
- }
143
- if (maxSelection && names.length > maxSelection) {
144
- return `Please enter at most ${maxSelection} project name(s)`;
145
- }
146
- return true;
123
+ const manualNames = await input({
124
+ message: "Project names:",
125
+ validate: (inputValue) => {
126
+ if (!inputValue.trim()) {
127
+ return "Please enter at least one project name";
128
+ }
129
+ const names = inputValue.split(",").map((n) => n.trim()).filter((n) => n.length > 0);
130
+ if (names.length < minSelection) {
131
+ return `Please enter at least ${minSelection} project name(s)`;
147
132
  }
133
+ if (maxSelection && names.length > maxSelection) {
134
+ return `Please enter at most ${maxSelection} project name(s)`;
135
+ }
136
+ return true;
148
137
  }
149
- ]);
138
+ });
150
139
  const selectedNames = manualNames.split(",").map((n) => n.trim()).filter((n) => n.length > 0);
151
140
  const knownNames = allProjects.map((p) => p.name);
152
141
  const unknownNames = selectedNames.filter((n) => !knownNames.includes(n));
@@ -9,7 +9,7 @@
9
9
  * - Validates project names
10
10
  */
11
11
 
12
- import inquirer from 'inquirer';
12
+ import { select, checkbox, input, Separator } from '@inquirer/prompts';
13
13
  import { AdoClient } from '../../../src/integrations/ado/ado-client.js';
14
14
 
15
15
  // ============================================================================
@@ -101,31 +101,27 @@ export async function selectAdoProjects(
101
101
  console.log(` Total: ${allProjects.length} projects\n`);
102
102
 
103
103
  // Decide selection method
104
- const { selectionMethod } = await inquirer.prompt([
105
- {
106
- type: 'list',
107
- name: 'selectionMethod',
108
- message: 'How would you like to select projects?',
109
- choices: [
110
- {
111
- name: `📋 Interactive (browse and select from ${allProjects.length} projects)`,
112
- value: 'interactive',
113
- },
114
- {
115
- name: '✏️ Manual entry (type project names)',
116
- value: 'manual',
117
- },
118
- ...(allowSelectAll
119
- ? [
120
- {
121
- name: `✨ Select all (${allProjects.length} projects)`,
122
- value: 'all',
123
- },
124
- ]
125
- : []),
126
- ],
127
- },
128
- ]);
104
+ const selectionMethod = await select({
105
+ message: 'How would you like to select projects?',
106
+ choices: [
107
+ {
108
+ name: `📋 Interactive (browse and select from ${allProjects.length} projects)`,
109
+ value: 'interactive' as const,
110
+ },
111
+ {
112
+ name: '✏️ Manual entry (type project names)',
113
+ value: 'manual' as const,
114
+ },
115
+ ...(allowSelectAll
116
+ ? [
117
+ {
118
+ name: `✨ Select all (${allProjects.length} projects)`,
119
+ value: 'all' as const,
120
+ },
121
+ ]
122
+ : []),
123
+ ],
124
+ });
129
125
 
130
126
  if (selectionMethod === 'all') {
131
127
  return {
@@ -160,45 +156,40 @@ async function interactiveProjectSelection(
160
156
  ): Promise<ProjectSelectionResult> {
161
157
  console.log('💡 Use <space> to select, <a> to toggle all, <i> to invert\n');
162
158
 
163
- const choices = allProjects.map((p) => ({
164
- name: formatProjectChoice(p),
165
- value: p.name,
166
- checked: preSelected.includes(p.name),
167
- }));
168
-
169
- // Add manual entry option at the end
170
- choices.push(
171
- new inquirer.Separator(),
159
+ const choices = [
160
+ ...allProjects.map((p) => ({
161
+ name: formatProjectChoice(p),
162
+ value: p.name,
163
+ checked: preSelected.includes(p.name),
164
+ })),
165
+ // Add separator and manual entry option at the end
166
+ new Separator(),
172
167
  {
173
168
  name: '✏️ Enter project names manually instead',
174
169
  value: '__MANUAL__',
175
170
  checked: false,
176
- } as any
177
- );
171
+ },
172
+ ];
178
173
 
179
- const { selectedNames } = await inquirer.prompt([
180
- {
181
- type: 'checkbox',
182
- name: 'selectedNames',
183
- message: `Select Azure DevOps projects (${minSelection}${maxSelection ? `-${maxSelection}` : '+'} required):`,
184
- choices,
185
- pageSize,
186
- loop: false,
187
- validate: (selected: string[]) => {
188
- const actualSelected = selected.filter((k) => k !== '__MANUAL__');
189
-
190
- if (actualSelected.length < minSelection) {
191
- return `Please select at least ${minSelection} project(s)`;
192
- }
193
-
194
- if (maxSelection && actualSelected.length > maxSelection) {
195
- return `Please select at most ${maxSelection} project(s)`;
196
- }
197
-
198
- return true;
199
- },
174
+ const selectedNames = await checkbox({
175
+ message: `Select Azure DevOps projects (${minSelection}${maxSelection ? `-${maxSelection}` : '+'} required):`,
176
+ choices,
177
+ pageSize,
178
+ loop: false,
179
+ validate: (selected: readonly string[]) => {
180
+ const actualSelected = selected.filter((k) => k !== '__MANUAL__');
181
+
182
+ if (actualSelected.length < minSelection) {
183
+ return `Please select at least ${minSelection} project(s)`;
184
+ }
185
+
186
+ if (maxSelection && actualSelected.length > maxSelection) {
187
+ return `Please select at most ${maxSelection} project(s)`;
188
+ }
189
+
190
+ return true;
200
191
  },
201
- ]);
192
+ });
202
193
 
203
194
  // Check if user chose manual entry
204
195
  if (selectedNames.includes('__MANUAL__')) {
@@ -235,33 +226,29 @@ async function manualProjectEntry(
235
226
  console.log('');
236
227
  }
237
228
 
238
- const { manualNames } = await inquirer.prompt([
239
- {
240
- type: 'input',
241
- name: 'manualNames',
242
- message: 'Project names:',
243
- validate: (input: string) => {
244
- if (!input.trim()) {
245
- return 'Please enter at least one project name';
246
- }
247
-
248
- const names = input
249
- .split(',')
250
- .map((n) => n.trim())
251
- .filter((n) => n.length > 0);
252
-
253
- if (names.length < minSelection) {
254
- return `Please enter at least ${minSelection} project name(s)`;
255
- }
256
-
257
- if (maxSelection && names.length > maxSelection) {
258
- return `Please enter at most ${maxSelection} project name(s)`;
259
- }
260
-
261
- return true;
262
- },
229
+ const manualNames = await input({
230
+ message: 'Project names:',
231
+ validate: (inputValue: string) => {
232
+ if (!inputValue.trim()) {
233
+ return 'Please enter at least one project name';
234
+ }
235
+
236
+ const names = inputValue
237
+ .split(',')
238
+ .map((n) => n.trim())
239
+ .filter((n) => n.length > 0);
240
+
241
+ if (names.length < minSelection) {
242
+ return `Please enter at least ${minSelection} project name(s)`;
243
+ }
244
+
245
+ if (maxSelection && names.length > maxSelection) {
246
+ return `Please enter at most ${maxSelection} project name(s)`;
247
+ }
248
+
249
+ return true;
263
250
  },
264
- ]);
251
+ });
265
252
 
266
253
  const selectedNames = manualNames
267
254
  .split(',')
@@ -428,7 +428,7 @@ export async function validateAzureDevOpsResources(
428
428
  ```typescript
429
429
  const { action } = await inquirer.prompt([
430
430
  {
431
- type: 'list',
431
+ type: 'select',
432
432
  name: 'action',
433
433
  message: `Project "${projectName}" not found. What would you like to do?`,
434
434
  choices: [
@@ -1096,3 +1096,9 @@
1096
1096
  [Mon Nov 24 15:02:47 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
1097
1097
  [Mon Nov 24 15:02:47 EST 2025] [GitHub] 🔗 GitHub sync hook fired
1098
1098
  [Mon Nov 24 15:02:47 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
1099
+ [Mon Nov 24 22:24:34 EST 2025] [GitHub] 🔗 GitHub sync hook fired
1100
+ [Mon Nov 24 22:24:34 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
1101
+ [Mon Nov 24 22:24:34 EST 2025] [GitHub] 🔗 GitHub sync hook fired
1102
+ [Mon Nov 24 22:24:34 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
1103
+ [Mon Nov 24 22:24:34 EST 2025] [GitHub] 🔗 GitHub sync hook fired
1104
+ [Mon Nov 24 22:24:34 EST 2025] [GitHub] ⚠️ sync-spec-content CLI not found at /Users/antonabyzov/Projects/github/specweave/plugins/specweave-github/hooks/dist/src/cli/commands/sync-spec-content.js, skipping sync
@@ -1,4 +1,4 @@
1
- import inquirer from "inquirer";
1
+ import { select, checkbox, input, Separator } from "@inquirer/prompts";
2
2
  import { GitHubClient } from "./github-client.js";
3
3
  async function fetchAllGitHubRepos(owner, limit = 100) {
4
4
  console.log("\u{1F50D} Fetching GitHub repositories...");
@@ -34,29 +34,25 @@ async function selectGitHubRepos(options = {}) {
34
34
  console.log("\u{1F4CB} Available GitHub Repositories:\n");
35
35
  console.log(` Total: ${allRepos.length} repositories
36
36
  `);
37
- const { selectionMethod } = await inquirer.prompt([
38
- {
39
- type: "list",
40
- name: "selectionMethod",
41
- message: "How would you like to select repositories?",
42
- choices: [
43
- {
44
- name: `\u{1F4CB} Interactive (browse and select from ${allRepos.length} repositories)`,
45
- value: "interactive"
46
- },
37
+ const selectionMethod = await select({
38
+ message: "How would you like to select repositories?",
39
+ choices: [
40
+ {
41
+ name: `\u{1F4CB} Interactive (browse and select from ${allRepos.length} repositories)`,
42
+ value: "interactive"
43
+ },
44
+ {
45
+ name: "\u270F\uFE0F Manual entry (type repository names)",
46
+ value: "manual"
47
+ },
48
+ ...allowSelectAll ? [
47
49
  {
48
- name: "\u270F\uFE0F Manual entry (type repository names)",
49
- value: "manual"
50
- },
51
- ...allowSelectAll ? [
52
- {
53
- name: `\u2728 Select all (${allRepos.length} repositories)`,
54
- value: "all"
55
- }
56
- ] : []
57
- ]
58
- }
59
- ]);
50
+ name: `\u2728 Select all (${allRepos.length} repositories)`,
51
+ value: "all"
52
+ }
53
+ ] : []
54
+ ]
55
+ });
60
56
  if (selectionMethod === "all") {
61
57
  return {
62
58
  selectedRepos: allRepos.map((r) => r.fullName),
@@ -81,34 +77,31 @@ async function interactiveRepoSelection(allRepos, preSelected, minSelection, max
81
77
  value: r.fullName,
82
78
  checked: preSelected.includes(r.fullName)
83
79
  }));
84
- choices.push(
85
- new inquirer.Separator(),
80
+ const allChoices = [
81
+ ...choices,
82
+ new Separator(),
86
83
  {
87
84
  name: "\u270F\uFE0F Enter repository names manually instead",
88
85
  value: "__MANUAL__",
89
86
  checked: false
90
87
  }
91
- );
92
- const { selectedRepos } = await inquirer.prompt([
93
- {
94
- type: "checkbox",
95
- name: "selectedRepos",
96
- message: `Select GitHub repositories (${minSelection}${maxSelection ? `-${maxSelection}` : "+"} required):`,
97
- choices,
98
- pageSize,
99
- loop: false,
100
- validate: (selected) => {
101
- const actualSelected = selected.filter((k) => k !== "__MANUAL__");
102
- if (actualSelected.length < minSelection) {
103
- return `Please select at least ${minSelection} repository(ies)`;
104
- }
105
- if (maxSelection && actualSelected.length > maxSelection) {
106
- return `Please select at most ${maxSelection} repository(ies)`;
107
- }
108
- return true;
88
+ ];
89
+ const selectedRepos = await checkbox({
90
+ message: `Select GitHub repositories (${minSelection}${maxSelection ? `-${maxSelection}` : "+"} required):`,
91
+ choices: allChoices,
92
+ pageSize,
93
+ loop: false,
94
+ validate: (selected) => {
95
+ const actualSelected = selected.filter((k) => k !== "__MANUAL__");
96
+ if (actualSelected.length < minSelection) {
97
+ return `Please select at least ${minSelection} repository(ies)`;
98
+ }
99
+ if (maxSelection && actualSelected.length > maxSelection) {
100
+ return `Please select at most ${maxSelection} repository(ies)`;
109
101
  }
102
+ return true;
110
103
  }
111
- ]);
104
+ });
112
105
  if (selectedRepos.includes("__MANUAL__")) {
113
106
  return await manualRepoEntry(allRepos, minSelection, maxSelection);
114
107
  }
@@ -130,30 +123,26 @@ async function manualRepoEntry(allRepos, minSelection, maxSelection) {
130
123
  );
131
124
  console.log("");
132
125
  }
133
- const { manualRepos } = await inquirer.prompt([
134
- {
135
- type: "input",
136
- name: "manualRepos",
137
- message: "Repository names:",
138
- validate: (input) => {
139
- if (!input.trim()) {
140
- return "Please enter at least one repository name";
141
- }
142
- const repos = input.split(",").map((r) => r.trim()).filter((r) => r.length > 0);
143
- if (repos.length < minSelection) {
144
- return `Please enter at least ${minSelection} repository name(s)`;
145
- }
146
- if (maxSelection && repos.length > maxSelection) {
147
- return `Please enter at most ${maxSelection} repository name(s)`;
148
- }
149
- const invalidRepos = repos.filter((r) => !/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+$/.test(r));
150
- if (invalidRepos.length > 0) {
151
- return `Invalid repository format: ${invalidRepos.join(", ")}. Use owner/repo format (e.g., octocat/Hello-World).`;
152
- }
153
- return true;
126
+ const manualRepos = await input({
127
+ message: "Repository names:",
128
+ validate: (inputValue) => {
129
+ if (!inputValue.trim()) {
130
+ return "Please enter at least one repository name";
131
+ }
132
+ const repos = inputValue.split(",").map((r) => r.trim()).filter((r) => r.length > 0);
133
+ if (repos.length < minSelection) {
134
+ return `Please enter at least ${minSelection} repository name(s)`;
135
+ }
136
+ if (maxSelection && repos.length > maxSelection) {
137
+ return `Please enter at most ${maxSelection} repository name(s)`;
154
138
  }
139
+ const invalidRepos = repos.filter((r) => !/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+$/.test(r));
140
+ if (invalidRepos.length > 0) {
141
+ return `Invalid repository format: ${invalidRepos.join(", ")}. Use owner/repo format (e.g., octocat/Hello-World).`;
142
+ }
143
+ return true;
155
144
  }
156
- ]);
145
+ });
157
146
  const selectedRepos = manualRepos.split(",").map((r) => r.trim()).filter((r) => r.length > 0);
158
147
  const knownRepos = allRepos.map((r) => r.fullName);
159
148
  const unknownRepos = selectedRepos.filter((r) => !knownRepos.includes(r));