@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,260 @@
1
+ const { v4: uuidv4 } = require('uuid');
2
+ const storage = require('./storage');
3
+
4
+ /**
5
+ * Skip Tracker - Records user skip and answer behavior
6
+ *
7
+ * Tracks:
8
+ * - Questions skipped manually
9
+ * - Questions skipped by filtering
10
+ * - Answer metadata (length, quality scores)
11
+ * - Time spent on questions
12
+ */
13
+
14
+ class SkipTracker {
15
+ constructor(projectPath, sessionMetadata = {}) {
16
+ this.projectPath = projectPath;
17
+ this.sessionId = uuidv4();
18
+ this.sessionMetadata = sessionMetadata;
19
+ this.sessionData = {
20
+ sessionId: this.sessionId,
21
+ timestamp: new Date().toISOString(),
22
+ projectType: sessionMetadata.projectType || 'unknown',
23
+ frameworks: sessionMetadata.frameworks || [],
24
+ languages: sessionMetadata.languages || [],
25
+ skips: [],
26
+ answers: []
27
+ };
28
+ this.questionStartTimes = {};
29
+ }
30
+
31
+ /**
32
+ * Record when a question is shown to the user
33
+ * @param {string} questionId - Question identifier
34
+ */
35
+ startQuestion(questionId) {
36
+ this.questionStartTimes[questionId] = Date.now();
37
+ }
38
+
39
+ /**
40
+ * Get time spent on a question in seconds
41
+ * @param {string} questionId - Question identifier
42
+ * @returns {number} Time in seconds
43
+ */
44
+ getTimeSpent(questionId) {
45
+ if (!this.questionStartTimes[questionId]) {
46
+ return 0;
47
+ }
48
+ const elapsed = Date.now() - this.questionStartTimes[questionId];
49
+ return Math.round(elapsed / 100) / 10; // Round to 1 decimal
50
+ }
51
+
52
+ /**
53
+ * Record a skip event
54
+ * @param {Object} question - Question object
55
+ * @param {string} reason - 'manual' | 'filtered'
56
+ * @param {Object} metadata - Additional metadata
57
+ */
58
+ recordSkip(question, reason = 'manual', metadata = {}) {
59
+ const skipEvent = {
60
+ questionId: question.id,
61
+ text: question.text,
62
+ category: question.category || null,
63
+ phase: question.phase || null,
64
+ action: 'skipped',
65
+ reason,
66
+ timeViewed: this.getTimeSpent(question.id),
67
+ relevanceScore: question.relevance || null,
68
+ skipReason: question.skipReason || null,
69
+ ...metadata
70
+ };
71
+
72
+ this.sessionData.skips.push(skipEvent);
73
+ }
74
+
75
+ /**
76
+ * Record an answer event
77
+ * @param {Object} question - Question object
78
+ * @param {string} answer - User's answer
79
+ * @param {Object} metadata - Additional metadata (quality scores, etc.)
80
+ */
81
+ recordAnswer(question, answer, metadata = {}) {
82
+ const answerEvent = {
83
+ questionId: question.id,
84
+ text: question.text,
85
+ category: question.category || null,
86
+ phase: question.phase || null,
87
+ action: 'answered',
88
+ answerLength: answer.length,
89
+ wordCount: answer.split(/\s+/).filter(w => w.length > 0).length,
90
+ timeSpent: this.getTimeSpent(question.id),
91
+ qualityScore: metadata.qualityScore || null,
92
+ richness: metadata.richness || null,
93
+ relevanceScore: question.relevance || null,
94
+ ...metadata
95
+ };
96
+
97
+ this.sessionData.answers.push(answerEvent);
98
+ }
99
+
100
+ /**
101
+ * Record multiple filtered questions (bulk operation)
102
+ * @param {Array} filteredQuestions - Array of filtered question objects
103
+ */
104
+ recordFilteredQuestions(filteredQuestions) {
105
+ for (const question of filteredQuestions) {
106
+ this.recordSkip(question, 'filtered', {
107
+ filterReason: question.reason || 'Low relevance score'
108
+ });
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Get session summary statistics
114
+ * @returns {Object} Session summary
115
+ */
116
+ getSessionSummary() {
117
+ return {
118
+ sessionId: this.sessionId,
119
+ timestamp: this.sessionData.timestamp,
120
+ projectType: this.sessionData.projectType,
121
+ frameworks: this.sessionData.frameworks,
122
+ totalSkips: this.sessionData.skips.length,
123
+ manualSkips: this.sessionData.skips.filter(s => s.reason === 'manual').length,
124
+ filteredSkips: this.sessionData.skips.filter(s => s.reason === 'filtered').length,
125
+ totalAnswers: this.sessionData.answers.length,
126
+ avgAnswerLength: this.sessionData.answers.length > 0
127
+ ? Math.round(this.sessionData.answers.reduce((sum, a) => sum + a.wordCount, 0) / this.sessionData.answers.length)
128
+ : 0
129
+ };
130
+ }
131
+
132
+ /**
133
+ * Save session data to storage
134
+ */
135
+ async saveSession() {
136
+ try {
137
+ // Save skip history
138
+ await storage.appendToLearningHistory(
139
+ this.projectPath,
140
+ 'skip-history.json',
141
+ this.sessionData,
142
+ 'sessions'
143
+ );
144
+
145
+ // Save answer history
146
+ const answerSessionData = {
147
+ sessionId: this.sessionId,
148
+ timestamp: this.sessionData.timestamp,
149
+ projectType: this.sessionData.projectType,
150
+ frameworks: this.sessionData.frameworks,
151
+ answers: this.sessionData.answers
152
+ };
153
+
154
+ await storage.appendToLearningHistory(
155
+ this.projectPath,
156
+ 'answer-history.json',
157
+ answerSessionData,
158
+ 'sessions'
159
+ );
160
+
161
+ // Update statistics
162
+ await storage.updateLearningStats(this.projectPath, {
163
+ totalSessions: (await storage.getLearningStats(this.projectPath)).totalSessions + 1,
164
+ totalSkips: (await storage.getLearningStats(this.projectPath)).totalSkips + this.sessionData.skips.length,
165
+ totalAnswers: (await storage.getLearningStats(this.projectPath)).totalAnswers + this.sessionData.answers.length
166
+ });
167
+
168
+ return true;
169
+ } catch (error) {
170
+ console.error('Error saving skip tracker session:', error.message);
171
+ return false;
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Get current session data (for debugging/testing)
177
+ * @returns {Object} Current session data
178
+ */
179
+ getSessionData() {
180
+ return this.sessionData;
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Helper function to analyze skip patterns from history
186
+ * @param {string} projectPath - Project root path
187
+ * @returns {Promise<Object>} Skip pattern analysis
188
+ */
189
+ async function analyzeSkipPatterns(projectPath) {
190
+ const skipHistory = await storage.getSkipHistory(projectPath);
191
+
192
+ if (!skipHistory || !skipHistory.sessions || skipHistory.sessions.length === 0) {
193
+ return {
194
+ totalSessions: 0,
195
+ totalSkips: 0,
196
+ manualSkips: 0,
197
+ filteredSkips: 0,
198
+ mostSkippedQuestions: [],
199
+ mostSkippedCategories: []
200
+ };
201
+ }
202
+
203
+ // Count skips by question
204
+ const questionSkipCounts = {};
205
+ const categorySkipCounts = {};
206
+ let totalManualSkips = 0;
207
+ let totalFilteredSkips = 0;
208
+
209
+ for (const session of skipHistory.sessions) {
210
+ for (const skip of session.skips || []) {
211
+ // Count by question
212
+ if (!questionSkipCounts[skip.questionId]) {
213
+ questionSkipCounts[skip.questionId] = {
214
+ questionId: skip.questionId,
215
+ text: skip.text,
216
+ count: 0,
217
+ category: skip.category
218
+ };
219
+ }
220
+ questionSkipCounts[skip.questionId].count++;
221
+
222
+ // Count by category
223
+ if (skip.category) {
224
+ categorySkipCounts[skip.category] = (categorySkipCounts[skip.category] || 0) + 1;
225
+ }
226
+
227
+ // Count by reason
228
+ if (skip.reason === 'manual') {
229
+ totalManualSkips++;
230
+ } else if (skip.reason === 'filtered') {
231
+ totalFilteredSkips++;
232
+ }
233
+ }
234
+ }
235
+
236
+ // Sort and get top questions
237
+ const mostSkippedQuestions = Object.values(questionSkipCounts)
238
+ .sort((a, b) => b.count - a.count)
239
+ .slice(0, 10);
240
+
241
+ // Sort and get top categories
242
+ const mostSkippedCategories = Object.entries(categorySkipCounts)
243
+ .map(([category, count]) => ({ category, count }))
244
+ .sort((a, b) => b.count - a.count)
245
+ .slice(0, 5);
246
+
247
+ return {
248
+ totalSessions: skipHistory.sessions.length,
249
+ totalSkips: totalManualSkips + totalFilteredSkips,
250
+ manualSkips: totalManualSkips,
251
+ filteredSkips: totalFilteredSkips,
252
+ mostSkippedQuestions,
253
+ mostSkippedCategories
254
+ };
255
+ }
256
+
257
+ module.exports = {
258
+ SkipTracker,
259
+ analyzeSkipPatterns
260
+ };
@@ -0,0 +1,296 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ /**
5
+ * Learning Storage - Manages learning data persistence
6
+ *
7
+ * Handles all file I/O for the learning system with:
8
+ * - Atomic writes (write to temp, then rename)
9
+ * - Directory creation
10
+ * - Data validation
11
+ * - Error handling
12
+ */
13
+
14
+ /**
15
+ * Get the learning directory path
16
+ * @param {string} projectPath - Project root path
17
+ * @returns {string} Learning directory path
18
+ */
19
+ function getLearningPath(projectPath) {
20
+ return path.join(projectPath, '.adf', 'learning');
21
+ }
22
+
23
+ /**
24
+ * Ensure learning directory exists
25
+ * @param {string} projectPath - Project root path
26
+ */
27
+ async function ensureLearningDirectory(projectPath) {
28
+ const learningPath = getLearningPath(projectPath);
29
+ await fs.ensureDir(learningPath);
30
+ }
31
+
32
+ /**
33
+ * Read learning data file
34
+ * @param {string} projectPath - Project root path
35
+ * @param {string} filename - File name (e.g., 'skip-history.json')
36
+ * @returns {Promise<Object|null>} Data object or null if doesn't exist
37
+ */
38
+ async function readLearningData(projectPath, filename) {
39
+ try {
40
+ const learningPath = getLearningPath(projectPath);
41
+ const filePath = path.join(learningPath, filename);
42
+
43
+ if (!await fs.pathExists(filePath)) {
44
+ return null;
45
+ }
46
+
47
+ const data = await fs.readJSON(filePath);
48
+ return data;
49
+ } catch (error) {
50
+ console.warn(`Warning: Could not read ${filename}: ${error.message}`);
51
+ return null;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Write learning data file atomically
57
+ * @param {string} projectPath - Project root path
58
+ * @param {string} filename - File name
59
+ * @param {Object} data - Data to write
60
+ */
61
+ async function writeLearningData(projectPath, filename, data) {
62
+ try {
63
+ await ensureLearningDirectory(projectPath);
64
+
65
+ const learningPath = getLearningPath(projectPath);
66
+ const filePath = path.join(learningPath, filename);
67
+ const tempPath = filePath + '.tmp';
68
+
69
+ // Write to temp file first (atomic operation)
70
+ await fs.writeJSON(tempPath, data, { spaces: 2 });
71
+
72
+ // Rename temp to actual file (atomic on most filesystems)
73
+ await fs.rename(tempPath, filePath);
74
+ } catch (error) {
75
+ console.error(`Error writing ${filename}: ${error.message}`);
76
+ throw error;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Append to learning history file
82
+ * @param {string} projectPath - Project root path
83
+ * @param {string} filename - File name
84
+ * @param {Object} newEntry - New entry to append
85
+ * @param {string} arrayKey - Key for the array to append to (e.g., 'sessions')
86
+ */
87
+ async function appendToLearningHistory(projectPath, filename, newEntry, arrayKey = 'sessions') {
88
+ try {
89
+ // Read existing data
90
+ let data = await readLearningData(projectPath, filename);
91
+
92
+ if (!data) {
93
+ // Initialize if doesn't exist
94
+ data = {
95
+ version: '1.0',
96
+ [arrayKey]: []
97
+ };
98
+ }
99
+
100
+ // Append new entry
101
+ if (!data[arrayKey]) {
102
+ data[arrayKey] = [];
103
+ }
104
+ data[arrayKey].push(newEntry);
105
+
106
+ // Write back
107
+ await writeLearningData(projectPath, filename, data);
108
+ } catch (error) {
109
+ console.error(`Error appending to ${filename}: ${error.message}`);
110
+ throw error;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Get skip history
116
+ * @param {string} projectPath - Project root path
117
+ * @returns {Promise<Object>} Skip history data
118
+ */
119
+ async function getSkipHistory(projectPath) {
120
+ const data = await readLearningData(projectPath, 'skip-history.json');
121
+ return data || { version: '1.0', sessions: [] };
122
+ }
123
+
124
+ /**
125
+ * Get answer history
126
+ * @param {string} projectPath - Project root path
127
+ * @returns {Promise<Object>} Answer history data
128
+ */
129
+ async function getAnswerHistory(projectPath) {
130
+ const data = await readLearningData(projectPath, 'answer-history.json');
131
+ return data || { version: '1.0', sessions: [] };
132
+ }
133
+
134
+ /**
135
+ * Get detected patterns
136
+ * @param {string} projectPath - Project root path
137
+ * @returns {Promise<Object>} Patterns data
138
+ */
139
+ async function getPatterns(projectPath) {
140
+ const data = await readLearningData(projectPath, 'patterns.json');
141
+ return data || { version: '1.0', lastUpdated: null, patterns: [] };
142
+ }
143
+
144
+ /**
145
+ * Save patterns
146
+ * @param {string} projectPath - Project root path
147
+ * @param {Object} patterns - Patterns data
148
+ */
149
+ async function savePatterns(projectPath, patterns) {
150
+ patterns.lastUpdated = new Date().toISOString();
151
+ await writeLearningData(projectPath, 'patterns.json', patterns);
152
+ }
153
+
154
+ /**
155
+ * Get learned rules
156
+ * @param {string} projectPath - Project root path
157
+ * @returns {Promise<Object>} Learned rules data
158
+ */
159
+ async function getLearnedRules(projectPath) {
160
+ const data = await readLearningData(projectPath, 'learned-rules.json');
161
+ return data || { version: '1.0', rules: [] };
162
+ }
163
+
164
+ /**
165
+ * Save learned rules
166
+ * @param {string} projectPath - Project root path
167
+ * @param {Object} rules - Rules data
168
+ */
169
+ async function saveLearnedRules(projectPath, rules) {
170
+ await writeLearningData(projectPath, 'learned-rules.json', rules);
171
+ }
172
+
173
+ /**
174
+ * Get learning configuration
175
+ * @param {string} projectPath - Project root path
176
+ * @returns {Promise<Object>} Config data
177
+ */
178
+ async function getLearningConfig(projectPath) {
179
+ const data = await readLearningData(projectPath, 'config.json');
180
+ return data || {
181
+ version: '1.0',
182
+ enabled: true,
183
+ trackSkips: true,
184
+ trackAnswers: true,
185
+ detectPatterns: true,
186
+ applyLearnedFilters: true,
187
+ shareAnonymousPatterns: false,
188
+ minSessionsForPattern: 3,
189
+ minConfidenceForAutoFilter: 75
190
+ };
191
+ }
192
+
193
+ /**
194
+ * Save learning configuration
195
+ * @param {string} projectPath - Project root path
196
+ * @param {Object} config - Config data
197
+ */
198
+ async function saveLearningConfig(projectPath, config) {
199
+ await writeLearningData(projectPath, 'config.json', config);
200
+ }
201
+
202
+ /**
203
+ * Get learning statistics
204
+ * @param {string} projectPath - Project root path
205
+ * @returns {Promise<Object>} Statistics data
206
+ */
207
+ async function getLearningStats(projectPath) {
208
+ const data = await readLearningData(projectPath, 'stats.json');
209
+ return data || {
210
+ version: '1.0',
211
+ totalSessions: 0,
212
+ totalSkips: 0,
213
+ totalAnswers: 0,
214
+ patternsDetected: 0,
215
+ rulesApplied: 0,
216
+ lastUpdated: null
217
+ };
218
+ }
219
+
220
+ /**
221
+ * Update learning statistics
222
+ * @param {string} projectPath - Project root path
223
+ * @param {Object} updates - Statistics updates
224
+ */
225
+ async function updateLearningStats(projectPath, updates) {
226
+ const stats = await getLearningStats(projectPath);
227
+
228
+ Object.assign(stats, updates);
229
+ stats.lastUpdated = new Date().toISOString();
230
+
231
+ await writeLearningData(projectPath, 'stats.json', stats);
232
+ }
233
+
234
+ /**
235
+ * Clear all learning data
236
+ * @param {string} projectPath - Project root path
237
+ */
238
+ async function clearLearningData(projectPath) {
239
+ const learningPath = getLearningPath(projectPath);
240
+
241
+ if (await fs.pathExists(learningPath)) {
242
+ // Remove all JSON files but keep directory
243
+ const files = await fs.readdir(learningPath);
244
+ for (const file of files) {
245
+ if (file.endsWith('.json')) {
246
+ await fs.remove(path.join(learningPath, file));
247
+ }
248
+ }
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Get learning data size in bytes
254
+ * @param {string} projectPath - Project root path
255
+ * @returns {Promise<number>} Total size in bytes
256
+ */
257
+ async function getLearningDataSize(projectPath) {
258
+ const learningPath = getLearningPath(projectPath);
259
+
260
+ if (!await fs.pathExists(learningPath)) {
261
+ return 0;
262
+ }
263
+
264
+ let totalSize = 0;
265
+ const files = await fs.readdir(learningPath);
266
+
267
+ for (const file of files) {
268
+ if (file.endsWith('.json')) {
269
+ const filePath = path.join(learningPath, file);
270
+ const stats = await fs.stat(filePath);
271
+ totalSize += stats.size;
272
+ }
273
+ }
274
+
275
+ return totalSize;
276
+ }
277
+
278
+ module.exports = {
279
+ getLearningPath,
280
+ ensureLearningDirectory,
281
+ readLearningData,
282
+ writeLearningData,
283
+ appendToLearningHistory,
284
+ getSkipHistory,
285
+ getAnswerHistory,
286
+ getPatterns,
287
+ savePatterns,
288
+ getLearnedRules,
289
+ saveLearnedRules,
290
+ getLearningConfig,
291
+ saveLearningConfig,
292
+ getLearningStats,
293
+ updateLearningStats,
294
+ clearLearningData,
295
+ getLearningDataSize
296
+ };
package/package.json CHANGED
@@ -1,57 +1,70 @@
1
- {
2
- "name": "@iservu-inc/adf-cli",
3
- "version": "0.3.0",
4
- "description": "CLI tool for AgentDevFramework - AI-assisted development framework",
5
- "main": "index.js",
6
- "bin": {
7
- "adf": "bin/adf.js"
8
- },
9
- "scripts": {
10
- "test": "jest --coverage",
11
- "test:watch": "jest --watch"
12
- },
13
- "keywords": [
14
- "cli",
15
- "framework",
16
- "ai",
17
- "development",
18
- "agent",
19
- "bmad",
20
- "spec-kit",
21
- "context-engineering",
22
- "prp",
23
- "agentic",
24
- "tdd",
25
- "windsurf",
26
- "cursor",
27
- "claude-code"
28
- ],
29
- "author": "iServU",
30
- "license": "MIT",
31
- "dependencies": {
32
- "chalk": "^4.1.2",
33
- "commander": "^11.1.0",
34
- "fs-extra": "^11.2.0",
35
- "inquirer": "^8.2.5",
36
- "ora": "^5.4.1"
37
- },
38
- "engines": {
39
- "node": ">=18.0.0",
40
- "npm": ">=9.0.0"
41
- },
42
- "repository": {
43
- "type": "git",
44
- "url": "git+https://github.com/iservu/adf-cli.git"
45
- },
46
- "bugs": {
47
- "url": "https://github.com/iservu/adf-cli/issues"
48
- },
49
- "homepage": "https://github.com/iservu/adf-cli#readme",
50
- "publishConfig": {
51
- "access": "public"
52
- },
53
- "devDependencies": {
54
- "@types/node": "^24.6.2",
55
- "jest": "^30.2.0"
56
- }
57
- }
1
+ {
2
+ "name": "@iservu-inc/adf-cli",
3
+ "version": "0.4.12",
4
+ "description": "CLI tool for AgentDevFramework - AI-assisted development framework with multi-provider AI support",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "adf": "bin/adf.js"
8
+ },
9
+ "scripts": {
10
+ "test": "jest --coverage",
11
+ "test:watch": "jest --watch"
12
+ },
13
+ "keywords": [
14
+ "cli",
15
+ "framework",
16
+ "ai",
17
+ "development",
18
+ "agent",
19
+ "bmad",
20
+ "spec-kit",
21
+ "context-engineering",
22
+ "prp",
23
+ "agentic",
24
+ "tdd",
25
+ "windsurf",
26
+ "cursor",
27
+ "claude-code",
28
+ "anthropic",
29
+ "openai",
30
+ "gemini",
31
+ "openrouter",
32
+ "llm",
33
+ "requirements-gathering"
34
+ ],
35
+ "author": "iServU",
36
+ "license": "MIT",
37
+ "dependencies": {
38
+ "@anthropic-ai/sdk": "^0.32.0",
39
+ "@google/generative-ai": "^0.21.0",
40
+ "chalk": "^4.1.2",
41
+ "commander": "^11.1.0",
42
+ "dotenv": "^17.2.3",
43
+ "fs-extra": "^11.2.0",
44
+ "inquirer": "^8.2.5",
45
+ "inquirer-autocomplete-prompt": "^2.0.1",
46
+ "node-fetch": "^2.7.0",
47
+ "openai": "^4.73.0",
48
+ "ora": "^5.4.1",
49
+ "uuid": "^9.0.1"
50
+ },
51
+ "engines": {
52
+ "node": ">=18.0.0",
53
+ "npm": ">=9.0.0"
54
+ },
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/iservu/adf-cli.git"
58
+ },
59
+ "bugs": {
60
+ "url": "https://github.com/iservu/adf-cli/issues"
61
+ },
62
+ "homepage": "https://github.com/iservu/adf-cli#readme",
63
+ "publishConfig": {
64
+ "access": "public"
65
+ },
66
+ "devDependencies": {
67
+ "@types/node": "^24.6.2",
68
+ "jest": "^30.2.0"
69
+ }
70
+ }