@iservu-inc/adf-cli 0.1.6 ā 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.project/chats/current/2025-10-03_ADF-CLI-QUALITY-BASED-PROGRESS-AND-RESUME.md +399 -0
- package/.project/docs/architecture/SYSTEM-DESIGN.md +369 -0
- package/.project/docs/frameworks/FRAMEWORK-METHODOLOGIES.md +449 -0
- package/.project/docs/goals/PROJECT-VISION.md +112 -0
- package/.project/docs/tool-integrations/IDE-CUSTOMIZATIONS.md +578 -0
- package/CHANGELOG.md +115 -0
- package/jest.config.js +20 -0
- package/lib/commands/init.js +41 -113
- package/lib/frameworks/answer-quality-analyzer.js +216 -0
- package/lib/frameworks/interviewer.js +447 -0
- package/lib/frameworks/output-generators.js +345 -0
- package/lib/frameworks/progress-tracker.js +239 -0
- package/lib/frameworks/questions.js +664 -0
- package/lib/frameworks/session-manager.js +100 -0
- package/package.json +10 -5
- package/tests/answer-quality-analyzer.test.js +173 -0
- package/tests/progress-tracker.test.js +205 -0
- package/tests/session-manager.test.js +162 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const inquirer = require('inquirer');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { getQuestionsForFramework } = require('./questions');
|
|
6
|
+
const ProgressTracker = require('./progress-tracker');
|
|
7
|
+
const AnswerQualityAnalyzer = require('./answer-quality-analyzer');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Conversational AI Interviewer
|
|
11
|
+
* Guides users through framework-specific questions with intelligent follow-ups
|
|
12
|
+
* Supports real-time progress tracking and resume capability
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
class Interviewer {
|
|
16
|
+
constructor(framework, projectPath, existingSession = null) {
|
|
17
|
+
this.framework = framework;
|
|
18
|
+
this.projectPath = projectPath;
|
|
19
|
+
|
|
20
|
+
if (existingSession) {
|
|
21
|
+
// Resuming existing session
|
|
22
|
+
this.sessionId = existingSession.sessionId;
|
|
23
|
+
this.sessionPath = existingSession.sessionPath;
|
|
24
|
+
this.answers = existingSession.progress.answers || {};
|
|
25
|
+
this.transcript = existingSession.progress.transcript || [];
|
|
26
|
+
this.isResuming = true;
|
|
27
|
+
} else {
|
|
28
|
+
// New session
|
|
29
|
+
this.sessionId = this.generateSessionId();
|
|
30
|
+
this.sessionPath = path.join(projectPath, '.adf', 'sessions', this.sessionId);
|
|
31
|
+
this.answers = {};
|
|
32
|
+
this.transcript = [];
|
|
33
|
+
this.isResuming = false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.progressTracker = null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
generateSessionId() {
|
|
40
|
+
const now = new Date();
|
|
41
|
+
const timestamp = now.toISOString().replace(/:/g, '-').split('.')[0];
|
|
42
|
+
return `${timestamp}_${this.framework}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async start() {
|
|
46
|
+
console.log(chalk.cyan.bold('\nš¤ AI-Guided Requirements Gathering\n'));
|
|
47
|
+
console.log(chalk.gray(`I'll guide you through questions to create a comprehensive ${this.getFrameworkName()} document.\n`));
|
|
48
|
+
console.log(chalk.gray(`Session: ${this.sessionId}`));
|
|
49
|
+
console.log(chalk.gray(`Files will be saved to: .adf/sessions/${this.sessionId}/\n`));
|
|
50
|
+
|
|
51
|
+
// Create session directory
|
|
52
|
+
await fs.ensureDir(this.sessionPath);
|
|
53
|
+
await fs.ensureDir(path.join(this.sessionPath, 'qa-responses'));
|
|
54
|
+
await fs.ensureDir(path.join(this.sessionPath, 'outputs'));
|
|
55
|
+
|
|
56
|
+
// Get questions for framework
|
|
57
|
+
const questions = getQuestionsForFramework(this.framework);
|
|
58
|
+
|
|
59
|
+
// Group questions into blocks by phase
|
|
60
|
+
const questionBlocks = this.groupQuestionsIntoBlocks(questions);
|
|
61
|
+
|
|
62
|
+
// Initialize progress tracker
|
|
63
|
+
this.progressTracker = new ProgressTracker(this.sessionPath, questionBlocks.length, this.framework);
|
|
64
|
+
const isResumable = await this.progressTracker.initialize();
|
|
65
|
+
|
|
66
|
+
if (isResumable && this.isResuming) {
|
|
67
|
+
console.log(chalk.green('\nā Resuming previous session\n'));
|
|
68
|
+
const resumeInfo = this.progressTracker.getResumeInfo();
|
|
69
|
+
console.log(chalk.gray(`Last updated: ${new Date(resumeInfo.lastUpdated).toLocaleString()}`));
|
|
70
|
+
console.log(chalk.gray(`Progress: ${resumeInfo.completedBlocks}/${resumeInfo.totalBlocks} blocks | ${resumeInfo.totalQuestionsAnswered} questions\n`));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log(chalk.cyan(`\nā¹ļø Total question blocks: ${questionBlocks.length}\n`));
|
|
74
|
+
console.log(chalk.gray('ā'.repeat(60)) + '\n');
|
|
75
|
+
|
|
76
|
+
// Interview each block
|
|
77
|
+
for (let i = 0; i < questionBlocks.length; i++) {
|
|
78
|
+
const block = questionBlocks[i];
|
|
79
|
+
|
|
80
|
+
// Show block preview
|
|
81
|
+
const shouldAnswer = await this.showBlockPreview(block, i + 1, questionBlocks.length);
|
|
82
|
+
|
|
83
|
+
if (shouldAnswer === 'skip') {
|
|
84
|
+
console.log(chalk.yellow(`\nāļø Skipped: ${block.title}\n`));
|
|
85
|
+
await this.progressTracker.skipBlock(i + 1, block.title);
|
|
86
|
+
this.transcript.push({
|
|
87
|
+
type: 'block-skipped',
|
|
88
|
+
block: block.title,
|
|
89
|
+
timestamp: new Date().toISOString()
|
|
90
|
+
});
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (shouldAnswer === 'quit') {
|
|
95
|
+
console.log(chalk.yellow('\nš Interview ended early. Partial progress saved.\n'));
|
|
96
|
+
await this.progressTracker.saveCheckpoint('User ended interview early');
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Track block start
|
|
101
|
+
await this.progressTracker.startBlock(i + 1, block.title);
|
|
102
|
+
|
|
103
|
+
// Ask questions in this block
|
|
104
|
+
const questionsAnswered = await this.askBlockQuestions(block, i + 1, questionBlocks.length);
|
|
105
|
+
|
|
106
|
+
// Track block complete
|
|
107
|
+
await this.progressTracker.completeBlock(i + 1, block.title, questionsAnswered);
|
|
108
|
+
|
|
109
|
+
// Save block answers
|
|
110
|
+
await this.saveBlockAnswers(block);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Generate framework outputs
|
|
114
|
+
await this.generateOutputs();
|
|
115
|
+
|
|
116
|
+
// Save transcript
|
|
117
|
+
await this.saveTranscript();
|
|
118
|
+
|
|
119
|
+
// Save session metadata
|
|
120
|
+
await this.saveMetadata();
|
|
121
|
+
|
|
122
|
+
// Mark session as complete
|
|
123
|
+
await this.progressTracker.complete();
|
|
124
|
+
|
|
125
|
+
console.log(chalk.green.bold('\n⨠Requirements gathering complete!\n'));
|
|
126
|
+
console.log(chalk.cyan(`š Session saved to: .adf/sessions/${this.sessionId}/\n`));
|
|
127
|
+
|
|
128
|
+
return this.sessionPath;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
getFrameworkName() {
|
|
132
|
+
const names = {
|
|
133
|
+
rapid: 'Product Requirement Prompt (PRP)',
|
|
134
|
+
balanced: 'Specification + Implementation Plan',
|
|
135
|
+
comprehensive: 'BMAD Framework Document'
|
|
136
|
+
};
|
|
137
|
+
return names[this.framework] || 'Requirements Document';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
groupQuestionsIntoBlocks(questions) {
|
|
141
|
+
const blocks = {};
|
|
142
|
+
|
|
143
|
+
questions.forEach(q => {
|
|
144
|
+
if (!blocks[q.phase]) {
|
|
145
|
+
blocks[q.phase] = {
|
|
146
|
+
phase: q.phase,
|
|
147
|
+
title: this.formatPhaseTitle(q.phase),
|
|
148
|
+
questions: []
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
blocks[q.phase].questions.push(q);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Sort questions within each block by importance (priority questions first)
|
|
155
|
+
Object.values(blocks).forEach(block => {
|
|
156
|
+
block.questions.sort((a, b) => {
|
|
157
|
+
// Priority order: questions with followUpTriggers come first (more critical)
|
|
158
|
+
const aPriority = a.followUpTriggers ? 0 : 1;
|
|
159
|
+
const bPriority = b.followUpTriggers ? 0 : 1;
|
|
160
|
+
return aPriority - bPriority;
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return Object.values(blocks);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
formatPhaseTitle(phase) {
|
|
168
|
+
return phase
|
|
169
|
+
.split('-')
|
|
170
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
171
|
+
.join(' ');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async showBlockPreview(block, current, total) {
|
|
175
|
+
console.log(chalk.cyan.bold(`š Block ${current} of ${total}: ${block.title}\n`));
|
|
176
|
+
|
|
177
|
+
// Show what this block covers
|
|
178
|
+
console.log(chalk.gray('This block covers:'));
|
|
179
|
+
const topQuestions = block.questions.slice(0, 3);
|
|
180
|
+
topQuestions.forEach(q => {
|
|
181
|
+
console.log(chalk.gray(` ⢠${q.text}`));
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
if (block.questions.length > 3) {
|
|
185
|
+
console.log(chalk.gray(` ⢠...and ${block.questions.length - 3} more questions\n`));
|
|
186
|
+
} else {
|
|
187
|
+
console.log('');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Show example
|
|
191
|
+
if (topQuestions[0]) {
|
|
192
|
+
console.log(chalk.gray('š” Example good answer:'));
|
|
193
|
+
console.log(chalk.green(` "${topQuestions[0].goodExample}"\n`));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Ask if they want to answer this block
|
|
197
|
+
const { action } = await inquirer.prompt([
|
|
198
|
+
{
|
|
199
|
+
type: 'list',
|
|
200
|
+
name: 'action',
|
|
201
|
+
message: 'How would you like to proceed?',
|
|
202
|
+
choices: [
|
|
203
|
+
{ name: 'Answer this block', value: 'answer' },
|
|
204
|
+
{ name: 'Skip this block', value: 'skip' },
|
|
205
|
+
{ name: 'Skip remaining blocks and finish', value: 'quit' }
|
|
206
|
+
],
|
|
207
|
+
default: 'answer'
|
|
208
|
+
}
|
|
209
|
+
]);
|
|
210
|
+
|
|
211
|
+
console.log(chalk.gray('\n' + 'ā'.repeat(60)) + '\n');
|
|
212
|
+
|
|
213
|
+
return action;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async askBlockQuestions(block, currentBlock, totalBlocks) {
|
|
217
|
+
const blockAnswers = {};
|
|
218
|
+
let questionsAnswered = 0;
|
|
219
|
+
|
|
220
|
+
for (let i = 0; i < block.questions.length; i++) {
|
|
221
|
+
const question = block.questions[i];
|
|
222
|
+
const answer = await this.askQuestion(question, i + 1, block.questions.length, currentBlock, totalBlocks);
|
|
223
|
+
|
|
224
|
+
if (answer === null) {
|
|
225
|
+
// User skipped remaining questions in block
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
blockAnswers[question.id] = answer;
|
|
230
|
+
this.answers[question.id] = answer;
|
|
231
|
+
questionsAnswered++;
|
|
232
|
+
|
|
233
|
+
// Log to transcript
|
|
234
|
+
this.transcript.push({
|
|
235
|
+
type: 'question-answer',
|
|
236
|
+
question: question.text,
|
|
237
|
+
answer: answer,
|
|
238
|
+
questionId: question.id,
|
|
239
|
+
timestamp: new Date().toISOString()
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return questionsAnswered;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async askQuestion(question, current, totalInBlock, currentBlock, totalBlocks) {
|
|
247
|
+
console.log(chalk.cyan(`Question ${current}/${totalInBlock}`) + chalk.gray(` (Block ${currentBlock}/${totalBlocks})`) + '\n');
|
|
248
|
+
console.log(chalk.white.bold(question.text) + '\n');
|
|
249
|
+
|
|
250
|
+
// Show guidance
|
|
251
|
+
console.log(chalk.gray(`š” ${question.guidance}`));
|
|
252
|
+
console.log(chalk.green(` ā Good: ${question.goodExample}`));
|
|
253
|
+
console.log(chalk.red(` ā Bad: ${question.badExample}\n`));
|
|
254
|
+
|
|
255
|
+
// Get answer
|
|
256
|
+
const { answer } = await inquirer.prompt([
|
|
257
|
+
{
|
|
258
|
+
type: 'input',
|
|
259
|
+
name: 'answer',
|
|
260
|
+
message: 'Your answer:',
|
|
261
|
+
validate: (input) => {
|
|
262
|
+
if (!input || input.trim().length === 0) {
|
|
263
|
+
return 'Please provide an answer or type "skip" to skip remaining questions in this block';
|
|
264
|
+
}
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
]);
|
|
269
|
+
|
|
270
|
+
if (answer.toLowerCase() === 'skip') {
|
|
271
|
+
return null; // Signal to skip remaining questions
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Analyze answer quality
|
|
275
|
+
const qualityMetrics = AnswerQualityAnalyzer.analyze(answer, question);
|
|
276
|
+
|
|
277
|
+
// Show quality feedback
|
|
278
|
+
const feedback = AnswerQualityAnalyzer.getFeedback(qualityMetrics);
|
|
279
|
+
if (feedback) {
|
|
280
|
+
console.log(chalk.cyan(`${feedback}`));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Track answer with quality metrics
|
|
284
|
+
await this.progressTracker.answerQuestion(question.id, question.text, answer, qualityMetrics);
|
|
285
|
+
|
|
286
|
+
// Check if answer is comprehensive enough to skip follow-ups
|
|
287
|
+
if (qualityMetrics.canSkipFollowUps) {
|
|
288
|
+
console.log(chalk.green('\nā Saved\n'));
|
|
289
|
+
return answer;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Check if answer needs follow-up
|
|
293
|
+
const followUp = this.determineFollowUp(question, answer);
|
|
294
|
+
|
|
295
|
+
if (followUp) {
|
|
296
|
+
console.log(chalk.yellow(`\nš¤ ${followUp.message}\n`));
|
|
297
|
+
|
|
298
|
+
const { followUpAnswer } = await inquirer.prompt([
|
|
299
|
+
{
|
|
300
|
+
type: 'input',
|
|
301
|
+
name: 'followUpAnswer',
|
|
302
|
+
message: followUp.question
|
|
303
|
+
}
|
|
304
|
+
]);
|
|
305
|
+
|
|
306
|
+
if (followUpAnswer && followUpAnswer.trim()) {
|
|
307
|
+
// Combine answers
|
|
308
|
+
const combined = `${answer} | Follow-up: ${followUpAnswer}`;
|
|
309
|
+
|
|
310
|
+
// Re-analyze combined answer
|
|
311
|
+
const combinedMetrics = AnswerQualityAnalyzer.analyze(combined, question);
|
|
312
|
+
await this.progressTracker.answerQuestion(question.id, question.text, combined, combinedMetrics);
|
|
313
|
+
|
|
314
|
+
console.log(chalk.green('\nā Saved\n'));
|
|
315
|
+
return combined;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
console.log(chalk.green('\nā Saved\n'));
|
|
320
|
+
return answer;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
determineFollowUp(question, answer) {
|
|
324
|
+
if (!question.followUpTriggers) return null;
|
|
325
|
+
|
|
326
|
+
const triggers = question.followUpTriggers;
|
|
327
|
+
const lowerAnswer = answer.toLowerCase();
|
|
328
|
+
|
|
329
|
+
// Check for vague answers
|
|
330
|
+
if (triggers.vague) {
|
|
331
|
+
const hasVagueWord = triggers.vague.some(word => lowerAnswer.includes(word));
|
|
332
|
+
if (hasVagueWord && answer.split(' ').length < 5) {
|
|
333
|
+
return {
|
|
334
|
+
message: "That's a bit vague. Let me ask a more specific question:",
|
|
335
|
+
question: "Can you provide more specific details? (e.g., what technology, what platform, what specific functionality)"
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Check for missing technology
|
|
341
|
+
if (triggers.missingTech && typeof triggers.missingTech === 'function') {
|
|
342
|
+
if (triggers.missingTech(answer)) {
|
|
343
|
+
return {
|
|
344
|
+
message: "I notice you didn't mention the technology stack.",
|
|
345
|
+
question: "What framework, language, or technology will you use for this?"
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Check for missing platform
|
|
351
|
+
if (triggers.missingPlatform && typeof triggers.missingPlatform === 'function') {
|
|
352
|
+
if (triggers.missingPlatform(answer)) {
|
|
353
|
+
return {
|
|
354
|
+
message: "I'm not clear on the platform.",
|
|
355
|
+
question: "Is this for web, mobile, desktop, API, or something else?"
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async saveBlockAnswers(block) {
|
|
364
|
+
const fileName = `${block.phase}.md`;
|
|
365
|
+
const filePath = path.join(this.sessionPath, 'qa-responses', fileName);
|
|
366
|
+
|
|
367
|
+
let content = `# ${block.title}\n\n`;
|
|
368
|
+
content += `**Block:** ${block.phase}\n`;
|
|
369
|
+
content += `**Questions answered:** ${block.questions.filter(q => this.answers[q.id]).length}/${block.questions.length}\n`;
|
|
370
|
+
content += `**Timestamp:** ${new Date().toISOString()}\n\n`;
|
|
371
|
+
content += `---\n\n`;
|
|
372
|
+
|
|
373
|
+
block.questions.forEach(q => {
|
|
374
|
+
if (this.answers[q.id]) {
|
|
375
|
+
content += `## ${q.text}\n\n`;
|
|
376
|
+
content += `**Answer:** ${this.answers[q.id]}\n\n`;
|
|
377
|
+
content += `---\n\n`;
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
await fs.writeFile(filePath, content, 'utf-8');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
async saveTranscript() {
|
|
385
|
+
const filePath = path.join(this.sessionPath, '_transcript.md');
|
|
386
|
+
|
|
387
|
+
let content = `# Interview Transcript\n\n`;
|
|
388
|
+
content += `**Session:** ${this.sessionId}\n`;
|
|
389
|
+
content += `**Framework:** ${this.getFrameworkName()}\n`;
|
|
390
|
+
content += `**Total Answers:** ${Object.keys(this.answers).length}\n`;
|
|
391
|
+
content += `**Date:** ${new Date().toISOString()}\n\n`;
|
|
392
|
+
content += `---\n\n`;
|
|
393
|
+
|
|
394
|
+
this.transcript.forEach((entry, i) => {
|
|
395
|
+
if (entry.type === 'question-answer') {
|
|
396
|
+
content += `## Q${i + 1}: ${entry.question}\n\n`;
|
|
397
|
+
content += `**Answer:** ${entry.answer}\n\n`;
|
|
398
|
+
content += `**Timestamp:** ${entry.timestamp}\n\n`;
|
|
399
|
+
content += `---\n\n`;
|
|
400
|
+
} else if (entry.type === 'block-skipped') {
|
|
401
|
+
content += `## [SKIPPED] ${entry.block}\n\n`;
|
|
402
|
+
content += `**Timestamp:** ${entry.timestamp}\n\n`;
|
|
403
|
+
content += `---\n\n`;
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
await fs.writeFile(filePath, content, 'utf-8');
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
async saveMetadata() {
|
|
411
|
+
const metadata = {
|
|
412
|
+
sessionId: this.sessionId,
|
|
413
|
+
framework: this.framework,
|
|
414
|
+
frameworkName: this.getFrameworkName(),
|
|
415
|
+
startedAt: this.transcript[0]?.timestamp || new Date().toISOString(),
|
|
416
|
+
completedAt: new Date().toISOString(),
|
|
417
|
+
totalQuestions: Object.keys(this.answers).length,
|
|
418
|
+
answers: this.answers,
|
|
419
|
+
projectPath: this.projectPath
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
const filePath = path.join(this.sessionPath, '_metadata.json');
|
|
423
|
+
await fs.writeJson(filePath, metadata, { spaces: 2 });
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
async generateOutputs() {
|
|
427
|
+
const outputsPath = path.join(this.sessionPath, 'outputs');
|
|
428
|
+
|
|
429
|
+
// Import output generators
|
|
430
|
+
const generators = require('./output-generators');
|
|
431
|
+
|
|
432
|
+
console.log(chalk.cyan('\nš Generating framework documents...\n'));
|
|
433
|
+
|
|
434
|
+
if (this.framework === 'rapid') {
|
|
435
|
+
await generators.generatePRP(this.answers, outputsPath);
|
|
436
|
+
console.log(chalk.green('ā Generated: prp.md\n'));
|
|
437
|
+
} else if (this.framework === 'balanced') {
|
|
438
|
+
await generators.generateBalanced(this.answers, outputsPath);
|
|
439
|
+
console.log(chalk.green('ā Generated: constitution.md, specification.md, plan.md, tasks.md\n'));
|
|
440
|
+
} else if (this.framework === 'comprehensive') {
|
|
441
|
+
await generators.generateBMAD(this.answers, outputsPath);
|
|
442
|
+
console.log(chalk.green('ā Generated: prd.md, architecture.md, stories.md\n'));
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
module.exports = Interviewer;
|