opencode-conductor-cdd-plugin 1.0.0-beta.18 → 1.0.0-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/prompts/cdd/setup.json +2 -2
- package/dist/prompts/cdd/setup.test.js +40 -118
- package/dist/prompts/cdd/setup.test.ts +40 -143
- package/dist/utils/codebaseAnalysis.d.ts +61 -0
- package/dist/utils/codebaseAnalysis.js +429 -0
- package/dist/utils/codebaseAnalysis.test.d.ts +1 -0
- package/dist/utils/codebaseAnalysis.test.js +556 -0
- package/dist/utils/documentGeneration.d.ts +97 -0
- package/dist/utils/documentGeneration.js +301 -0
- package/dist/utils/documentGeneration.test.d.ts +1 -0
- package/dist/utils/documentGeneration.test.js +380 -0
- package/dist/utils/interactiveMenu.d.ts +56 -0
- package/dist/utils/interactiveMenu.js +144 -0
- package/dist/utils/interactiveMenu.test.d.ts +1 -0
- package/dist/utils/interactiveMenu.test.js +231 -0
- package/dist/utils/interactiveSetup.d.ts +43 -0
- package/dist/utils/interactiveSetup.js +131 -0
- package/dist/utils/interactiveSetup.test.d.ts +1 -0
- package/dist/utils/interactiveSetup.test.js +124 -0
- package/dist/utils/projectMaturity.d.ts +53 -0
- package/dist/utils/projectMaturity.js +179 -0
- package/dist/utils/projectMaturity.test.d.ts +1 -0
- package/dist/utils/projectMaturity.test.js +298 -0
- package/dist/utils/questionGenerator.d.ts +51 -0
- package/dist/utils/questionGenerator.js +535 -0
- package/dist/utils/questionGenerator.test.d.ts +1 -0
- package/dist/utils/questionGenerator.test.js +328 -0
- package/dist/utils/setupIntegration.d.ts +72 -0
- package/dist/utils/setupIntegration.js +179 -0
- package/dist/utils/setupIntegration.test.d.ts +1 -0
- package/dist/utils/setupIntegration.test.js +344 -0
- package/package.json +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { CodebaseAnalysis } from './codebaseAnalysis.js';
|
|
2
|
+
/**
|
|
3
|
+
* Question Generation Engine
|
|
4
|
+
*
|
|
5
|
+
* Generates context-aware questions for the CDD setup process:
|
|
6
|
+
* - Classifies questions as Additive (multiple) or Exclusive (single choice)
|
|
7
|
+
* - Generates brownfield questions based on codebase analysis
|
|
8
|
+
* - Generates greenfield questions based on common patterns
|
|
9
|
+
* - Creates 5 answer options (A-C: contextual, D: custom, E: autogenerate)
|
|
10
|
+
*
|
|
11
|
+
* Based on reference implementations:
|
|
12
|
+
* - derekbar90/opencode-conductor
|
|
13
|
+
* - gemini-cli-extensions/conductor
|
|
14
|
+
*/
|
|
15
|
+
export type QuestionType = 'additive' | 'exclusive';
|
|
16
|
+
export type Section = 'product' | 'guidelines' | 'tech-stack' | 'styleguides' | 'workflow';
|
|
17
|
+
export interface Question {
|
|
18
|
+
id: string;
|
|
19
|
+
text: string;
|
|
20
|
+
type: QuestionType;
|
|
21
|
+
section: Section;
|
|
22
|
+
options: string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Classify question type based on question text
|
|
26
|
+
*/
|
|
27
|
+
export declare function classifyQuestionType(questionText: string): QuestionType;
|
|
28
|
+
/**
|
|
29
|
+
* Add suffix to question text based on type
|
|
30
|
+
*/
|
|
31
|
+
export declare function addQuestionSuffix(questionText: string, type: QuestionType): string;
|
|
32
|
+
/**
|
|
33
|
+
* Generate brownfield questions based on codebase analysis
|
|
34
|
+
*/
|
|
35
|
+
export declare function generateBrownfieldQuestions(section: Section, analysis: CodebaseAnalysis): Question[];
|
|
36
|
+
/**
|
|
37
|
+
* Generate greenfield questions based on common patterns
|
|
38
|
+
*/
|
|
39
|
+
export declare function generateGreenfieldQuestions(section: Section): Question[];
|
|
40
|
+
/**
|
|
41
|
+
* Generate answer options (always 5 options: A-C contextual, D custom, E autogenerate)
|
|
42
|
+
*/
|
|
43
|
+
export declare function generateAnswerOptions(contextualOptions: string[], section: Section): string[];
|
|
44
|
+
/**
|
|
45
|
+
* Format question for display with lettered options
|
|
46
|
+
*/
|
|
47
|
+
export declare function formatQuestion(question: Question, questionNumber: number): string;
|
|
48
|
+
/**
|
|
49
|
+
* Main function: Generate questions for a section
|
|
50
|
+
*/
|
|
51
|
+
export declare function generateQuestionsForSection(section: Section, projectMaturity: 'brownfield' | 'greenfield', codebaseAnalysis?: CodebaseAnalysis): Question[];
|
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure question has exactly 5 options (A-E)
|
|
3
|
+
* Options D and E are always "Custom" and "Auto-generate"
|
|
4
|
+
*/
|
|
5
|
+
function ensureFiveOptions(question) {
|
|
6
|
+
const options = [...question.options];
|
|
7
|
+
// Trim to 3 contextual options (A, B, C)
|
|
8
|
+
while (options.length > 3) {
|
|
9
|
+
options.pop();
|
|
10
|
+
}
|
|
11
|
+
// Add D (Custom) and E (Auto-generate)
|
|
12
|
+
options.push('Enter custom text');
|
|
13
|
+
options.push(`Auto-generate ${question.section} from context`);
|
|
14
|
+
return {
|
|
15
|
+
...question,
|
|
16
|
+
options,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Classify question type based on question text
|
|
21
|
+
*/
|
|
22
|
+
export function classifyQuestionType(questionText) {
|
|
23
|
+
const lowerText = questionText.toLowerCase();
|
|
24
|
+
// Exclusive indicators (single choice)
|
|
25
|
+
const exclusiveKeywords = [
|
|
26
|
+
'what is the',
|
|
27
|
+
'which one',
|
|
28
|
+
'select one',
|
|
29
|
+
'choose one',
|
|
30
|
+
'primary',
|
|
31
|
+
'main',
|
|
32
|
+
'or',
|
|
33
|
+
];
|
|
34
|
+
// Additive indicators (multiple choices)
|
|
35
|
+
const additiveKeywords = [
|
|
36
|
+
'what are',
|
|
37
|
+
'which',
|
|
38
|
+
'all',
|
|
39
|
+
'select all',
|
|
40
|
+
'features',
|
|
41
|
+
'capabilities',
|
|
42
|
+
'and',
|
|
43
|
+
];
|
|
44
|
+
// Check for exclusive indicators first (more specific)
|
|
45
|
+
for (const keyword of exclusiveKeywords) {
|
|
46
|
+
if (lowerText.includes(keyword)) {
|
|
47
|
+
return 'exclusive';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Check for additive indicators
|
|
51
|
+
for (const keyword of additiveKeywords) {
|
|
52
|
+
if (lowerText.includes(keyword)) {
|
|
53
|
+
return 'additive';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Default to exclusive for safety
|
|
57
|
+
return 'exclusive';
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Add suffix to question text based on type
|
|
61
|
+
*/
|
|
62
|
+
export function addQuestionSuffix(questionText, type) {
|
|
63
|
+
if (type === 'additive') {
|
|
64
|
+
return `${questionText} (Select all that apply)`;
|
|
65
|
+
}
|
|
66
|
+
return questionText;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Generate brownfield questions based on codebase analysis
|
|
70
|
+
*/
|
|
71
|
+
export function generateBrownfieldQuestions(section, analysis) {
|
|
72
|
+
const questions = [];
|
|
73
|
+
switch (section) {
|
|
74
|
+
case 'product':
|
|
75
|
+
questions.push(...generateProductQuestionsBrownfield(analysis));
|
|
76
|
+
break;
|
|
77
|
+
case 'guidelines':
|
|
78
|
+
questions.push(...generateGuidelinesQuestionsBrownfield(analysis));
|
|
79
|
+
break;
|
|
80
|
+
case 'tech-stack':
|
|
81
|
+
questions.push(...generateTechStackQuestionsBrownfield(analysis));
|
|
82
|
+
break;
|
|
83
|
+
case 'styleguides':
|
|
84
|
+
questions.push(...generateStyleguidesQuestionsBrownfield(analysis));
|
|
85
|
+
break;
|
|
86
|
+
case 'workflow':
|
|
87
|
+
questions.push(...generateWorkflowQuestionsBrownfield(analysis));
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
// Ensure all questions have exactly 5 options (A-E)
|
|
91
|
+
const questionsWithFiveOptions = questions.map(ensureFiveOptions);
|
|
92
|
+
// Limit to max 5 questions per section
|
|
93
|
+
return questionsWithFiveOptions.slice(0, 5);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Generate greenfield questions based on common patterns
|
|
97
|
+
*/
|
|
98
|
+
export function generateGreenfieldQuestions(section) {
|
|
99
|
+
let questions = [];
|
|
100
|
+
switch (section) {
|
|
101
|
+
case 'product':
|
|
102
|
+
questions = generateProductQuestionsGreenfield();
|
|
103
|
+
break;
|
|
104
|
+
case 'guidelines':
|
|
105
|
+
questions = generateGuidelinesQuestionsGreenfield();
|
|
106
|
+
break;
|
|
107
|
+
case 'tech-stack':
|
|
108
|
+
questions = generateTechStackQuestionsGreenfield();
|
|
109
|
+
break;
|
|
110
|
+
case 'styleguides':
|
|
111
|
+
questions = generateStyleguidesQuestionsGreenfield();
|
|
112
|
+
break;
|
|
113
|
+
case 'workflow':
|
|
114
|
+
questions = generateWorkflowQuestionsGreenfield();
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
// Ensure all questions have exactly 5 options (A-E)
|
|
118
|
+
const questionsWithFiveOptions = questions.map(ensureFiveOptions);
|
|
119
|
+
// Limit to max 5 questions per section
|
|
120
|
+
return questionsWithFiveOptions.slice(0, 5);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Product section - Brownfield
|
|
124
|
+
*/
|
|
125
|
+
function generateProductQuestionsBrownfield(analysis) {
|
|
126
|
+
const questions = [];
|
|
127
|
+
// Question 1: Refine project goal
|
|
128
|
+
const goalHint = analysis.projectGoal || 'this project';
|
|
129
|
+
questions.push({
|
|
130
|
+
id: 'product_goal',
|
|
131
|
+
text: `Based on "${goalHint}", what is the primary goal?`,
|
|
132
|
+
type: 'exclusive',
|
|
133
|
+
section: 'product',
|
|
134
|
+
options: [
|
|
135
|
+
'Deliver a production-ready application',
|
|
136
|
+
'Create a proof-of-concept or prototype',
|
|
137
|
+
'Build an internal tool or utility',
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
// Question 2: Target users
|
|
141
|
+
questions.push({
|
|
142
|
+
id: 'product_users',
|
|
143
|
+
text: 'Who are the target users?',
|
|
144
|
+
type: 'additive',
|
|
145
|
+
section: 'product',
|
|
146
|
+
options: [
|
|
147
|
+
'End consumers (B2C)',
|
|
148
|
+
'Business clients (B2B)',
|
|
149
|
+
'Internal team members',
|
|
150
|
+
],
|
|
151
|
+
});
|
|
152
|
+
// Question 3: Key features
|
|
153
|
+
questions.push({
|
|
154
|
+
id: 'product_features',
|
|
155
|
+
text: 'What are the key features to document?',
|
|
156
|
+
type: 'additive',
|
|
157
|
+
section: 'product',
|
|
158
|
+
options: generateContextualFeatures(analysis),
|
|
159
|
+
});
|
|
160
|
+
return questions;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Product section - Greenfield
|
|
164
|
+
*/
|
|
165
|
+
function generateProductQuestionsGreenfield() {
|
|
166
|
+
return [
|
|
167
|
+
{
|
|
168
|
+
id: 'product_goal',
|
|
169
|
+
text: 'What is the primary goal of this project?',
|
|
170
|
+
type: 'exclusive',
|
|
171
|
+
section: 'product',
|
|
172
|
+
options: [
|
|
173
|
+
'Deliver a production-ready application',
|
|
174
|
+
'Create a proof-of-concept or prototype',
|
|
175
|
+
'Build an internal tool or utility',
|
|
176
|
+
],
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
id: 'product_users',
|
|
180
|
+
text: 'Who are the target users?',
|
|
181
|
+
type: 'additive',
|
|
182
|
+
section: 'product',
|
|
183
|
+
options: [
|
|
184
|
+
'End consumers (B2C)',
|
|
185
|
+
'Business clients (B2B)',
|
|
186
|
+
'Internal team members',
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
id: 'product_features',
|
|
191
|
+
text: 'What are the core features?',
|
|
192
|
+
type: 'additive',
|
|
193
|
+
section: 'product',
|
|
194
|
+
options: [
|
|
195
|
+
'User authentication and authorization',
|
|
196
|
+
'Data management (CRUD operations)',
|
|
197
|
+
'Real-time notifications or updates',
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
];
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Guidelines section - Brownfield
|
|
204
|
+
*/
|
|
205
|
+
function generateGuidelinesQuestionsBrownfield(analysis) {
|
|
206
|
+
return [
|
|
207
|
+
{
|
|
208
|
+
id: 'guidelines_tone',
|
|
209
|
+
text: 'What tone should the documentation use?',
|
|
210
|
+
type: 'exclusive',
|
|
211
|
+
section: 'guidelines',
|
|
212
|
+
options: [
|
|
213
|
+
'Professional and formal',
|
|
214
|
+
'Friendly and conversational',
|
|
215
|
+
'Technical and precise',
|
|
216
|
+
],
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
id: 'guidelines_audience',
|
|
220
|
+
text: 'Who is the primary audience for documentation?',
|
|
221
|
+
type: 'exclusive',
|
|
222
|
+
section: 'guidelines',
|
|
223
|
+
options: [
|
|
224
|
+
'Developers (internal team)',
|
|
225
|
+
'External contributors (open source)',
|
|
226
|
+
'End users (product documentation)',
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
];
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Guidelines section - Greenfield
|
|
233
|
+
*/
|
|
234
|
+
function generateGuidelinesQuestionsGreenfield() {
|
|
235
|
+
return [
|
|
236
|
+
{
|
|
237
|
+
id: 'guidelines_tone',
|
|
238
|
+
text: 'What tone should the documentation use?',
|
|
239
|
+
type: 'exclusive',
|
|
240
|
+
section: 'guidelines',
|
|
241
|
+
options: [
|
|
242
|
+
'Professional and formal',
|
|
243
|
+
'Friendly and conversational',
|
|
244
|
+
'Technical and precise',
|
|
245
|
+
],
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
id: 'guidelines_audience',
|
|
249
|
+
text: 'Who is the primary audience for documentation?',
|
|
250
|
+
type: 'exclusive',
|
|
251
|
+
section: 'guidelines',
|
|
252
|
+
options: [
|
|
253
|
+
'Developers (internal team)',
|
|
254
|
+
'External contributors (open source)',
|
|
255
|
+
'End users (product documentation)',
|
|
256
|
+
],
|
|
257
|
+
},
|
|
258
|
+
];
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Tech Stack section - Brownfield
|
|
262
|
+
*/
|
|
263
|
+
function generateTechStackQuestionsBrownfield(analysis) {
|
|
264
|
+
const questions = [];
|
|
265
|
+
// Generate language-specific question
|
|
266
|
+
const languages = Object.keys(analysis.languages);
|
|
267
|
+
if (languages.length > 0) {
|
|
268
|
+
const topLanguages = languages.slice(0, 3);
|
|
269
|
+
questions.push({
|
|
270
|
+
id: 'techstack_languages',
|
|
271
|
+
text: 'Confirm the primary programming languages:',
|
|
272
|
+
type: 'additive',
|
|
273
|
+
section: 'tech-stack',
|
|
274
|
+
options: topLanguages.length >= 3 ? topLanguages : [
|
|
275
|
+
...topLanguages,
|
|
276
|
+
...['TypeScript', 'Python', 'Go'].filter(l => !topLanguages.includes(l)),
|
|
277
|
+
].slice(0, 3),
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
// Generate framework question
|
|
281
|
+
const allFrameworks = [...analysis.frameworks.frontend, ...analysis.frameworks.backend];
|
|
282
|
+
if (allFrameworks.length > 0) {
|
|
283
|
+
// Ensure we have exactly 3 options
|
|
284
|
+
const frameworkOptions = allFrameworks.slice(0, 3);
|
|
285
|
+
while (frameworkOptions.length < 3) {
|
|
286
|
+
const fallbacks = ['React', 'Express', 'Django', 'Vue', 'Spring Boot'];
|
|
287
|
+
const missing = fallbacks.find(f => !frameworkOptions.includes(f));
|
|
288
|
+
if (missing)
|
|
289
|
+
frameworkOptions.push(missing);
|
|
290
|
+
else
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
questions.push({
|
|
294
|
+
id: 'techstack_frameworks',
|
|
295
|
+
text: 'Confirm the frameworks in use:',
|
|
296
|
+
type: 'additive',
|
|
297
|
+
section: 'tech-stack',
|
|
298
|
+
options: frameworkOptions.slice(0, 3),
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
// Generate database question
|
|
302
|
+
if (analysis.databases.length > 0) {
|
|
303
|
+
// Ensure we have exactly 3 options
|
|
304
|
+
const dbOptions = analysis.databases.slice(0, 3);
|
|
305
|
+
while (dbOptions.length < 3) {
|
|
306
|
+
const fallbacks = ['PostgreSQL', 'MySQL', 'MongoDB', 'Redis'];
|
|
307
|
+
const missing = fallbacks.find(f => !dbOptions.includes(f));
|
|
308
|
+
if (missing)
|
|
309
|
+
dbOptions.push(missing);
|
|
310
|
+
else
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
questions.push({
|
|
314
|
+
id: 'techstack_databases',
|
|
315
|
+
text: 'Confirm the databases in use:',
|
|
316
|
+
type: 'additive',
|
|
317
|
+
section: 'tech-stack',
|
|
318
|
+
options: dbOptions.slice(0, 3),
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
// Generate architecture question
|
|
322
|
+
if (analysis.architecture.length > 0 && !analysis.architecture.includes('unknown')) {
|
|
323
|
+
const archOptions = analysis.architecture.map(arch => {
|
|
324
|
+
return arch.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
|
325
|
+
});
|
|
326
|
+
// Ensure we have exactly 3 options
|
|
327
|
+
while (archOptions.length < 3) {
|
|
328
|
+
const fallbacks = ['Monorepo', 'Microservices', 'MVC', 'Layered Architecture'];
|
|
329
|
+
const missing = fallbacks.find(f => !archOptions.includes(f));
|
|
330
|
+
if (missing)
|
|
331
|
+
archOptions.push(missing);
|
|
332
|
+
else
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
questions.push({
|
|
336
|
+
id: 'techstack_architecture',
|
|
337
|
+
text: 'Confirm the architectural pattern:',
|
|
338
|
+
type: 'additive',
|
|
339
|
+
section: 'tech-stack',
|
|
340
|
+
options: archOptions.slice(0, 3),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
return questions;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Tech Stack section - Greenfield
|
|
347
|
+
*/
|
|
348
|
+
function generateTechStackQuestionsGreenfield() {
|
|
349
|
+
return [
|
|
350
|
+
{
|
|
351
|
+
id: 'techstack_languages',
|
|
352
|
+
text: 'What programming languages will you use?',
|
|
353
|
+
type: 'additive',
|
|
354
|
+
section: 'tech-stack',
|
|
355
|
+
options: [
|
|
356
|
+
'TypeScript',
|
|
357
|
+
'Python',
|
|
358
|
+
'Go',
|
|
359
|
+
],
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
id: 'techstack_frontend',
|
|
363
|
+
text: 'What frontend framework will you use?',
|
|
364
|
+
type: 'exclusive',
|
|
365
|
+
section: 'tech-stack',
|
|
366
|
+
options: [
|
|
367
|
+
'React',
|
|
368
|
+
'Vue',
|
|
369
|
+
'Angular',
|
|
370
|
+
],
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
id: 'techstack_backend',
|
|
374
|
+
text: 'What backend framework will you use?',
|
|
375
|
+
type: 'exclusive',
|
|
376
|
+
section: 'tech-stack',
|
|
377
|
+
options: [
|
|
378
|
+
'Express (Node.js)',
|
|
379
|
+
'Django (Python)',
|
|
380
|
+
'Spring Boot (Java)',
|
|
381
|
+
],
|
|
382
|
+
},
|
|
383
|
+
];
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Styleguides section - Brownfield
|
|
387
|
+
*/
|
|
388
|
+
function generateStyleguidesQuestionsBrownfield(analysis) {
|
|
389
|
+
const languages = Object.keys(analysis.languages);
|
|
390
|
+
const primaryLanguage = languages[0] || 'JavaScript';
|
|
391
|
+
return [
|
|
392
|
+
{
|
|
393
|
+
id: 'styleguides_choice',
|
|
394
|
+
text: `What code style guide should be used for ${primaryLanguage}?`,
|
|
395
|
+
type: 'exclusive',
|
|
396
|
+
section: 'styleguides',
|
|
397
|
+
options: getStyleguideOptionsForLanguage(primaryLanguage),
|
|
398
|
+
},
|
|
399
|
+
];
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Styleguides section - Greenfield
|
|
403
|
+
*/
|
|
404
|
+
function generateStyleguidesQuestionsGreenfield() {
|
|
405
|
+
return [
|
|
406
|
+
{
|
|
407
|
+
id: 'styleguides_choice',
|
|
408
|
+
text: 'What code style guide should be used?',
|
|
409
|
+
type: 'exclusive',
|
|
410
|
+
section: 'styleguides',
|
|
411
|
+
options: [
|
|
412
|
+
'Airbnb JavaScript Style Guide',
|
|
413
|
+
'Google Style Guides',
|
|
414
|
+
'Standard JS',
|
|
415
|
+
],
|
|
416
|
+
},
|
|
417
|
+
];
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Workflow section - Brownfield & Greenfield (similar)
|
|
421
|
+
*/
|
|
422
|
+
function generateWorkflowQuestionsBrownfield(analysis) {
|
|
423
|
+
return generateWorkflowQuestionsGreenfield();
|
|
424
|
+
}
|
|
425
|
+
function generateWorkflowQuestionsGreenfield() {
|
|
426
|
+
return [
|
|
427
|
+
{
|
|
428
|
+
id: 'workflow_testing',
|
|
429
|
+
text: 'What testing approach will you follow?',
|
|
430
|
+
type: 'exclusive',
|
|
431
|
+
section: 'workflow',
|
|
432
|
+
options: [
|
|
433
|
+
'Test-Driven Development (TDD)',
|
|
434
|
+
'Behavior-Driven Development (BDD)',
|
|
435
|
+
'Write tests after implementation',
|
|
436
|
+
],
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
id: 'workflow_commits',
|
|
440
|
+
text: 'What commit message convention will you use?',
|
|
441
|
+
type: 'exclusive',
|
|
442
|
+
section: 'workflow',
|
|
443
|
+
options: [
|
|
444
|
+
'Conventional Commits (feat:, fix:, etc.)',
|
|
445
|
+
'Semantic versioning triggers',
|
|
446
|
+
'Freeform descriptive messages',
|
|
447
|
+
],
|
|
448
|
+
},
|
|
449
|
+
];
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Helper: Generate contextual features from analysis
|
|
453
|
+
*/
|
|
454
|
+
function generateContextualFeatures(analysis) {
|
|
455
|
+
const features = [];
|
|
456
|
+
if (analysis.frameworks.frontend.length > 0) {
|
|
457
|
+
features.push('User interface and interactions');
|
|
458
|
+
}
|
|
459
|
+
if (analysis.frameworks.backend.length > 0) {
|
|
460
|
+
features.push('API endpoints and business logic');
|
|
461
|
+
}
|
|
462
|
+
if (analysis.databases.length > 0) {
|
|
463
|
+
features.push('Data persistence and retrieval');
|
|
464
|
+
}
|
|
465
|
+
// Fill remaining with generic options
|
|
466
|
+
const generic = [
|
|
467
|
+
'Authentication and authorization',
|
|
468
|
+
'Real-time updates',
|
|
469
|
+
'Third-party integrations',
|
|
470
|
+
];
|
|
471
|
+
for (const g of generic) {
|
|
472
|
+
if (features.length >= 3)
|
|
473
|
+
break;
|
|
474
|
+
if (!features.includes(g))
|
|
475
|
+
features.push(g);
|
|
476
|
+
}
|
|
477
|
+
return features.slice(0, 3);
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Helper: Get styleguide options for language
|
|
481
|
+
*/
|
|
482
|
+
function getStyleguideOptionsForLanguage(language) {
|
|
483
|
+
const guides = {
|
|
484
|
+
'TypeScript': ['Airbnb TypeScript Style Guide', 'Google TypeScript Style Guide', 'Standard TS'],
|
|
485
|
+
'JavaScript': ['Airbnb JavaScript Style Guide', 'Google JavaScript Style Guide', 'Standard JS'],
|
|
486
|
+
'Python': ['PEP 8', 'Google Python Style Guide', 'Black (opinionated)'],
|
|
487
|
+
'Go': ['Effective Go', 'Uber Go Style Guide', 'Go standard formatting'],
|
|
488
|
+
'Rust': ['Rust Style Guide', 'Rustfmt (official)', 'Clippy lints'],
|
|
489
|
+
'Ruby': ['Ruby Style Guide', 'RuboCop defaults', 'GitHub Ruby Style Guide'],
|
|
490
|
+
'Java': ['Google Java Style Guide', 'Oracle Code Conventions', 'Spring conventions'],
|
|
491
|
+
};
|
|
492
|
+
return guides[language] || ['Google Style Guides', 'Language-specific standard', 'Team custom guide'];
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Generate answer options (always 5 options: A-C contextual, D custom, E autogenerate)
|
|
496
|
+
*/
|
|
497
|
+
export function generateAnswerOptions(contextualOptions, section) {
|
|
498
|
+
// Ensure exactly 3 contextual options
|
|
499
|
+
const options = contextualOptions.slice(0, 3);
|
|
500
|
+
while (options.length < 3) {
|
|
501
|
+
options.push(`Option ${options.length + 1}`);
|
|
502
|
+
}
|
|
503
|
+
// Truncate options to max 80 characters
|
|
504
|
+
const truncated = options.map(opt => opt.length > 80 ? opt.substring(0, 77) + '...' : opt);
|
|
505
|
+
// Add standard D and E options
|
|
506
|
+
truncated.push('Type your own answer');
|
|
507
|
+
truncated.push(`Autogenerate and review ${section}.md`);
|
|
508
|
+
return truncated;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Format question for display with lettered options
|
|
512
|
+
*/
|
|
513
|
+
export function formatQuestion(question, questionNumber) {
|
|
514
|
+
const suffix = question.type === 'additive' ? ' (Select all that apply)' : '';
|
|
515
|
+
const lines = [];
|
|
516
|
+
lines.push(`Question ${questionNumber}: ${question.text}${suffix}`);
|
|
517
|
+
lines.push('');
|
|
518
|
+
const letters = ['A', 'B', 'C', 'D', 'E'];
|
|
519
|
+
const options = generateAnswerOptions(question.options, question.section);
|
|
520
|
+
options.forEach((option, index) => {
|
|
521
|
+
lines.push(`${letters[index]}) ${option}`);
|
|
522
|
+
});
|
|
523
|
+
return lines.join('\n');
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Main function: Generate questions for a section
|
|
527
|
+
*/
|
|
528
|
+
export function generateQuestionsForSection(section, projectMaturity, codebaseAnalysis) {
|
|
529
|
+
if (projectMaturity === 'brownfield' && codebaseAnalysis) {
|
|
530
|
+
return generateBrownfieldQuestions(section, codebaseAnalysis);
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
return generateGreenfieldQuestions(section);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|