@iservu-inc/adf-cli 0.8.0 → 0.9.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.
@@ -0,0 +1,418 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const inquirer = require('inquirer');
5
+
6
+ /**
7
+ * AI Analysis Configuration Manager
8
+ * Controls performance vs intelligence tradeoffs during interviews
9
+ */
10
+
11
+ const DEFAULT_CONFIG = {
12
+ enabled: true,
13
+ performanceMode: 'balanced', // 'fast', 'balanced', 'comprehensive'
14
+ features: {
15
+ qualityAnalysis: true, // AI-powered answer quality analysis
16
+ intelligentReordering: true, // Dynamic question reordering based on answers
17
+ followUpQuestions: true, // AI-generated follow-up questions
18
+ patternDetection: true, // Learn from answer patterns
19
+ smartFiltering: true // Skip redundant questions intelligently
20
+ }
21
+ };
22
+
23
+ const PERFORMANCE_MODES = {
24
+ fast: {
25
+ name: 'Fast Mode',
26
+ description: 'Minimal AI analysis - faster but less intelligent',
27
+ features: {
28
+ qualityAnalysis: false,
29
+ intelligentReordering: false,
30
+ followUpQuestions: false,
31
+ patternDetection: false,
32
+ smartFiltering: false
33
+ }
34
+ },
35
+ balanced: {
36
+ name: 'Balanced Mode',
37
+ description: 'Moderate AI analysis - good balance of speed and intelligence',
38
+ features: {
39
+ qualityAnalysis: true,
40
+ intelligentReordering: false,
41
+ followUpQuestions: true,
42
+ patternDetection: true,
43
+ smartFiltering: true
44
+ }
45
+ },
46
+ comprehensive: {
47
+ name: 'Comprehensive Mode',
48
+ description: 'Full AI analysis - slower but most intelligent',
49
+ features: {
50
+ qualityAnalysis: true,
51
+ intelligentReordering: true,
52
+ followUpQuestions: true,
53
+ patternDetection: true,
54
+ smartFiltering: true
55
+ }
56
+ }
57
+ };
58
+
59
+ /**
60
+ * Get config file path
61
+ */
62
+ function getAnalysisConfigPath(projectPath = process.cwd()) {
63
+ return path.join(projectPath, '.adf', 'analysis-config.json');
64
+ }
65
+
66
+ /**
67
+ * Load analysis configuration
68
+ */
69
+ async function loadAnalysisConfig(projectPath = process.cwd()) {
70
+ const configPath = getAnalysisConfigPath(projectPath);
71
+
72
+ if (!await fs.pathExists(configPath)) {
73
+ return DEFAULT_CONFIG;
74
+ }
75
+
76
+ try {
77
+ const config = await fs.readJson(configPath);
78
+ // Merge with defaults to ensure all keys exist
79
+ return {
80
+ ...DEFAULT_CONFIG,
81
+ ...config,
82
+ features: {
83
+ ...DEFAULT_CONFIG.features,
84
+ ...(config.features || {})
85
+ }
86
+ };
87
+ } catch (error) {
88
+ console.log(chalk.yellow(`⚠️ Failed to load analysis config: ${error.message}`));
89
+ return DEFAULT_CONFIG;
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Save analysis configuration
95
+ */
96
+ async function saveAnalysisConfig(config, projectPath = process.cwd()) {
97
+ const configPath = getAnalysisConfigPath(projectPath);
98
+
99
+ try {
100
+ await fs.ensureDir(path.dirname(configPath));
101
+ await fs.writeJson(configPath, config, { spaces: 2 });
102
+ return true;
103
+ } catch (error) {
104
+ console.log(chalk.red(`❌ Failed to save analysis config: ${error.message}`));
105
+ return false;
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Get feature status summary
111
+ */
112
+ function getFeatureStatusSummary(config) {
113
+ const features = config.features;
114
+ const enabledCount = Object.values(features).filter(v => v).length;
115
+ const totalCount = Object.keys(features).length;
116
+
117
+ if (enabledCount === totalCount) {
118
+ return chalk.green(`All features enabled (${totalCount}/${totalCount})`);
119
+ } else if (enabledCount === 0) {
120
+ return chalk.red(`All features disabled (0/${totalCount})`);
121
+ } else {
122
+ return chalk.yellow(`${enabledCount}/${totalCount} features enabled`);
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Interactive configuration menu
128
+ */
129
+ async function configureAnalysisSettings(projectPath = process.cwd()) {
130
+ console.log(chalk.cyan.bold('\n🧠 AI Analysis Settings\n'));
131
+ console.log(chalk.gray('Control the balance between performance and intelligence during interviews\n'));
132
+
133
+ // Load current config
134
+ const currentConfig = await loadAnalysisConfig(projectPath);
135
+
136
+ // Main menu
137
+ while (true) {
138
+ console.log(chalk.gray('─'.repeat(60)));
139
+ console.log(chalk.cyan('\n📊 Current Configuration:\n'));
140
+ console.log(chalk.gray('Performance Mode: ') + chalk.white.bold(PERFORMANCE_MODES[currentConfig.performanceMode].name));
141
+ console.log(chalk.gray('Status: ') + getFeatureStatusSummary(currentConfig));
142
+ console.log('');
143
+
144
+ const { action } = await inquirer.prompt([
145
+ {
146
+ type: 'list',
147
+ name: 'action',
148
+ message: 'What would you like to do?',
149
+ choices: [
150
+ {
151
+ name: '🚀 Change Performance Mode (Fast/Balanced/Comprehensive)',
152
+ value: 'mode',
153
+ short: 'Change Mode'
154
+ },
155
+ {
156
+ name: '🎛️ Configure Individual Features',
157
+ value: 'features',
158
+ short: 'Configure Features'
159
+ },
160
+ {
161
+ name: '📖 View Feature Descriptions',
162
+ value: 'info',
163
+ short: 'View Info'
164
+ },
165
+ {
166
+ name: '♻️ Reset to Defaults',
167
+ value: 'reset',
168
+ short: 'Reset'
169
+ },
170
+ new inquirer.Separator(),
171
+ {
172
+ name: chalk.green('✓ Save and Exit'),
173
+ value: 'save',
174
+ short: 'Save'
175
+ },
176
+ {
177
+ name: chalk.gray('← Cancel'),
178
+ value: 'cancel',
179
+ short: 'Cancel'
180
+ }
181
+ ],
182
+ pageSize: 12
183
+ }
184
+ ]);
185
+
186
+ if (action === 'save') {
187
+ const saved = await saveAnalysisConfig(currentConfig, projectPath);
188
+ if (saved) {
189
+ console.log(chalk.green.bold('\n✅ AI Analysis settings saved!\n'));
190
+ console.log(chalk.gray(`Config saved to: ${getAnalysisConfigPath(projectPath)}\n`));
191
+ }
192
+ break;
193
+ } else if (action === 'cancel') {
194
+ console.log(chalk.yellow('\n✋ Changes discarded.\n'));
195
+ break;
196
+ } else if (action === 'mode') {
197
+ await changePerformanceMode(currentConfig);
198
+ } else if (action === 'features') {
199
+ await configureIndividualFeatures(currentConfig);
200
+ } else if (action === 'info') {
201
+ await showFeatureInfo();
202
+ } else if (action === 'reset') {
203
+ const { confirm } = await inquirer.prompt([
204
+ {
205
+ type: 'confirm',
206
+ name: 'confirm',
207
+ message: 'Reset all settings to defaults?',
208
+ default: false
209
+ }
210
+ ]);
211
+
212
+ if (confirm) {
213
+ currentConfig.performanceMode = DEFAULT_CONFIG.performanceMode;
214
+ currentConfig.features = { ...DEFAULT_CONFIG.features };
215
+ console.log(chalk.green('\n✓ Reset to defaults\n'));
216
+ }
217
+ }
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Change performance mode
223
+ */
224
+ async function changePerformanceMode(currentConfig) {
225
+ console.log(chalk.gray('\n' + '─'.repeat(60) + '\n'));
226
+
227
+ const { mode } = await inquirer.prompt([
228
+ {
229
+ type: 'list',
230
+ name: 'mode',
231
+ message: 'Select performance mode:',
232
+ choices: [
233
+ {
234
+ name: `${chalk.cyan('⚡ Fast Mode')} - ${PERFORMANCE_MODES.fast.description}`,
235
+ value: 'fast',
236
+ short: 'Fast'
237
+ },
238
+ {
239
+ name: `${chalk.yellow('⚖️ Balanced Mode')} - ${PERFORMANCE_MODES.balanced.description}`,
240
+ value: 'balanced',
241
+ short: 'Balanced'
242
+ },
243
+ {
244
+ name: `${chalk.green('🎯 Comprehensive Mode')} - ${PERFORMANCE_MODES.comprehensive.description}`,
245
+ value: 'comprehensive',
246
+ short: 'Comprehensive'
247
+ },
248
+ new inquirer.Separator(),
249
+ {
250
+ name: chalk.gray('← Back'),
251
+ value: 'back'
252
+ }
253
+ ]
254
+ }
255
+ ]);
256
+
257
+ if (mode !== 'back') {
258
+ currentConfig.performanceMode = mode;
259
+ currentConfig.features = { ...PERFORMANCE_MODES[mode].features };
260
+ console.log(chalk.green(`\n✓ Mode changed to: ${PERFORMANCE_MODES[mode].name}\n`));
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Configure individual features
266
+ */
267
+ async function configureIndividualFeatures(currentConfig) {
268
+ console.log(chalk.gray('\n' + '─'.repeat(60) + '\n'));
269
+ console.log(chalk.yellow('⚠️ Changing individual features will set mode to "Custom"\n'));
270
+
271
+ const { features } = await inquirer.prompt([
272
+ {
273
+ type: 'checkbox',
274
+ name: 'features',
275
+ message: 'Select features to enable (space to toggle, enter to confirm):',
276
+ choices: [
277
+ {
278
+ name: 'AI-Powered Quality Analysis',
279
+ value: 'qualityAnalysis',
280
+ checked: currentConfig.features.qualityAnalysis
281
+ },
282
+ {
283
+ name: 'Intelligent Question Reordering',
284
+ value: 'intelligentReordering',
285
+ checked: currentConfig.features.intelligentReordering
286
+ },
287
+ {
288
+ name: 'AI-Generated Follow-Up Questions',
289
+ value: 'followUpQuestions',
290
+ checked: currentConfig.features.followUpQuestions
291
+ },
292
+ {
293
+ name: 'Pattern Detection & Learning',
294
+ value: 'patternDetection',
295
+ checked: currentConfig.features.patternDetection
296
+ },
297
+ {
298
+ name: 'Smart Question Filtering',
299
+ value: 'smartFiltering',
300
+ checked: currentConfig.features.smartFiltering
301
+ }
302
+ ]
303
+ }
304
+ ]);
305
+
306
+ // Update features based on selection
307
+ currentConfig.features.qualityAnalysis = features.includes('qualityAnalysis');
308
+ currentConfig.features.intelligentReordering = features.includes('intelligentReordering');
309
+ currentConfig.features.followUpQuestions = features.includes('followUpQuestions');
310
+ currentConfig.features.patternDetection = features.includes('patternDetection');
311
+ currentConfig.features.smartFiltering = features.includes('smartFiltering');
312
+
313
+ // Check if matches any preset mode
314
+ let matchedMode = null;
315
+ for (const [mode, config] of Object.entries(PERFORMANCE_MODES)) {
316
+ if (JSON.stringify(config.features) === JSON.stringify(currentConfig.features)) {
317
+ matchedMode = mode;
318
+ break;
319
+ }
320
+ }
321
+
322
+ if (matchedMode) {
323
+ currentConfig.performanceMode = matchedMode;
324
+ console.log(chalk.green(`\n✓ Features updated (matches ${PERFORMANCE_MODES[matchedMode].name})\n`));
325
+ } else {
326
+ currentConfig.performanceMode = 'custom';
327
+ console.log(chalk.green('\n✓ Features updated (Custom mode)\n'));
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Show feature information
333
+ */
334
+ async function showFeatureInfo() {
335
+ console.log(chalk.gray('\n' + '─'.repeat(60)));
336
+ console.log(chalk.cyan.bold('\n📚 Feature Descriptions\n'));
337
+
338
+ const features = [
339
+ {
340
+ name: chalk.white.bold('AI-Powered Quality Analysis'),
341
+ description: 'Uses AI to analyze your answer quality in real-time',
342
+ impact: 'Provides feedback on answer completeness and suggests improvements',
343
+ performance: chalk.yellow('Medium impact') + ' - adds 1-2 seconds per answer'
344
+ },
345
+ {
346
+ name: chalk.white.bold('Intelligent Question Reordering'),
347
+ description: 'Dynamically reorders upcoming questions based on your answers',
348
+ impact: 'Asks more relevant questions based on what you\'ve already said',
349
+ performance: chalk.red('High impact') + ' - adds 2-3 seconds per answer'
350
+ },
351
+ {
352
+ name: chalk.white.bold('AI-Generated Follow-Up Questions'),
353
+ description: 'Generates contextual follow-up questions when answers need clarification',
354
+ impact: 'Gets more detailed information through targeted follow-ups',
355
+ performance: chalk.yellow('Medium impact') + ' - adds 1-2 seconds when triggered'
356
+ },
357
+ {
358
+ name: chalk.white.bold('Pattern Detection & Learning'),
359
+ description: 'Learns from your answer patterns to improve future interviews',
360
+ impact: 'Remembers your preferences and skips questions you typically skip',
361
+ performance: chalk.green('Low impact') + ' - minimal performance cost'
362
+ },
363
+ {
364
+ name: chalk.white.bold('Smart Question Filtering'),
365
+ description: 'Automatically skips questions already answered elsewhere',
366
+ impact: 'Reduces redundancy by not asking questions you\'ve already covered',
367
+ performance: chalk.green('Low impact') + ' - minimal performance cost'
368
+ }
369
+ ];
370
+
371
+ features.forEach((feature, i) => {
372
+ console.log(chalk.cyan(`${i + 1}. ${feature.name}`));
373
+ console.log(chalk.gray(` ${feature.description}`));
374
+ console.log(chalk.gray(` Impact: ${feature.impact}`));
375
+ console.log(chalk.gray(` Performance: ${feature.performance}`));
376
+ console.log('');
377
+ });
378
+
379
+ console.log(chalk.gray('─'.repeat(60)));
380
+
381
+ await inquirer.prompt([
382
+ {
383
+ type: 'input',
384
+ name: 'continue',
385
+ message: 'Press Enter to continue...',
386
+ default: ''
387
+ }
388
+ ]);
389
+
390
+ console.log('');
391
+ }
392
+
393
+ /**
394
+ * Get feature status for display in config menu
395
+ */
396
+ async function getAnalysisStatus(projectPath = process.cwd()) {
397
+ const config = await loadAnalysisConfig(projectPath);
398
+ const mode = PERFORMANCE_MODES[config.performanceMode];
399
+ const enabledCount = Object.values(config.features).filter(v => v).length;
400
+
401
+ return {
402
+ configured: true,
403
+ mode: config.performanceMode,
404
+ modeName: mode ? mode.name : 'Custom',
405
+ enabledCount: enabledCount,
406
+ totalCount: Object.keys(config.features).length
407
+ };
408
+ }
409
+
410
+ module.exports = {
411
+ loadAnalysisConfig,
412
+ saveAnalysisConfig,
413
+ configureAnalysisSettings,
414
+ getAnalysisStatus,
415
+ getAnalysisConfigPath,
416
+ DEFAULT_CONFIG,
417
+ PERFORMANCE_MODES
418
+ };
@@ -3,6 +3,7 @@ const chalk = require('chalk');
3
3
  const fs = require('fs-extra');
4
4
  const path = require('path');
5
5
  const { configureAIProvider, getEnvFilePath, loadEnvFile } = require('../ai/ai-config');
6
+ const { configureAnalysisSettings, getAnalysisStatus } = require('../ai/analysis-config');
6
7
  const LearningManager = require('../learning/learning-manager');
7
8
  const { getLearningStats, getLearningConfig } = require('../learning/storage');
8
9
 
@@ -15,6 +16,11 @@ const CONFIG_CATEGORIES = {
15
16
  description: 'Configure AI provider (Anthropic, OpenAI, Google Gemini, OpenRouter)',
16
17
  value: 'ai-provider'
17
18
  },
19
+ AI_ANALYSIS: {
20
+ name: 'AI Analysis Settings',
21
+ description: 'Control AI analysis features and performance modes',
22
+ value: 'ai-analysis'
23
+ },
18
24
  IDE_DEPLOYMENT: {
19
25
  name: 'IDE Deployment',
20
26
  description: 'Deploy requirements to IDEs (Windsurf, Cursor, VSCode, etc.)',
@@ -110,6 +116,17 @@ function displayLearningStatus(status) {
110
116
  }
111
117
  }
112
118
 
119
+ /**
120
+ * Display configuration status for AI Analysis
121
+ */
122
+ function displayAnalysisStatus(status) {
123
+ if (status.configured) {
124
+ return `${chalk.green('✓ Configured')} ${chalk.gray(`(${status.modeName}, ${status.enabledCount}/${status.totalCount} features)`)}`;
125
+ } else {
126
+ return chalk.gray('○ Default settings');
127
+ }
128
+ }
129
+
113
130
  /**
114
131
  * Main config command
115
132
  */
@@ -120,6 +137,7 @@ async function config() {
120
137
 
121
138
  // Check configuration status for all categories
122
139
  const aiStatus = await isAIConfigured(cwd);
140
+ const analysisStatus = await getAnalysisStatus(cwd);
123
141
  const deploymentStatus = await getDeploymentStatus(cwd);
124
142
  const learningStatus = await getLearningStatus(cwd);
125
143
 
@@ -130,6 +148,11 @@ async function config() {
130
148
  value: CONFIG_CATEGORIES.AI_PROVIDER.value,
131
149
  short: CONFIG_CATEGORIES.AI_PROVIDER.name
132
150
  },
151
+ {
152
+ name: `${CONFIG_CATEGORIES.AI_ANALYSIS.name} - ${displayAnalysisStatus(analysisStatus)}`,
153
+ value: CONFIG_CATEGORIES.AI_ANALYSIS.value,
154
+ short: CONFIG_CATEGORIES.AI_ANALYSIS.name
155
+ },
133
156
  {
134
157
  name: `${CONFIG_CATEGORIES.IDE_DEPLOYMENT.name} - ${displayDeploymentStatus(deploymentStatus)}`,
135
158
  value: CONFIG_CATEGORIES.IDE_DEPLOYMENT.value,
@@ -168,6 +191,10 @@ async function config() {
168
191
  await configureAIProviderCategory(cwd, aiStatus);
169
192
  break;
170
193
 
194
+ case 'ai-analysis':
195
+ await configureAnalysisSettings(cwd);
196
+ break;
197
+
171
198
  case 'ide-deployment':
172
199
  await configureIDEDeploymentCategory(cwd, deploymentStatus);
173
200
  break;
@@ -63,6 +63,16 @@ class Interviewer {
63
63
  console.log(chalk.gray(`Session: ${this.sessionId}`));
64
64
  console.log(chalk.gray(`Files will be saved to: .adf/sessions/${this.sessionId}/\n`));
65
65
 
66
+ // Load AI Analysis configuration
67
+ const { loadAnalysisConfig } = require('../ai/analysis-config');
68
+ this.analysisConfig = await loadAnalysisConfig(this.projectPath);
69
+
70
+ // Show performance mode
71
+ const modeEmoji = this.analysisConfig.performanceMode === 'fast' ? '⚡' :
72
+ this.analysisConfig.performanceMode === 'comprehensive' ? '🎯' : '⚖️';
73
+ console.log(chalk.gray(`${modeEmoji} Analysis Mode: ${this.analysisConfig.performanceMode}`));
74
+ console.log(chalk.gray(` (Configure with: adf config)\n`));
75
+
66
76
  // Setup global Ctrl+C handler for graceful exit from anywhere
67
77
  const exitHandler = async () => {
68
78
  console.log(chalk.yellow('\n\n💾 Saving progress and exiting...'));
@@ -135,82 +145,101 @@ class Interviewer {
135
145
  }
136
146
  }
137
147
 
138
- // Initialize AI Client
139
- if (!this.aiClient && this.aiConfig) {
148
+ // Initialize AI Client (only if quality analysis or follow-ups are enabled)
149
+ const needsAI = this.analysisConfig.features.qualityAnalysis ||
150
+ this.analysisConfig.features.followUpQuestions ||
151
+ this.analysisConfig.features.intelligentReordering;
152
+
153
+ if (!this.aiClient && this.aiConfig && needsAI) {
140
154
  const AIClient = require('../ai/ai-client');
141
155
  this.aiClient = new AIClient(this.aiConfig);
142
156
  console.log(chalk.green(`\n✓ AI Provider: ${this.aiConfig.providerName} (${this.aiConfig.model})\n`));
143
- } else if (!this.aiConfig) {
144
- console.log(chalk.yellow('⚠️ No AI configuration - continuing without AI assistance\n'));
145
- // Allow interview to continue without AI (graceful degradation)
157
+ } else if (!this.aiConfig && needsAI) {
158
+ console.log(chalk.yellow('⚠️ No AI configuration - AI features disabled\n'));
159
+ // Disable AI-dependent features
160
+ this.analysisConfig.features.qualityAnalysis = false;
161
+ this.analysisConfig.features.followUpQuestions = false;
162
+ this.analysisConfig.features.intelligentReordering = false;
163
+ } else if (!needsAI) {
164
+ console.log(chalk.gray('ℹ️ AI features disabled by configuration\n'));
146
165
  }
147
166
 
148
167
  // Initialize Dynamic Pipeline (Intelligent Question System)
149
- this.dynamicPipeline = new DynamicPipeline(this.sessionPath, this.aiClient, {
150
- enabled: true,
151
- minSkipConfidence: 75,
152
- showAnalysis: true,
153
- verbose: false
154
- });
155
- await this.dynamicPipeline.initialize();
168
+ // Only enable if intelligentReordering is enabled
169
+ if (this.analysisConfig.features.intelligentReordering) {
170
+ this.dynamicPipeline = new DynamicPipeline(this.sessionPath, this.aiClient, {
171
+ enabled: true,
172
+ minSkipConfidence: 75,
173
+ showAnalysis: true,
174
+ verbose: false
175
+ });
176
+ await this.dynamicPipeline.initialize();
177
+ } else {
178
+ // Create disabled pipeline
179
+ this.dynamicPipeline = null;
180
+ }
156
181
 
157
182
  // Create session directory
158
183
  await fs.ensureDir(this.sessionPath);
159
184
  await fs.ensureDir(path.join(this.sessionPath, 'qa-responses'));
160
185
  await fs.ensureDir(path.join(this.sessionPath, 'outputs'));
161
186
 
162
- // Analyze project for smart filtering
163
- const spinner = ora('Analyzing your project for context...').start();
187
+ // Analyze project for smart filtering (only if smart filtering is enabled)
164
188
  let projectContext = null;
165
189
  let enableSmartFiltering = false;
166
190
 
167
- try {
168
- projectContext = await analyzeProject(this.projectPath);
169
- spinner.succeed(chalk.green(`✓ Project analyzed: ${getProjectSummary(projectContext)}`));
170
-
171
- // Initialize skip tracker with project context
172
- this.skipTracker = new SkipTracker(this.projectPath, {
173
- projectType: projectContext.type,
174
- frameworks: projectContext.frameworks,
175
- languages: projectContext.languages
176
- });
191
+ if (this.analysisConfig.features.smartFiltering) {
192
+ const spinner = ora('Analyzing your project for context...').start();
177
193
 
178
- // Load learning configuration and learned rules
179
- const learningConfig = await getLearningConfig(this.projectPath);
180
- if (learningConfig.enabled && learningConfig.applyLearnedFilters) {
181
- this.learnedRules = await getActiveRules(this.projectPath);
182
- }
194
+ try {
195
+ projectContext = await analyzeProject(this.projectPath);
196
+ spinner.succeed(chalk.green(`✓ Project analyzed: ${getProjectSummary(projectContext)}`));
197
+
198
+ // Initialize skip tracker with project context (only if pattern detection enabled)
199
+ if (this.analysisConfig.features.patternDetection) {
200
+ this.skipTracker = new SkipTracker(this.projectPath, {
201
+ projectType: projectContext.type,
202
+ frameworks: projectContext.frameworks,
203
+ languages: projectContext.languages
204
+ });
183
205
 
184
- if (projectContext.confidence >= 50) {
185
- // Show project context
186
- console.log(chalk.gray(`\n📊 Project Context:`));
187
- console.log(chalk.gray(` Type: ${projectContext.type}`));
188
- if (projectContext.frameworks.length > 0) {
189
- console.log(chalk.gray(` Frameworks: ${projectContext.frameworks.join(', ')}`));
190
- }
191
- if (projectContext.languages.length > 0) {
192
- console.log(chalk.gray(` Languages: ${projectContext.languages.join(', ')}`));
206
+ // Load learning configuration and learned rules
207
+ const learningConfig = await getLearningConfig(this.projectPath);
208
+ if (learningConfig.enabled && learningConfig.applyLearnedFilters) {
209
+ this.learnedRules = await getActiveRules(this.projectPath);
210
+ }
193
211
  }
194
- console.log(chalk.gray(` Confidence: ${projectContext.confidence}%`));
195
212
 
196
- // Show learning status
197
- if (this.learnedRules.length > 0) {
198
- console.log(chalk.gray(` Learning: ${this.learnedRules.length} learned rule${this.learnedRules.length > 1 ? 's' : ''} active\n`));
199
- } else {
200
- console.log('');
201
- }
213
+ if (projectContext.confidence >= 50) {
214
+ // Show project context
215
+ console.log(chalk.gray(`\n📊 Project Context:`));
216
+ console.log(chalk.gray(` Type: ${projectContext.type}`));
217
+ if (projectContext.frameworks.length > 0) {
218
+ console.log(chalk.gray(` Frameworks: ${projectContext.frameworks.join(', ')}`));
219
+ }
220
+ if (projectContext.languages.length > 0) {
221
+ console.log(chalk.gray(` Languages: ${projectContext.languages.join(', ')}`));
222
+ }
223
+ console.log(chalk.gray(` Confidence: ${projectContext.confidence}%`));
202
224
 
203
- // Ask user if they want smart filtering
204
- const { useSmartFiltering } = await inquirer.prompt([
205
- {
206
- type: 'confirm',
207
- name: 'useSmartFiltering',
208
- message: 'Enable smart filtering to skip irrelevant questions? (Recommended)',
209
- default: true
225
+ // Show learning status
226
+ if (this.learnedRules && this.learnedRules.length > 0) {
227
+ console.log(chalk.gray(` Learning: ${this.learnedRules.length} learned rule${this.learnedRules.length > 1 ? 's' : ''} active\n`));
228
+ } else {
229
+ console.log('');
210
230
  }
211
- ]);
212
231
 
213
- enableSmartFiltering = useSmartFiltering;
232
+ // Ask user if they want smart filtering
233
+ const { useSmartFiltering } = await inquirer.prompt([
234
+ {
235
+ type: 'confirm',
236
+ name: 'useSmartFiltering',
237
+ message: 'Enable smart filtering to skip irrelevant questions? (Recommended)',
238
+ default: true
239
+ }
240
+ ]);
241
+
242
+ enableSmartFiltering = useSmartFiltering;
214
243
 
215
244
  // If user enables filtering and we have learned rules, ask about applying them
216
245
  if (enableSmartFiltering && this.learnedRules.length > 0) {
@@ -637,10 +666,10 @@ class Interviewer {
637
666
  process.exit(0);
638
667
  }
639
668
 
640
- // Analyze answer quality (use AI if available, fallback to heuristic)
669
+ // Analyze answer quality (use AI if enabled and available, fallback to heuristic)
641
670
  let qualityMetrics;
642
671
  try {
643
- if (this.aiClient) {
672
+ if (this.analysisConfig.features.qualityAnalysis && this.aiClient) {
644
673
  const aiAnalysis = await this.aiClient.analyzeAnswerQuality(question.text, answer);
645
674
  qualityMetrics = {
646
675
  wordCount: answer.trim().split(/\s+/).length,
@@ -661,16 +690,18 @@ class Interviewer {
661
690
  qualityMetrics = AnswerQualityAnalyzer.analyze(answer, question);
662
691
  }
663
692
 
664
- // Show quality feedback
665
- if (qualityMetrics.issues && qualityMetrics.issues.length > 0 && qualityMetrics.qualityScore < 70) {
666
- console.log(chalk.yellow(`\n💡 Quality: ${qualityMetrics.qualityScore}/100`));
667
- if (qualityMetrics.suggestions && qualityMetrics.suggestions.length > 0) {
668
- console.log(chalk.gray(` Suggestion: ${qualityMetrics.suggestions[0]}`));
669
- }
670
- } else {
671
- const feedback = AnswerQualityAnalyzer.getFeedback(qualityMetrics);
672
- if (feedback) {
673
- console.log(chalk.cyan(`${feedback}`));
693
+ // Show quality feedback (only if quality analysis is enabled)
694
+ if (this.analysisConfig.features.qualityAnalysis) {
695
+ if (qualityMetrics.issues && qualityMetrics.issues.length > 0 && qualityMetrics.qualityScore < 70) {
696
+ console.log(chalk.yellow(`\n💡 Quality: ${qualityMetrics.qualityScore}/100`));
697
+ if (qualityMetrics.suggestions && qualityMetrics.suggestions.length > 0) {
698
+ console.log(chalk.gray(` Suggestion: ${qualityMetrics.suggestions[0]}`));
699
+ }
700
+ } else {
701
+ const feedback = AnswerQualityAnalyzer.getFeedback(qualityMetrics);
702
+ if (feedback) {
703
+ console.log(chalk.cyan(`${feedback}`));
704
+ }
674
705
  }
675
706
  }
676
707
 
@@ -696,26 +727,28 @@ class Interviewer {
696
727
  return answer;
697
728
  }
698
729
 
699
- // Check if answer needs follow-up
730
+ // Check if answer needs follow-up (only if follow-up questions are enabled)
700
731
  let followUp = null;
701
732
 
702
- // Try AI-generated follow-up first
703
- if (this.aiClient && qualityMetrics.issues && qualityMetrics.issues.length > 0 && qualityMetrics.qualityScore < 70) {
704
- try {
705
- const aiFollowUp = await this.aiClient.generateFollowUp(question.text, answer, qualityMetrics.issues);
706
- if (aiFollowUp) {
707
- followUp = {
708
- message: "Let me ask a more specific question:",
709
- question: aiFollowUp
710
- };
733
+ if (this.analysisConfig.features.followUpQuestions) {
734
+ // Try AI-generated follow-up first
735
+ if (this.aiClient && qualityMetrics.issues && qualityMetrics.issues.length > 0 && qualityMetrics.qualityScore < 70) {
736
+ try {
737
+ const aiFollowUp = await this.aiClient.generateFollowUp(question.text, answer, qualityMetrics.issues);
738
+ if (aiFollowUp) {
739
+ followUp = {
740
+ message: "Let me ask a more specific question:",
741
+ question: aiFollowUp
742
+ };
743
+ }
744
+ } catch (error) {
745
+ // If AI fails, use heuristic fallback
746
+ followUp = this.determineFollowUp(question, answer);
711
747
  }
712
- } catch (error) {
713
- // If AI fails, use heuristic fallback
748
+ } else {
749
+ // Use heuristic follow-up
714
750
  followUp = this.determineFollowUp(question, answer);
715
751
  }
716
- } else {
717
- // Use heuristic follow-up
718
- followUp = this.determineFollowUp(question, answer);
719
752
  }
720
753
 
721
754
  if (followUp) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iservu-inc/adf-cli",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "CLI tool for AgentDevFramework - AI-assisted development framework with multi-provider AI support",
5
5
  "main": "index.js",
6
6
  "bin": {