@iservu-inc/adf-cli 0.14.0 → 0.14.2

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,27 @@ 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.14.2] - 2026-01-12
9
+
10
+ ### šŸ› Fix - Google Gemini API Validation
11
+
12
+ **Patch Release:** Fixed a bug where valid Google API keys were sometimes reported as invalid.
13
+
14
+ #### Fixed
15
+ - šŸ”§ **Improved Validation** - Switched Google API key validation to use the official SDK's `countTokens` method instead of a manual REST API call.
16
+ - šŸ”§ **URL Encoding** - Added `encodeURIComponent` to the API key in model fetching requests to handle special characters.
17
+ - šŸ”§ **Better Error Messaging** - Clearer error descriptions when a Google key fails validation.
18
+
19
+ ## [0.14.1] - 2026-01-12
20
+
21
+ ### šŸš€ Integration - Project Context Synthesis in core CLI
22
+
23
+ **Patch Release:** Integrated the Synthesis Engine and Adaptive Augmentation flow directly into the `adf init` command.
24
+
25
+ #### Fixed/Integrated
26
+ - šŸ”§ **Core CLI Integration** - The `adf init` command now automatically detects existing BMAD, OpenSpec, and Spec-Kit frameworks and offers a "Synthesize & Augment" path.
27
+ - šŸ”§ **Dependency Fix** - Ensured all new analysis utilities are correctly required in the command entry point.
28
+
8
29
  ## [0.14.0] - 2026-01-12
9
30
 
10
31
  ### šŸš€ Major Feature - Project Context Synthesis & Adaptive Augmentation
package/README.md CHANGED
@@ -501,8 +501,18 @@ When we release updates to the framework:
501
501
 
502
502
  See [CHANGELOG.md](./CHANGELOG.md) for detailed version history.
503
503
 
504
- **Latest:** v0.12.10 (2025-12-23)
505
- - **Critical Bug Fixes (v0.12.10)** - Patch release
504
+ **Latest:** v0.14.0 (2026-01-12)
505
+ - **Project Context Synthesis & Extended Tool Support (v0.14.0)** - Minor release
506
+ - ✨ **Adaptive Project Augmentation** - Synthesizes existing .adf, BMAD, OpenSpec, and Spec-Kit project files into unified context.
507
+ - ✨ **AI-Driven Gap Analysis** - Automatically identifies knowledge gaps and generates targeted questionnaire to fill them.
508
+ - ✨ **Extended Tool Support** - Native generators for Kiro, Trae, and Codex CLI.
509
+ - ✨ **Tool Audit Registry** - New `adf tools audit` command to monitor integration features across all 12+ supported tools.
510
+
511
+ **Previous Releases:**
512
+ - **v0.13.0 (2026-01-03)** - OpenCode Multi-Agent Integration
513
+ - Complete OpenCode generator rewrite with multi-provider, multi-agent support.
514
+ - Optimal model assignment and MCP server integration.
515
+ - **v0.12.10 (2025-12-23)** - Critical Bug Fixes (v0.12.10) - Patch release
506
516
  - Fixed EISDIR deployment error for directory-based tools
507
517
  - Improved rate limit error detection for Gemini models
508
518
  - Added free tier model recommendations for Google Gemini
@@ -215,20 +215,19 @@ async function validateAPIKeyWithProvider(provider, apiKey) {
215
215
  break;
216
216
 
217
217
  case 'google':
218
- const fetchGoogle = require('node-fetch');
219
- // Validate by fetching models list (validates key and shows available models)
220
- const googleResponse = await fetchGoogle(
221
- `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`
222
- );
223
-
224
- if (!googleResponse.ok) {
225
- const errorText = await googleResponse.text();
226
- throw new Error(`HTTP ${googleResponse.status}: ${errorText || googleResponse.statusText}`);
227
- }
228
-
229
- const googleData = await googleResponse.json();
230
- if (!googleData.models || !Array.isArray(googleData.models) || googleData.models.length === 0) {
231
- throw new Error('No models available for this API key');
218
+ try {
219
+ const { GoogleGenerativeAI } = require('@google/generative-ai');
220
+ const genAI = new GoogleGenerativeAI(apiKey);
221
+ // Use gemini-1.5-flash as it's the most available model for validation
222
+ const model = genAI.getGenerativeModel({ model: 'gemini-1.5-flash' });
223
+ // countTokens is a metadata call that validates the API key without incurring costs
224
+ await model.countTokens("connectivity test");
225
+ } catch (error) {
226
+ // If SDK fails, provide a clearer error message
227
+ if (error.message.includes('API_KEY_INVALID') || error.message.includes('API key not found')) {
228
+ throw new Error('Invalid Google API key. Please check your key at https://aistudio.google.com/app/apikey');
229
+ }
230
+ throw error;
232
231
  }
233
232
  break;
234
233
 
@@ -332,7 +331,7 @@ async function fetchAvailableModels(provider, apiKey) {
332
331
 
333
332
  // Use Google's REST API to list available models
334
333
  const response = await fetch(
335
- `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`
334
+ `https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(apiKey)}`
336
335
  );
337
336
 
338
337
  if (!response.ok) {
@@ -7,6 +7,12 @@ const {
7
7
  detectProjectType,
8
8
  getWorkflowRecommendation
9
9
  } = require('../utils/project-detector');
10
+ const FrameworkDetector = require('../utils/framework-detector');
11
+ const ContextExtractor = require('../utils/context-extractor');
12
+ const SynthesisEngine = require('../analysis/synthesis-engine');
13
+ const HeuristicGapAnalyzer = require('../analysis/heuristic-gap-analyzer');
14
+ const AIGapAnalyzer = require('../analysis/ai-gap-analyzer');
15
+ const DynamicQuestionGenerator = require('../analysis/dynamic-question-generator');
10
16
  const Interviewer = require('../frameworks/interviewer');
11
17
  const SessionManager = require('../frameworks/session-manager');
12
18
  const { deployToTool } = require('./deploy');
@@ -24,6 +30,94 @@ async function init(options) {
24
30
  loadEnvIntoProcess(envPath);
25
31
  }
26
32
 
33
+ // Detect existing frameworks for potential synthesis
34
+ const detectedFrameworks = await FrameworkDetector.detect(cwd);
35
+ const hasOtherFrameworks = detectedFrameworks.filter(f => f !== 'adf').length > 0;
36
+
37
+ if (hasOtherFrameworks) {
38
+ console.log(chalk.cyan('šŸ“¦ Existing Development Frameworks Detected:'));
39
+ console.log(chalk.gray(` ${detectedFrameworks.join(', ')}\n`));
40
+
41
+ const { action } = await inquirer.prompt([
42
+ {
43
+ type: 'list',
44
+ name: 'action',
45
+ message: 'How would you like to proceed?',
46
+ choices: [
47
+ {
48
+ name: 'Synthesize & Augment (Seamless Merge - Recommended)',
49
+ value: 'synthesize'
50
+ },
51
+ {
52
+ name: 'Start Fresh (Ignore existing frameworks)',
53
+ value: 'fresh'
54
+ },
55
+ new inquirer.Separator(),
56
+ {
57
+ name: chalk.gray('← Exit'),
58
+ value: 'exit'
59
+ }
60
+ ]
61
+ }
62
+ ]);
63
+
64
+ if (action === 'exit') return;
65
+
66
+ if (action === 'synthesize') {
67
+ const spinner = ora('Synthesizing project context...').start();
68
+ try {
69
+ const context = await ContextExtractor.extract(cwd, detectedFrameworks);
70
+ const sessionPath = await SynthesisEngine.createAugmentedSession(cwd, context, 'balanced');
71
+ spinner.succeed(chalk.green(`āœ“ Project synthesized into new session: ${path.basename(sessionPath)}`));
72
+
73
+ console.log(chalk.yellow('\nšŸ’” Starting Adaptive Augmentation Interview to fill knowledge gaps...\n'));
74
+
75
+ // Load AI config for the interviewer
76
+ const aiConfig = await configureAIProvider(cwd);
77
+ const sessionProgress = await fs.readJson(path.join(sessionPath, '_progress.json'));
78
+
79
+ // Perform Knowledge Gap Analysis
80
+ console.log(chalk.cyan('šŸ” Analyzing for knowledge gaps...'));
81
+ const hGaps = HeuristicGapAnalyzer.analyze(context, 'balanced');
82
+
83
+ let aiGaps = [];
84
+ if (aiConfig) {
85
+ const AIClient = require('../ai/ai-client');
86
+ const aiClient = new AIClient(aiConfig);
87
+ const aiAnalyzer = new AIGapAnalyzer(aiClient);
88
+ aiGaps = await aiAnalyzer.analyze(context);
89
+ }
90
+
91
+ const dynamicQuestions = DynamicQuestionGenerator.generate(hGaps, aiGaps);
92
+
93
+ if (dynamicQuestions.length === 0) {
94
+ console.log(chalk.green('āœ“ Context is comprehensive. No additional questions needed.'));
95
+ const interviewer = new Interviewer('balanced', cwd, {
96
+ sessionId: path.basename(sessionPath),
97
+ sessionPath,
98
+ progress: sessionProgress
99
+ }, aiConfig);
100
+ await interviewer.generateOutputs();
101
+ return;
102
+ }
103
+
104
+ console.log(chalk.yellow(`\nšŸ’” Identified ${dynamicQuestions.length} gaps. Starting targeted interview...\n`));
105
+
106
+ const interviewer = new Interviewer('balanced', cwd, {
107
+ sessionId: path.basename(sessionPath),
108
+ sessionPath,
109
+ progress: sessionProgress
110
+ }, aiConfig, dynamicQuestions);
111
+
112
+ await interviewer.start();
113
+ return;
114
+ } catch (error) {
115
+ spinner.fail(chalk.red(`Synthesis failed: ${error.message}`));
116
+ console.log(chalk.yellow('Falling back to standard initialization...\n'));
117
+ }
118
+ }
119
+ }
120
+
27
121
  // Check for resumable sessions FIRST (before asking to overwrite)
28
122
  const sessionManager = new SessionManager(cwd);
29
123
  const existingSession = await sessionManager.promptToResume();
@@ -21,10 +21,11 @@ const DynamicPipeline = require('../analysis/dynamic-pipeline');
21
21
  */
22
22
 
23
23
  class Interviewer {
24
- constructor(framework, projectPath, existingSession = null, aiConfig = null) {
24
+ constructor(framework, projectPath, existingSession = null, aiConfig = null, customQuestions = null) {
25
25
  this.framework = framework;
26
26
  this.projectPath = projectPath;
27
27
  this.aiConfig = aiConfig; // Store AI configuration
28
+ this.customQuestions = customQuestions; // Dynamic questions for augmentation
28
29
 
29
30
  if (existingSession) {
30
31
  // Resuming existing session
@@ -293,8 +294,8 @@ class Interviewer {
293
294
  projectContext = { type: 'unknown', frameworks: [], languages: [], confidence: 0 };
294
295
  }
295
296
 
296
- // Get questions for framework
297
- let questions = getQuestionsForFramework(this.framework);
297
+ // Get questions for framework (or use custom ones if provided)
298
+ let questions = this.customQuestions || getQuestionsForFramework(this.framework);
298
299
 
299
300
  // Apply smart filtering if enabled
300
301
  let filteringResult = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iservu-inc/adf-cli",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
4
4
  "description": "CLI tool for AgentDevFramework - AI-assisted development framework with multi-provider AI support",
5
5
  "main": "index.js",
6
6
  "bin": {