@iservu-inc/adf-cli 0.4.36 → 0.5.1

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,249 @@ 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.1] - 2025-10-05
9
+
10
+ ### 🎯 Improved Existing Project Detection UX
11
+
12
+ **ENHANCEMENT:** Better user experience when initializing ADF in directories with existing content.
13
+
14
+ #### What Changed
15
+
16
+ **Before v0.5.1:**
17
+ ```
18
+ .adf directory already exists with sessions. Overwrite? (y/N)
19
+ ```
20
+ - Binary choice: Yes (delete everything) or No (exit)
21
+ - No visibility into what exists
22
+ - Easy to accidentally delete valuable data
23
+ - No option to continue with existing project
24
+
25
+ **After v0.5.1:**
26
+ ```
27
+ 📦 Existing ADF Project Detected
28
+
29
+ Sessions: 3 session(s)
30
+ Outputs: 5 file(s)
31
+ Learning data: Present
32
+
33
+ ? What would you like to do?
34
+ ❯ Continue with Existing Project
35
+ Reset this Project (delete all data)
36
+ ← Don't change & Exit
37
+ ```
38
+
39
+ #### Improvements
40
+
41
+ **1. Visibility**
42
+ - Shows what exists (session count, output count, learning data)
43
+ - Clear summary before making any decision
44
+
45
+ **2. Better Options**
46
+ - **Continue with Existing Project**: Keep all data, start new session
47
+ - **Reset this Project**: Delete all data (with confirmation prompt)
48
+ - **Don't change & Exit**: Leave everything as-is
49
+
50
+ **3. Safety**
51
+ - "Continue" is now the default option
52
+ - "Reset" requires explicit confirmation
53
+ - Data deletion is much harder to trigger accidentally
54
+
55
+ **4. User Flow**
56
+ When choosing "Continue":
57
+ ```
58
+ ✓ Continuing with existing project...
59
+
60
+ ? What would you like to do?
61
+ ❯ Start a new session (keeps existing data)
62
+ ← Exit
63
+ ```
64
+
65
+ #### Technical Changes
66
+
67
+ **Modified Files:**
68
+ - `lib/commands/init.js`:
69
+ - Added `getExistingContent()` helper function
70
+ - Replaced binary confirm prompt with list-based menu
71
+ - Added content summary display
72
+ - Added confirmation step for destructive reset
73
+ - Added continue flow for non-destructive new sessions
74
+
75
+ **New Helper:**
76
+ ```javascript
77
+ async function getExistingContent(adfDir) {
78
+ // Returns: { sessions: count, outputs: count, learning: boolean }
79
+ }
80
+ ```
81
+
82
+ #### Benefits
83
+
84
+ - **Prevents accidental data loss**: Multi-step confirmation for deletion
85
+ - **Better transparency**: Users see what they have before deciding
86
+ - **More intuitive**: Options clearly describe outcomes
87
+ - **Preserves work**: Default is to continue, not delete
88
+ - **Professional UX**: Matches industry standards for handling existing data
89
+
90
+ ---
91
+
92
+ ## [0.5.0] - 2025-10-05
93
+
94
+ ### 🧠 Intelligent Answer Analysis & Dynamic Question Pipeline
95
+
96
+ **MAJOR FEATURE:** AI-powered answer analysis that extracts multiple pieces of information from each answer and intelligently skips redundant questions.
97
+
98
+ #### What This Means for Users
99
+
100
+ **Before v0.5.0:**
101
+ ```
102
+ Q: What are you building?
103
+ A: A React web app with PostgreSQL database for user management
104
+
105
+ Q: What tech stack will you use? ← Redundant!
106
+ A: [User has to repeat: React, PostgreSQL...]
107
+
108
+ Q: What platform? ← Also redundant!
109
+ A: [User repeats: Web...]
110
+ ```
111
+
112
+ **After v0.5.0:**
113
+ ```
114
+ Q: What are you building?
115
+ A: A React web app with PostgreSQL database for user management
116
+
117
+ 📚 Learned: TECH STACK: 90% confidence, PLATFORM: 85% confidence
118
+
119
+ ⏭️ Skipping: What tech stack will you use?
120
+ ✓ Already have: tech stack (90% confidence)
121
+
122
+ ⏭️ Skipping: What platform?
123
+ ✓ Already have: platform (85% confidence)
124
+
125
+ 📊 Time saved: ~3 minutes
126
+ ```
127
+
128
+ #### Core Components Added
129
+
130
+ **1. Answer Analyzer (`lib/analysis/answer-analyzer.js`)**
131
+ - Extracts 12 information types from each answer:
132
+ - Tech Stack, Architecture, Project Goal, Target Users
133
+ - Features, Platform, Constraints, Timeline
134
+ - Team Size, Deployment, Security, Performance
135
+ - Dual extraction: Heuristic (fast, always works) + AI (accurate, context-aware)
136
+ - Confidence scoring (0-100) for each extracted piece
137
+ - Works with or without AI client (graceful degradation)
138
+
139
+ **2. Knowledge Graph (`lib/analysis/knowledge-graph.js`)**
140
+ - Tracks all extracted information across the interview
141
+ - Maintains confidence scores and sources for each piece
142
+ - Merges similar information automatically
143
+ - Persists to disk (`_knowledge_graph.json`) for resume capability
144
+ - Provides displayable summaries with icons
145
+
146
+ **3. Question Mapper (`lib/analysis/question-mapper.js`)**
147
+ - Maps each question to the information types it gathers
148
+ - Determines which questions can be skipped based on knowledge
149
+ - Reorders questions dynamically to prioritize missing information
150
+ - Calculates time saved estimates
151
+ - Priority-based question boosting (fundamental questions first)
152
+
153
+ **4. Dynamic Pipeline (`lib/analysis/dynamic-pipeline.js`)**
154
+ - Orchestrates the entire intelligent question system
155
+ - Processes answers after each response
156
+ - Checks skip eligibility before each question
157
+ - Displays knowledge summaries periodically
158
+ - Final statistics showing questions asked/skipped and time saved
159
+
160
+ #### Integration with Interviewer
161
+
162
+ **Modified Files:**
163
+ - `lib/frameworks/interviewer.js`:
164
+ - Initialize DynamicPipeline with AI client
165
+ - Process each answer for information extraction
166
+ - Check shouldSkipQuestion() before asking
167
+ - Display knowledge summary every 2 blocks
168
+ - Show final stats at interview completion
169
+
170
+ #### User Experience Enhancements
171
+
172
+ **During Interview:**
173
+ - Real-time learning display after each answer
174
+ - Clear skip messages with reasoning and confidence
175
+ - Block summaries showing answered vs skipped questions
176
+ - Periodic knowledge summaries (every 2 blocks)
177
+
178
+ **Final Statistics:**
179
+ ```
180
+ 📊 Intelligent Question System Stats:
181
+
182
+ Questions asked: 12
183
+ Questions skipped: 8
184
+ Information pieces extracted: 24
185
+ High-confidence knowledge: 18
186
+ Estimated time saved: ~12 minutes
187
+ ```
188
+
189
+ #### Benefits
190
+
191
+ - **Reduced user pain:** No more answering the same question multiple times
192
+ - **Time savings:** 40-60% reduction in redundant questions for comprehensive answers
193
+ - **Better UX:** System learns as you type, adapts in real-time
194
+ - **Intelligent adaptation:** Questions reordered based on what's missing
195
+ - **Full transparency:** See what was learned and why questions were skipped
196
+
197
+ #### Testing
198
+
199
+ - **New Test Suites:** 4 comprehensive test files added
200
+ - `tests/answer-analyzer.test.js` (58 tests)
201
+ - `tests/knowledge-graph.test.js` (45 tests)
202
+ - `tests/question-mapper.test.js` (47 tests)
203
+ - `tests/dynamic-pipeline.test.js` (50 tests)
204
+ - **Total Tests:** 200 passing (was 120)
205
+ - **Coverage:** All new modules fully tested
206
+
207
+ #### Technical Details
208
+
209
+ **Information Extraction Patterns:**
210
+ - Heuristic: Regex patterns + keyword matching (fast)
211
+ - AI: Context-aware analysis with reasoning (accurate)
212
+ - Merged results: Highest confidence wins
213
+
214
+ **Skip Decision Logic:**
215
+ ```javascript
216
+ canSkip = ALL required info types satisfied
217
+ AND confidence >= threshold (default 75%)
218
+ ```
219
+
220
+ **Question Reordering:**
221
+ ```
222
+ Score = 100 if no knowledge exists
223
+ = 0 if all knowledge exists
224
+ = partial % if some knowledge exists
225
+
226
+ Score *= priority boost (1.3x for fundamental questions)
227
+ Sort by score descending
228
+ ```
229
+
230
+ #### Configuration Options
231
+
232
+ ```javascript
233
+ new DynamicPipeline(sessionPath, aiClient, {
234
+ enabled: true, // Enable/disable system
235
+ minSkipConfidence: 75, // Minimum confidence to skip
236
+ showAnalysis: true, // Show what was learned
237
+ verbose: false // Debug output
238
+ })
239
+ ```
240
+
241
+ #### Backward Compatibility
242
+
243
+ - ✅ Fully backward compatible
244
+ - ✅ Works with or without AI client
245
+ - ✅ Can be disabled if needed
246
+ - ✅ Graceful degradation on errors
247
+ - ✅ All existing tests still pass
248
+
249
+ ---
250
+
8
251
  ## [0.4.36] - 2025-10-04
9
252
 
10
253
  ### ✨ 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;