@iservu-inc/adf-cli 0.3.0 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/.project/chats/{current → complete}/2025-10-03_AGENTS-MD-AND-TOOL-GENERATORS.md +82 -17
  2. package/.project/chats/complete/2025-10-03_AI-PROVIDER-INTEGRATION.md +568 -0
  3. package/.project/chats/complete/2025-10-03_FRAMEWORK-UPDATE-SYSTEM.md +497 -0
  4. package/.project/chats/complete/2025-10-04_CONFIG-COMMAND.md +503 -0
  5. package/.project/chats/current/2025-10-04_PHASE-4-1-SMART-FILTERING.md +381 -0
  6. package/.project/chats/current/SESSION-STATUS.md +168 -0
  7. package/.project/docs/AI-PROVIDER-INTEGRATION.md +600 -0
  8. package/.project/docs/FRAMEWORK-UPDATE-INTEGRATION.md +421 -0
  9. package/.project/docs/FRAMEWORK-UPDATE-SYSTEM.md +832 -0
  10. package/.project/docs/PHASE-4-2-LEARNING-SYSTEM.md +881 -0
  11. package/.project/docs/PROJECT-STRUCTURE-EXPLANATION.md +500 -0
  12. package/.project/docs/SMART-FILTERING-SYSTEM.md +385 -0
  13. package/.project/docs/architecture/SYSTEM-DESIGN.md +122 -1
  14. package/.project/docs/goals/PROJECT-VISION.md +61 -34
  15. package/CHANGELOG.md +257 -1
  16. package/README.md +476 -292
  17. package/bin/adf.js +7 -0
  18. package/lib/ai/ai-client.js +328 -0
  19. package/lib/ai/ai-config.js +398 -0
  20. package/lib/analyzers/project-analyzer.js +380 -0
  21. package/lib/commands/config.js +221 -0
  22. package/lib/commands/init.js +56 -10
  23. package/lib/filters/question-filter.js +480 -0
  24. package/lib/frameworks/interviewer.js +271 -12
  25. package/lib/frameworks/progress-tracker.js +8 -1
  26. package/lib/learning/learning-manager.js +447 -0
  27. package/lib/learning/pattern-detector.js +376 -0
  28. package/lib/learning/rule-generator.js +304 -0
  29. package/lib/learning/skip-tracker.js +260 -0
  30. package/lib/learning/storage.js +296 -0
  31. package/package.json +70 -57
  32. package/tests/learning-storage.test.js +184 -0
  33. package/tests/pattern-detector.test.js +297 -0
  34. package/tests/project-analyzer.test.js +221 -0
  35. package/tests/question-filter.test.js +297 -0
  36. package/tests/skip-tracker.test.js +198 -0
@@ -0,0 +1,447 @@
1
+ const inquirer = require('inquirer');
2
+ const chalk = require('chalk');
3
+ const storage = require('./storage');
4
+ const { analyzeSkipPatterns } = require('./skip-tracker');
5
+ const { detectPatterns, getPatternSummary } = require('./pattern-detector');
6
+ const { getActiveRules, toggleRule, removeRule } = require('./rule-generator');
7
+
8
+ /**
9
+ * Learning Manager - CLI interface for managing learning data
10
+ *
11
+ * Provides:
12
+ * - View skip history
13
+ * - Review detected patterns
14
+ * - Enable/disable learning
15
+ * - Clear learning data
16
+ * - Export learning data
17
+ */
18
+
19
+ class LearningManager {
20
+ constructor(projectPath) {
21
+ this.projectPath = projectPath;
22
+ }
23
+
24
+ /**
25
+ * Show main learning management menu
26
+ */
27
+ async showMenu() {
28
+ // Load stats
29
+ const stats = await storage.getLearningStats(this.projectPath);
30
+ const config = await storage.getLearningConfig(this.projectPath);
31
+ const patterns = await detectPatterns(this.projectPath);
32
+ const patternSummary = getPatternSummary(patterns);
33
+ const dataSize = await storage.getLearningDataSize(this.projectPath);
34
+
35
+ console.log(chalk.cyan.bold('\n┌─────────────────────────────────────────────────────┐'));
36
+ console.log(chalk.cyan.bold('│ Learning System Configuration │'));
37
+ console.log(chalk.cyan.bold('├─────────────────────────────────────────────────────┤'));
38
+ console.log(chalk.cyan('│'));
39
+ console.log(chalk.cyan(`│ 📊 Learning Statistics`));
40
+ console.log(chalk.cyan(`│ Sessions analyzed: ${stats.totalSessions}`));
41
+ console.log(chalk.cyan(`│ Questions tracked: ${stats.totalAnswers + stats.totalSkips}`));
42
+ console.log(chalk.cyan(`│ Patterns detected: ${patternSummary.total}`));
43
+ console.log(chalk.cyan(`│ Storage used: ${(dataSize / 1024).toFixed(1)} KB`));
44
+ console.log(chalk.cyan('│'));
45
+
46
+ if (patternSummary.total > 0) {
47
+ console.log(chalk.cyan(`│ 🎯 Detected Patterns`));
48
+
49
+ const allPatterns = [
50
+ ...patterns.consistentSkips.slice(0, 2),
51
+ ...patterns.categoryPatterns.slice(0, 1)
52
+ ];
53
+
54
+ for (const pattern of allPatterns.slice(0, 3)) {
55
+ const icon = pattern.confidence >= 80 ? '🔴' : pattern.confidence >= 60 ? '🟡' : '🟢';
56
+ if (pattern.type === 'consistent_skip') {
57
+ console.log(chalk.cyan(`│ ${icon} Skip "${pattern.questionText?.substring(0, 35)}..." (${pattern.confidence}%)`));
58
+ } else if (pattern.type === 'category_skip') {
59
+ console.log(chalk.cyan(`│ ${icon} Skip ${pattern.category} questions (${pattern.confidence}%)`));
60
+ }
61
+ }
62
+
63
+ if (patternSummary.total > 3) {
64
+ console.log(chalk.cyan(`│ ... and ${patternSummary.total - 3} more`));
65
+ }
66
+ console.log(chalk.cyan('│'));
67
+ }
68
+
69
+ console.log(chalk.cyan(`│ ⚙️ Options`));
70
+ console.log(chalk.cyan(`│ 1. View Skip History`));
71
+ console.log(chalk.cyan(`│ 2. Review Detected Patterns`));
72
+ console.log(chalk.cyan(`│ 3. Manage Learned Rules`));
73
+ console.log(chalk.cyan(`│ 4. Learning Settings ${config.enabled ? chalk.green('(✓ Enabled)') : chalk.yellow('(○ Disabled)')}`));
74
+ console.log(chalk.cyan(`│ 5. Clear Learning Data`));
75
+ console.log(chalk.cyan(`│ 6. Back to Main Menu`));
76
+ console.log(chalk.cyan('│'));
77
+ console.log(chalk.cyan.bold('└─────────────────────────────────────────────────────┘\n'));
78
+
79
+ const { choice } = await inquirer.prompt([
80
+ {
81
+ type: 'list',
82
+ name: 'choice',
83
+ message: 'Select an option:',
84
+ choices: [
85
+ { name: '1. View Skip History', value: 'history' },
86
+ { name: '2. Review Detected Patterns', value: 'patterns' },
87
+ { name: '3. Manage Learned Rules', value: 'rules' },
88
+ { name: '4. Learning Settings', value: 'settings' },
89
+ { name: '5. Clear Learning Data', value: 'clear' },
90
+ { name: '6. Back to Main Menu', value: 'back' }
91
+ ]
92
+ }
93
+ ]);
94
+
95
+ switch (choice) {
96
+ case 'history':
97
+ await this.viewSkipHistory();
98
+ break;
99
+ case 'patterns':
100
+ await this.reviewPatterns();
101
+ break;
102
+ case 'rules':
103
+ await this.manageRules();
104
+ break;
105
+ case 'settings':
106
+ await this.manageSettings();
107
+ break;
108
+ case 'clear':
109
+ await this.clearLearningData();
110
+ break;
111
+ case 'back':
112
+ return 'back';
113
+ }
114
+
115
+ return 'continue';
116
+ }
117
+
118
+ /**
119
+ * View skip history
120
+ */
121
+ async viewSkipHistory() {
122
+ const analysis = await analyzeSkipPatterns(this.projectPath);
123
+
124
+ console.log(chalk.cyan.bold('\n📋 Skip History\n'));
125
+
126
+ if (analysis.totalSessions === 0) {
127
+ console.log(chalk.yellow('No skip history available yet.\n'));
128
+ console.log(chalk.gray('Skip history will be tracked as you complete interviews.\n'));
129
+ await this.pressEnterToContinue();
130
+ return;
131
+ }
132
+
133
+ console.log(chalk.gray(`Total Sessions: ${analysis.totalSessions}`));
134
+ console.log(chalk.gray(`Total Skips: ${analysis.totalSkips} (${analysis.manualSkips} manual, ${analysis.filteredSkips} filtered)\n`));
135
+
136
+ if (analysis.mostSkippedQuestions.length > 0) {
137
+ console.log(chalk.cyan('Most Skipped Questions:\n'));
138
+ for (const q of analysis.mostSkippedQuestions.slice(0, 10)) {
139
+ const percentage = Math.round((q.count / analysis.totalSessions) * 100);
140
+ console.log(chalk.white(` ${q.count}x (${percentage}%) - ${q.text.substring(0, 60)}${q.text.length > 60 ? '...' : ''}`));
141
+ if (q.category) {
142
+ console.log(chalk.gray(` Category: ${q.category}`));
143
+ }
144
+ console.log('');
145
+ }
146
+ }
147
+
148
+ if (analysis.mostSkippedCategories.length > 0) {
149
+ console.log(chalk.cyan('Most Skipped Categories:\n'));
150
+ for (const cat of analysis.mostSkippedCategories) {
151
+ console.log(chalk.white(` ${cat.category}: ${cat.count} skips`));
152
+ }
153
+ console.log('');
154
+ }
155
+
156
+ await this.pressEnterToContinue();
157
+ }
158
+
159
+ /**
160
+ * Review detected patterns
161
+ */
162
+ async reviewPatterns() {
163
+ const patterns = await detectPatterns(this.projectPath);
164
+ const patternSummary = getPatternSummary(patterns);
165
+
166
+ console.log(chalk.cyan.bold('\n🔍 Detected Patterns\n'));
167
+
168
+ if (patternSummary.total === 0) {
169
+ console.log(chalk.yellow('No patterns detected yet.\n'));
170
+ console.log(chalk.gray('Patterns will be detected after 3+ interview sessions.\n'));
171
+ await this.pressEnterToContinue();
172
+ return;
173
+ }
174
+
175
+ console.log(chalk.gray(`Total Patterns: ${patternSummary.total}`));
176
+ console.log(chalk.gray(`High Confidence (≥80%): ${patternSummary.highConfidence}`));
177
+ console.log(chalk.gray(`Medium Confidence (60-79%): ${patternSummary.mediumConfidence}`));
178
+ console.log(chalk.gray(`Low Confidence (<60%): ${patternSummary.lowConfidence}\n`));
179
+
180
+ // Show high confidence patterns
181
+ if (patternSummary.highConfidence > 0) {
182
+ console.log(chalk.red.bold('🔴 High Confidence (>80%)\n'));
183
+
184
+ const highPatterns = [
185
+ ...patterns.consistentSkips.filter(p => p.confidence >= 80),
186
+ ...patterns.categoryPatterns.filter(p => p.confidence >= 80)
187
+ ];
188
+
189
+ for (const pattern of highPatterns.slice(0, 5)) {
190
+ if (pattern.type === 'consistent_skip') {
191
+ console.log(chalk.white(` • Skip question: "${pattern.questionText}"`));
192
+ console.log(chalk.gray(` Confidence: ${pattern.confidence}% (${pattern.skipCount} of ${pattern.sessionsAnalyzed} sessions)`));
193
+ console.log(chalk.green(` ✓ Recommendation: ${pattern.recommendation}`));
194
+ } else if (pattern.type === 'category_skip') {
195
+ console.log(chalk.white(` • Skip ${pattern.category} questions`));
196
+ console.log(chalk.gray(` Confidence: ${pattern.confidence}% (${pattern.skipCount} of ${pattern.totalQuestions} questions)`));
197
+ console.log(chalk.green(` ✓ Recommendation: ${pattern.recommendation}`));
198
+ }
199
+ console.log('');
200
+ }
201
+ }
202
+
203
+ // Show medium confidence patterns
204
+ if (patternSummary.mediumConfidence > 0) {
205
+ console.log(chalk.yellow.bold('🟡 Medium Confidence (60-80%)\n'));
206
+
207
+ const mediumPatterns = [
208
+ ...patterns.consistentSkips.filter(p => p.confidence >= 60 && p.confidence < 80),
209
+ ...patterns.categoryPatterns.filter(p => p.confidence >= 60 && p.confidence < 80),
210
+ ...patterns.userPreferences
211
+ ];
212
+
213
+ for (const pattern of mediumPatterns.slice(0, 3)) {
214
+ if (pattern.type === 'user_preference') {
215
+ console.log(chalk.white(` • User preference: ${pattern.preference.replace('_', ' ')}`));
216
+ console.log(chalk.gray(` Category: ${pattern.category}, Avg: ${pattern.avgWordCount} words`));
217
+ console.log(chalk.green(` ℹ️ ${pattern.recommendation}`));
218
+ } else {
219
+ console.log(chalk.gray(` • ${pattern.recommendation} (${pattern.confidence}%)`));
220
+ }
221
+ console.log('');
222
+ }
223
+ }
224
+
225
+ await this.pressEnterToContinue();
226
+ }
227
+
228
+ /**
229
+ * Manage learned rules
230
+ */
231
+ async manageRules() {
232
+ const rules = await getActiveRules(this.projectPath);
233
+
234
+ console.log(chalk.cyan.bold('\n⚙️ Learned Rules\n'));
235
+
236
+ if (rules.length === 0) {
237
+ console.log(chalk.yellow('No learned rules yet.\n'));
238
+ console.log(chalk.gray('Rules are automatically created from high-confidence patterns.\n'));
239
+ await this.pressEnterToContinue();
240
+ return;
241
+ }
242
+
243
+ console.log(chalk.gray(`Total Rules: ${rules.length} active\n`));
244
+
245
+ // Show rules
246
+ for (let i = 0; i < rules.length; i++) {
247
+ const rule = rules[i];
248
+ const status = rule.enabled ? chalk.green('✓ Enabled') : chalk.yellow('○ Disabled');
249
+
250
+ console.log(chalk.white(`${i + 1}. ${status}`));
251
+ console.log(chalk.gray(` Type: ${rule.type}`));
252
+ console.log(chalk.gray(` ${rule.reason}`));
253
+ console.log(chalk.gray(` Confidence: ${rule.confidence}%`));
254
+ console.log('');
255
+ }
256
+
257
+ const { action } = await inquirer.prompt([
258
+ {
259
+ type: 'list',
260
+ name: 'action',
261
+ message: 'What would you like to do?',
262
+ choices: [
263
+ { name: 'Enable/Disable a rule', value: 'toggle' },
264
+ { name: 'Back', value: 'back' }
265
+ ]
266
+ }
267
+ ]);
268
+
269
+ if (action === 'toggle') {
270
+ const { ruleIndex } = await inquirer.prompt([
271
+ {
272
+ type: 'number',
273
+ name: 'ruleIndex',
274
+ message: 'Enter rule number:',
275
+ validate: (input) => {
276
+ if (input < 1 || input > rules.length) {
277
+ return `Please enter a number between 1 and ${rules.length}`;
278
+ }
279
+ return true;
280
+ }
281
+ }
282
+ ]);
283
+
284
+ const rule = rules[ruleIndex - 1];
285
+ await toggleRule(this.projectPath, rule.id, !rule.enabled);
286
+
287
+ console.log(chalk.green(`\n✓ Rule ${rule.enabled ? 'disabled' : 'enabled'}\n`));
288
+ await this.pressEnterToContinue();
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Manage learning settings
294
+ */
295
+ async manageSettings() {
296
+ const config = await storage.getLearningConfig(this.projectPath);
297
+
298
+ console.log(chalk.cyan.bold('\n⚙️ Learning System Settings\n'));
299
+
300
+ const { action } = await inquirer.prompt([
301
+ {
302
+ type: 'list',
303
+ name: 'action',
304
+ message: 'What would you like to configure?',
305
+ choices: [
306
+ {
307
+ name: `Learning System: ${config.enabled ? chalk.green('✓ Enabled') : chalk.yellow('○ Disabled')}`,
308
+ value: 'toggle_enabled'
309
+ },
310
+ {
311
+ name: `Track Skip Actions: ${config.trackSkips ? chalk.green('✓') : chalk.yellow('○')}`,
312
+ value: 'toggle_skips'
313
+ },
314
+ {
315
+ name: `Track Answers: ${config.trackAnswers ? chalk.green('✓') : chalk.yellow('○')}`,
316
+ value: 'toggle_answers'
317
+ },
318
+ {
319
+ name: `Detect Patterns: ${config.detectPatterns ? chalk.green('✓') : chalk.yellow('○')}`,
320
+ value: 'toggle_patterns'
321
+ },
322
+ {
323
+ name: `Apply Learned Filters: ${config.applyLearnedFilters ? chalk.green('✓') : chalk.yellow('○')}`,
324
+ value: 'toggle_filters'
325
+ },
326
+ { name: `Minimum sessions for pattern: ${config.minSessionsForPattern}`, value: 'min_sessions' },
327
+ { name: `Minimum confidence for auto-filter: ${config.minConfidenceForAutoFilter}%`, value: 'min_confidence' },
328
+ { name: 'Reset to defaults', value: 'reset' },
329
+ { name: 'Back', value: 'back' }
330
+ ]
331
+ }
332
+ ]);
333
+
334
+ if (action === 'back') return;
335
+
336
+ if (action === 'toggle_enabled') {
337
+ config.enabled = !config.enabled;
338
+ await storage.saveLearningConfig(this.projectPath, config);
339
+ console.log(chalk.green(`\n✓ Learning system ${config.enabled ? 'enabled' : 'disabled'}\n`));
340
+ } else if (action === 'toggle_skips') {
341
+ config.trackSkips = !config.trackSkips;
342
+ await storage.saveLearningConfig(this.projectPath, config);
343
+ console.log(chalk.green(`\n✓ Skip tracking ${config.trackSkips ? 'enabled' : 'disabled'}\n`));
344
+ } else if (action === 'toggle_answers') {
345
+ config.trackAnswers = !config.trackAnswers;
346
+ await storage.saveLearningConfig(this.projectPath, config);
347
+ console.log(chalk.green(`\n✓ Answer tracking ${config.trackAnswers ? 'enabled' : 'disabled'}\n`));
348
+ } else if (action === 'toggle_patterns') {
349
+ config.detectPatterns = !config.detectPatterns;
350
+ await storage.saveLearningConfig(this.projectPath, config);
351
+ console.log(chalk.green(`\n✓ Pattern detection ${config.detectPatterns ? 'enabled' : 'disabled'}\n`));
352
+ } else if (action === 'toggle_filters') {
353
+ config.applyLearnedFilters = !config.applyLearnedFilters;
354
+ await storage.saveLearningConfig(this.projectPath, config);
355
+ console.log(chalk.green(`\n✓ Learned filters ${config.applyLearnedFilters ? 'enabled' : 'disabled'}\n`));
356
+ } else if (action === 'min_sessions') {
357
+ const { value } = await inquirer.prompt([
358
+ {
359
+ type: 'number',
360
+ name: 'value',
361
+ message: 'Minimum sessions for pattern detection:',
362
+ default: config.minSessionsForPattern,
363
+ validate: (input) => input >= 1 && input <= 10
364
+ }
365
+ ]);
366
+ config.minSessionsForPattern = value;
367
+ await storage.saveLearningConfig(this.projectPath, config);
368
+ console.log(chalk.green(`\n✓ Minimum sessions updated to ${value}\n`));
369
+ } else if (action === 'min_confidence') {
370
+ const { value } = await inquirer.prompt([
371
+ {
372
+ type: 'number',
373
+ name: 'value',
374
+ message: 'Minimum confidence for auto-filter (%):',
375
+ default: config.minConfidenceForAutoFilter,
376
+ validate: (input) => input >= 50 && input <= 100
377
+ }
378
+ ]);
379
+ config.minConfidenceForAutoFilter = value;
380
+ await storage.saveLearningConfig(this.projectPath, config);
381
+ console.log(chalk.green(`\n✓ Minimum confidence updated to ${value}%\n`));
382
+ } else if (action === 'reset') {
383
+ const defaultConfig = {
384
+ version: '1.0',
385
+ enabled: true,
386
+ trackSkips: true,
387
+ trackAnswers: true,
388
+ detectPatterns: true,
389
+ applyLearnedFilters: true,
390
+ shareAnonymousPatterns: false,
391
+ minSessionsForPattern: 3,
392
+ minConfidenceForAutoFilter: 75
393
+ };
394
+ await storage.saveLearningConfig(this.projectPath, defaultConfig);
395
+ console.log(chalk.green('\n✓ Settings reset to defaults\n'));
396
+ }
397
+
398
+ await this.pressEnterToContinue();
399
+ }
400
+
401
+ /**
402
+ * Clear all learning data
403
+ */
404
+ async clearLearningData() {
405
+ console.log(chalk.yellow.bold('\n⚠️ Clear Learning Data\n'));
406
+ console.log(chalk.gray('This will delete:'));
407
+ console.log(chalk.gray(' • Skip history'));
408
+ console.log(chalk.gray(' • Answer history'));
409
+ console.log(chalk.gray(' • Detected patterns'));
410
+ console.log(chalk.gray(' • Learned rules'));
411
+ console.log(chalk.gray(' • Statistics\n'));
412
+ console.log(chalk.red('This action cannot be undone.\n'));
413
+
414
+ const { confirm } = await inquirer.prompt([
415
+ {
416
+ type: 'confirm',
417
+ name: 'confirm',
418
+ message: 'Are you sure you want to clear all learning data?',
419
+ default: false
420
+ }
421
+ ]);
422
+
423
+ if (confirm) {
424
+ await storage.clearLearningData(this.projectPath);
425
+ console.log(chalk.green('\n✓ Learning data cleared\n'));
426
+ } else {
427
+ console.log(chalk.gray('\nCancelled\n'));
428
+ }
429
+
430
+ await this.pressEnterToContinue();
431
+ }
432
+
433
+ /**
434
+ * Helper to pause for user input
435
+ */
436
+ async pressEnterToContinue() {
437
+ await inquirer.prompt([
438
+ {
439
+ type: 'input',
440
+ name: 'continue',
441
+ message: 'Press Enter to continue...',
442
+ }
443
+ ]);
444
+ }
445
+ }
446
+
447
+ module.exports = LearningManager;