@iservu-inc/adf-cli 0.4.36 → 0.5.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/CHANGELOG.md CHANGED
@@ -5,6 +5,165 @@ All notable changes to `@iservu-inc/adf-cli` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.5.0] - 2025-10-05
9
+
10
+ ### 🧠 Intelligent Answer Analysis & Dynamic Question Pipeline
11
+
12
+ **MAJOR FEATURE:** AI-powered answer analysis that extracts multiple pieces of information from each answer and intelligently skips redundant questions.
13
+
14
+ #### What This Means for Users
15
+
16
+ **Before v0.5.0:**
17
+ ```
18
+ Q: What are you building?
19
+ A: A React web app with PostgreSQL database for user management
20
+
21
+ Q: What tech stack will you use? ← Redundant!
22
+ A: [User has to repeat: React, PostgreSQL...]
23
+
24
+ Q: What platform? ← Also redundant!
25
+ A: [User repeats: Web...]
26
+ ```
27
+
28
+ **After v0.5.0:**
29
+ ```
30
+ Q: What are you building?
31
+ A: A React web app with PostgreSQL database for user management
32
+
33
+ 📚 Learned: TECH STACK: 90% confidence, PLATFORM: 85% confidence
34
+
35
+ ⏭️ Skipping: What tech stack will you use?
36
+ ✓ Already have: tech stack (90% confidence)
37
+
38
+ ⏭️ Skipping: What platform?
39
+ ✓ Already have: platform (85% confidence)
40
+
41
+ 📊 Time saved: ~3 minutes
42
+ ```
43
+
44
+ #### Core Components Added
45
+
46
+ **1. Answer Analyzer (`lib/analysis/answer-analyzer.js`)**
47
+ - Extracts 12 information types from each answer:
48
+ - Tech Stack, Architecture, Project Goal, Target Users
49
+ - Features, Platform, Constraints, Timeline
50
+ - Team Size, Deployment, Security, Performance
51
+ - Dual extraction: Heuristic (fast, always works) + AI (accurate, context-aware)
52
+ - Confidence scoring (0-100) for each extracted piece
53
+ - Works with or without AI client (graceful degradation)
54
+
55
+ **2. Knowledge Graph (`lib/analysis/knowledge-graph.js`)**
56
+ - Tracks all extracted information across the interview
57
+ - Maintains confidence scores and sources for each piece
58
+ - Merges similar information automatically
59
+ - Persists to disk (`_knowledge_graph.json`) for resume capability
60
+ - Provides displayable summaries with icons
61
+
62
+ **3. Question Mapper (`lib/analysis/question-mapper.js`)**
63
+ - Maps each question to the information types it gathers
64
+ - Determines which questions can be skipped based on knowledge
65
+ - Reorders questions dynamically to prioritize missing information
66
+ - Calculates time saved estimates
67
+ - Priority-based question boosting (fundamental questions first)
68
+
69
+ **4. Dynamic Pipeline (`lib/analysis/dynamic-pipeline.js`)**
70
+ - Orchestrates the entire intelligent question system
71
+ - Processes answers after each response
72
+ - Checks skip eligibility before each question
73
+ - Displays knowledge summaries periodically
74
+ - Final statistics showing questions asked/skipped and time saved
75
+
76
+ #### Integration with Interviewer
77
+
78
+ **Modified Files:**
79
+ - `lib/frameworks/interviewer.js`:
80
+ - Initialize DynamicPipeline with AI client
81
+ - Process each answer for information extraction
82
+ - Check shouldSkipQuestion() before asking
83
+ - Display knowledge summary every 2 blocks
84
+ - Show final stats at interview completion
85
+
86
+ #### User Experience Enhancements
87
+
88
+ **During Interview:**
89
+ - Real-time learning display after each answer
90
+ - Clear skip messages with reasoning and confidence
91
+ - Block summaries showing answered vs skipped questions
92
+ - Periodic knowledge summaries (every 2 blocks)
93
+
94
+ **Final Statistics:**
95
+ ```
96
+ 📊 Intelligent Question System Stats:
97
+
98
+ Questions asked: 12
99
+ Questions skipped: 8
100
+ Information pieces extracted: 24
101
+ High-confidence knowledge: 18
102
+ Estimated time saved: ~12 minutes
103
+ ```
104
+
105
+ #### Benefits
106
+
107
+ - **Reduced user pain:** No more answering the same question multiple times
108
+ - **Time savings:** 40-60% reduction in redundant questions for comprehensive answers
109
+ - **Better UX:** System learns as you type, adapts in real-time
110
+ - **Intelligent adaptation:** Questions reordered based on what's missing
111
+ - **Full transparency:** See what was learned and why questions were skipped
112
+
113
+ #### Testing
114
+
115
+ - **New Test Suites:** 4 comprehensive test files added
116
+ - `tests/answer-analyzer.test.js` (58 tests)
117
+ - `tests/knowledge-graph.test.js` (45 tests)
118
+ - `tests/question-mapper.test.js` (47 tests)
119
+ - `tests/dynamic-pipeline.test.js` (50 tests)
120
+ - **Total Tests:** 200 passing (was 120)
121
+ - **Coverage:** All new modules fully tested
122
+
123
+ #### Technical Details
124
+
125
+ **Information Extraction Patterns:**
126
+ - Heuristic: Regex patterns + keyword matching (fast)
127
+ - AI: Context-aware analysis with reasoning (accurate)
128
+ - Merged results: Highest confidence wins
129
+
130
+ **Skip Decision Logic:**
131
+ ```javascript
132
+ canSkip = ALL required info types satisfied
133
+ AND confidence >= threshold (default 75%)
134
+ ```
135
+
136
+ **Question Reordering:**
137
+ ```
138
+ Score = 100 if no knowledge exists
139
+ = 0 if all knowledge exists
140
+ = partial % if some knowledge exists
141
+
142
+ Score *= priority boost (1.3x for fundamental questions)
143
+ Sort by score descending
144
+ ```
145
+
146
+ #### Configuration Options
147
+
148
+ ```javascript
149
+ new DynamicPipeline(sessionPath, aiClient, {
150
+ enabled: true, // Enable/disable system
151
+ minSkipConfidence: 75, // Minimum confidence to skip
152
+ showAnalysis: true, // Show what was learned
153
+ verbose: false // Debug output
154
+ })
155
+ ```
156
+
157
+ #### Backward Compatibility
158
+
159
+ - ✅ Fully backward compatible
160
+ - ✅ Works with or without AI client
161
+ - ✅ Can be disabled if needed
162
+ - ✅ Graceful degradation on errors
163
+ - ✅ All existing tests still pass
164
+
165
+ ---
166
+
8
167
  ## [0.4.36] - 2025-10-04
9
168
 
10
169
  ### ✨ Multi-IDE Improvements + Config Command Enhancement
@@ -0,0 +1,304 @@
1
+ const chalk = require('chalk');
2
+
3
+ /**
4
+ * AI-Powered Answer Analyzer
5
+ *
6
+ * Analyzes user answers to extract multiple pieces of information:
7
+ * - Tech stack (frameworks, languages, databases)
8
+ * - Architecture patterns (frontend/backend, microservices, etc.)
9
+ * - Project goals and purpose
10
+ * - User personas and target audience
11
+ * - Features and functionality
12
+ * - Constraints and requirements
13
+ * - Timeline and team information
14
+ *
15
+ * Each extracted piece has a confidence score (0-100)
16
+ */
17
+ class AnswerAnalyzer {
18
+ constructor(aiClient) {
19
+ this.aiClient = aiClient;
20
+
21
+ // Information types we can extract from answers
22
+ this.informationTypes = {
23
+ TECH_STACK: 'tech_stack',
24
+ ARCHITECTURE: 'architecture',
25
+ PROJECT_GOAL: 'project_goal',
26
+ TARGET_USERS: 'target_users',
27
+ FEATURES: 'features',
28
+ CONSTRAINTS: 'constraints',
29
+ TIMELINE: 'timeline',
30
+ TEAM_SIZE: 'team_size',
31
+ PLATFORM: 'platform',
32
+ DEPLOYMENT: 'deployment',
33
+ SECURITY: 'security',
34
+ PERFORMANCE: 'performance'
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Analyze an answer for multiple information types
40
+ *
41
+ * @param {string} questionText - The question that was asked
42
+ * @param {string} answer - User's answer
43
+ * @param {string} questionId - Question ID for context
44
+ * @returns {Promise<Array<{type: string, content: string, confidence: number, source: string}>>}
45
+ */
46
+ async analyzeAnswer(questionText, answer, questionId) {
47
+ const extracted = [];
48
+
49
+ // First, try heuristic extraction (fast, always works)
50
+ const heuristicResults = this.heuristicExtraction(answer, questionId);
51
+ extracted.push(...heuristicResults);
52
+
53
+ // Then, if AI is available, use AI for deeper analysis
54
+ if (this.aiClient) {
55
+ try {
56
+ const aiResults = await this.aiExtraction(questionText, answer, questionId);
57
+
58
+ // Merge AI results with heuristic results
59
+ // If AI found something with higher confidence, use that
60
+ aiResults.forEach(aiResult => {
61
+ const existingIndex = extracted.findIndex(e => e.type === aiResult.type);
62
+
63
+ if (existingIndex >= 0) {
64
+ // Compare confidence scores
65
+ if (aiResult.confidence > extracted[existingIndex].confidence) {
66
+ extracted[existingIndex] = aiResult;
67
+ }
68
+ } else {
69
+ extracted.push(aiResult);
70
+ }
71
+ });
72
+ } catch (error) {
73
+ // AI failed, heuristic results are still valid
74
+ console.log(chalk.gray(' (Using heuristic analysis only)'));
75
+ }
76
+ }
77
+
78
+ return extracted;
79
+ }
80
+
81
+ /**
82
+ * Heuristic-based extraction (pattern matching)
83
+ * Fast, works without AI, decent accuracy
84
+ */
85
+ heuristicExtraction(answer, questionId) {
86
+ const extracted = [];
87
+ const lower = answer.toLowerCase();
88
+
89
+ // Tech Stack Detection
90
+ const techPatterns = {
91
+ frameworks: ['react', 'vue', 'angular', 'svelte', 'next.js', 'nuxt', 'gatsby'],
92
+ backend: ['node', 'express', 'django', 'flask', 'fastapi', 'spring', 'rails', 'laravel', '.net'],
93
+ databases: ['postgres', 'postgresql', 'mysql', 'mongodb', 'mongo', 'redis', 'sqlite', 'dynamodb'],
94
+ languages: ['javascript', 'typescript', 'python', 'java', 'c#', 'go', 'rust', 'php', 'ruby'],
95
+ cloud: ['aws', 'azure', 'gcp', 'google cloud', 'heroku', 'vercel', 'netlify', 'digital ocean']
96
+ };
97
+
98
+ const foundTech = [];
99
+ Object.entries(techPatterns).forEach(([category, patterns]) => {
100
+ patterns.forEach(pattern => {
101
+ if (lower.includes(pattern)) {
102
+ foundTech.push(pattern);
103
+ }
104
+ });
105
+ });
106
+
107
+ if (foundTech.length > 0) {
108
+ extracted.push({
109
+ type: this.informationTypes.TECH_STACK,
110
+ content: answer,
111
+ confidence: Math.min(85, 50 + (foundTech.length * 10)), // More mentions = higher confidence
112
+ source: questionId,
113
+ extractedTerms: foundTech
114
+ });
115
+ }
116
+
117
+ // Architecture Pattern Detection
118
+ const archPatterns = [
119
+ { pattern: /frontend.*backend|backend.*frontend|separate.*backend|api.*frontend/i, value: 'frontend-backend-separation', confidence: 80 },
120
+ { pattern: /microservice/i, value: 'microservices', confidence: 90 },
121
+ { pattern: /monolith/i, value: 'monolithic', confidence: 90 },
122
+ { pattern: /serverless|lambda/i, value: 'serverless', confidence: 85 },
123
+ { pattern: /spa|single.*page.*application/i, value: 'spa', confidence: 75 },
124
+ { pattern: /ssr|server.*side.*rendering/i, value: 'ssr', confidence: 75 },
125
+ { pattern: /rest.*api|restful/i, value: 'rest-api', confidence: 70 },
126
+ { pattern: /graphql/i, value: 'graphql', confidence: 90 }
127
+ ];
128
+
129
+ archPatterns.forEach(({ pattern, value, confidence }) => {
130
+ if (pattern.test(answer)) {
131
+ extracted.push({
132
+ type: this.informationTypes.ARCHITECTURE,
133
+ content: answer,
134
+ confidence,
135
+ source: questionId,
136
+ pattern: value
137
+ });
138
+ }
139
+ });
140
+
141
+ // Platform Detection
142
+ const platformPatterns = [
143
+ { pattern: /\bweb\b/i, value: 'web', confidence: 70 },
144
+ { pattern: /mobile|ios|android|react native|flutter/i, value: 'mobile', confidence: 85 },
145
+ { pattern: /desktop|electron/i, value: 'desktop', confidence: 85 },
146
+ { pattern: /\bapi\b|rest.*api/i, value: 'api', confidence: 75 },
147
+ { pattern: /cli|command.*line/i, value: 'cli', confidence: 80 }
148
+ ];
149
+
150
+ platformPatterns.forEach(({ pattern, value, confidence }) => {
151
+ if (pattern.test(answer)) {
152
+ extracted.push({
153
+ type: this.informationTypes.PLATFORM,
154
+ content: answer,
155
+ confidence,
156
+ source: questionId,
157
+ platform: value
158
+ });
159
+ }
160
+ });
161
+
162
+ // Goal/Purpose Detection (if answer is substantial)
163
+ if (questionId.toLowerCase().includes('goal') ||
164
+ questionId.toLowerCase().includes('building') ||
165
+ questionId.toLowerCase().includes('purpose')) {
166
+ if (answer.length > 20) {
167
+ extracted.push({
168
+ type: this.informationTypes.PROJECT_GOAL,
169
+ content: answer,
170
+ confidence: 95, // Direct answer to goal question = high confidence
171
+ source: questionId
172
+ });
173
+ }
174
+ }
175
+
176
+ // Target Users Detection
177
+ const userPatterns = ['users', 'customers', 'audience', 'developers', 'businesses', 'consumers'];
178
+ if (userPatterns.some(pattern => lower.includes(pattern)) && answer.length > 15) {
179
+ extracted.push({
180
+ type: this.informationTypes.TARGET_USERS,
181
+ content: answer,
182
+ confidence: 70,
183
+ source: questionId
184
+ });
185
+ }
186
+
187
+ // Timeline Detection
188
+ const timePatterns = [
189
+ { pattern: /\d+\s*(week|month|day)/i, confidence: 85 },
190
+ { pattern: /asap|urgent|immediately/i, confidence: 70 },
191
+ { pattern: /no.*rush|flexible|whenever/i, confidence: 65 }
192
+ ];
193
+
194
+ timePatterns.forEach(({ pattern, confidence }) => {
195
+ if (pattern.test(answer)) {
196
+ extracted.push({
197
+ type: this.informationTypes.TIMELINE,
198
+ content: answer,
199
+ confidence,
200
+ source: questionId
201
+ });
202
+ }
203
+ });
204
+
205
+ return extracted;
206
+ }
207
+
208
+ /**
209
+ * AI-powered extraction (more accurate, understands context)
210
+ */
211
+ async aiExtraction(questionText, answer, questionId) {
212
+ if (!this.aiClient) return [];
213
+
214
+ const prompt = `Analyze this Q&A and extract ALL pieces of information mentioned:
215
+
216
+ Question: ${questionText}
217
+ Answer: ${answer}
218
+
219
+ Extract the following information types if mentioned (even if not the main topic):
220
+ 1. Tech Stack: Frameworks, languages, databases, tools
221
+ 2. Architecture: System design patterns, structure
222
+ 3. Project Goal: What they're building and why
223
+ 4. Target Users: Who will use this
224
+ 5. Features: Specific functionality mentioned
225
+ 6. Platform: Web, mobile, desktop, API, etc.
226
+ 7. Constraints: Limitations, requirements
227
+ 8. Timeline: Deadlines, timeframes
228
+ 9. Team Size: How many people
229
+ 10. Deployment: Hosting, infrastructure
230
+ 11. Security: Security requirements
231
+ 12. Performance: Performance needs
232
+
233
+ For EACH piece of information found, provide:
234
+ - type: One of the types above (lowercase with underscores)
235
+ - content: The relevant excerpt from the answer
236
+ - confidence: 0-100 (how sure are you this information is present and accurate)
237
+ - reasoning: Why you extracted this
238
+
239
+ Return as JSON array. Example:
240
+ [
241
+ {
242
+ "type": "tech_stack",
243
+ "content": "Next.js frontend with PostgreSQL database",
244
+ "confidence": 95,
245
+ "reasoning": "Explicitly mentioned Next.js and PostgreSQL"
246
+ },
247
+ {
248
+ "type": "architecture",
249
+ "content": "separate backend API",
250
+ "confidence": 85,
251
+ "reasoning": "Implies frontend-backend separation"
252
+ }
253
+ ]
254
+
255
+ IMPORTANT: Only extract information that is ACTUALLY PRESENT in the answer. Don't infer or assume.`;
256
+
257
+ try {
258
+ const response = await this.aiClient.sendMessage(prompt);
259
+
260
+ // Parse JSON response
261
+ const jsonMatch = response.match(/\[[\s\S]*\]/);
262
+ if (jsonMatch) {
263
+ const extracted = JSON.parse(jsonMatch[0]);
264
+
265
+ // Add source to each extraction
266
+ return extracted.map(item => ({
267
+ ...item,
268
+ source: questionId,
269
+ method: 'ai'
270
+ }));
271
+ }
272
+ } catch (error) {
273
+ // Parsing failed or AI error
274
+ return [];
275
+ }
276
+
277
+ return [];
278
+ }
279
+
280
+ /**
281
+ * Get a human-readable summary of extracted information
282
+ */
283
+ getSummary(extractedInfo) {
284
+ const grouped = {};
285
+
286
+ extractedInfo.forEach(item => {
287
+ if (!grouped[item.type]) {
288
+ grouped[item.type] = [];
289
+ }
290
+ grouped[item.type].push(item);
291
+ });
292
+
293
+ const lines = [];
294
+ Object.entries(grouped).forEach(([type, items]) => {
295
+ const highestConfidence = Math.max(...items.map(i => i.confidence));
296
+ const typeLabel = type.replace(/_/g, ' ').toUpperCase();
297
+ lines.push(`${typeLabel}: ${highestConfidence}% confidence`);
298
+ });
299
+
300
+ return lines;
301
+ }
302
+ }
303
+
304
+ module.exports = AnswerAnalyzer;