@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.
- package/lib/ai/analysis-config.js +418 -0
- package/lib/commands/config.js +27 -0
- package/lib/frameworks/interviewer.js +114 -81
- package/package.json +1 -1
|
@@ -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
|
+
};
|
package/lib/commands/config.js
CHANGED
|
@@ -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
|
-
|
|
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 -
|
|
145
|
-
//
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
168
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
console.log(chalk.gray(
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
-
|
|
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 (
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
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
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
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
|
-
}
|
|
713
|
-
//
|
|
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) {
|