@iservu-inc/adf-cli 0.14.2 → 0.14.3
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/README.md +13 -13
- package/bin/adf.js +43 -26
- package/conductor/product-guidelines.md +1 -1
- package/conductor/product.md +2 -3
- package/conductor/tracks/bootstrap_agents_20260111/plan.md +5 -0
- package/lib/ai/ai-client.js +80 -35
- package/lib/ai/ai-config.js +199 -107
- package/lib/commands/config.js +15 -5
- package/lib/commands/deploy.js +5 -2
- package/lib/commands/init.js +14 -4
- package/lib/frameworks/interviewer.js +3 -3
- package/lib/frameworks/output-generators.js +7 -7
- package/lib/frameworks/questions.js +3 -3
- package/lib/generators/agents-md-generator.js +3 -3
- package/lib/generators/antigravity-generator.js +3 -3
- package/lib/generators/cursor-generator.js +3 -3
- package/lib/generators/deepagent-generator.js +5 -5
- package/lib/generators/gemini-cli-generator.js +5 -5
- package/lib/generators/index.js +15 -0
- package/lib/generators/vscode-generator.js +3 -3
- package/lib/generators/windsurf-generator.js +3 -3
- package/lib/templates/scripts/analyze-docs.js +14 -13
- package/lib/templates/scripts/config-helpers.js +1 -1
- package/lib/templates/shared/agents/analyst.md +1 -1
- package/lib/templates/shared/agents/architect.md +1 -1
- package/lib/templates/shared/agents/dev.md +1 -1
- package/lib/templates/shared/agents/pm.md +2 -2
- package/lib/templates/shared/agents/qa.md +1 -1
- package/lib/templates/shared/agents/sm.md +3 -3
- package/lib/templates/shared/memory/constitution.md +2 -2
- package/lib/templates/shared/templates/README.md +14 -14
- package/lib/templates/shared/templates/prd-template.md +1 -1
- package/lib/templates/shared/templates/spec-template.md +1 -1
- package/lib/utils/context-manager.js +11 -10
- package/lib/utils/framework-detector.js +5 -5
- package/lib/utils/project-detector.js +7 -7
- package/package.json +5 -5
package/lib/ai/ai-config.js
CHANGED
|
@@ -4,6 +4,7 @@ const chalk = require('chalk');
|
|
|
4
4
|
const fs = require('fs-extra');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const os = require('os');
|
|
7
|
+
const ora = require('ora');
|
|
7
8
|
|
|
8
9
|
// Register autocomplete prompt
|
|
9
10
|
inquirer.registerPrompt('autocomplete', autocomplete);
|
|
@@ -43,18 +44,17 @@ const AI_PROVIDERS = {
|
|
|
43
44
|
website: 'https://ai.google.dev/',
|
|
44
45
|
setup: 'Get your API key from https://aistudio.google.com/app/apikey',
|
|
45
46
|
defaultModels: [
|
|
46
|
-
// Gemini
|
|
47
|
-
'gemini-
|
|
48
|
-
'gemini-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
'gemini-
|
|
52
|
-
'gemini-
|
|
53
|
-
'gemini-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
'gemini-pro'
|
|
57
|
-
'gemini-pro-vision'
|
|
47
|
+
// Gemini 3.0 Series (Latest)
|
|
48
|
+
'gemini-3.0-pro',
|
|
49
|
+
'gemini-3.0-flash',
|
|
50
|
+
'gemini-3.0-deep-think',
|
|
51
|
+
// Gemini 2.5 Series (Stable)
|
|
52
|
+
'gemini-2.5-pro',
|
|
53
|
+
'gemini-2.5-flash',
|
|
54
|
+
'gemini-2.5-flash-lite',
|
|
55
|
+
// Gemini 2.0 Series (Sunsetting)
|
|
56
|
+
'gemini-2.0-flash',
|
|
57
|
+
'gemini-2.0-pro'
|
|
58
58
|
]
|
|
59
59
|
},
|
|
60
60
|
OPENROUTER: {
|
|
@@ -70,6 +70,20 @@ const AI_PROVIDERS = {
|
|
|
70
70
|
'google/gemini-pro-1.5',
|
|
71
71
|
'meta-llama/llama-3.1-70b-instruct'
|
|
72
72
|
]
|
|
73
|
+
},
|
|
74
|
+
PERPLEXITY: {
|
|
75
|
+
id: 'perplexity',
|
|
76
|
+
name: 'Perplexity AI (Search + Reasoning)',
|
|
77
|
+
envVar: 'PERPLEXITY_API_KEY',
|
|
78
|
+
requiredFormat: 'pplx-',
|
|
79
|
+
website: 'https://www.perplexity.ai/api',
|
|
80
|
+
setup: 'Get your API key from https://www.perplexity.ai/settings/api',
|
|
81
|
+
defaultModels: [
|
|
82
|
+
'sonar-pro',
|
|
83
|
+
'sonar-reasoning-pro',
|
|
84
|
+
'sonar',
|
|
85
|
+
'sonar-deep-research'
|
|
86
|
+
]
|
|
73
87
|
}
|
|
74
88
|
};
|
|
75
89
|
|
|
@@ -194,7 +208,7 @@ function loadEnvIntoProcess(envPath) {
|
|
|
194
208
|
/**
|
|
195
209
|
* Validate API key with provider by making a simple API call
|
|
196
210
|
*/
|
|
197
|
-
async function validateAPIKeyWithProvider(provider, apiKey) {
|
|
211
|
+
async function validateAPIKeyWithProvider(provider, apiKey, model = null) {
|
|
198
212
|
switch (provider.id) {
|
|
199
213
|
case 'anthropic':
|
|
200
214
|
const Anthropic = require('@anthropic-ai/sdk');
|
|
@@ -216,15 +230,28 @@ async function validateAPIKeyWithProvider(provider, apiKey) {
|
|
|
216
230
|
|
|
217
231
|
case 'google':
|
|
218
232
|
try {
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
//
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
233
|
+
const fetch = require('node-fetch');
|
|
234
|
+
// Use query param instead of header to rule out header-stripping issues
|
|
235
|
+
// Using v1beta endpoint as verified by user testing
|
|
236
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`;
|
|
237
|
+
|
|
238
|
+
// List models is the most reliable way to validate an API key without assuming model availability
|
|
239
|
+
const response = await fetch(
|
|
240
|
+
url,
|
|
241
|
+
{
|
|
242
|
+
headers: {
|
|
243
|
+
'Content-Type': 'application/json'
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
if (!response.ok) {
|
|
249
|
+
const errorText = await response.text();
|
|
250
|
+
throw new Error(`HTTP ${response.status}: ${errorText || response.statusText}`);
|
|
251
|
+
}
|
|
225
252
|
} catch (error) {
|
|
226
|
-
// If
|
|
227
|
-
if (error.message.includes('API_KEY_INVALID') || error.message.includes('API key not found')) {
|
|
253
|
+
// If API call fails, provide a clearer error message
|
|
254
|
+
if (error.message.includes('400') || error.message.includes('API_KEY_INVALID') || error.message.includes('API key not found')) {
|
|
228
255
|
throw new Error('Invalid Google API key. Please check your key at https://aistudio.google.com/app/apikey');
|
|
229
256
|
}
|
|
230
257
|
throw error;
|
|
@@ -264,74 +291,81 @@ async function fetchAvailableModels(provider, apiKey) {
|
|
|
264
291
|
try {
|
|
265
292
|
const Anthropic = require('@anthropic-ai/sdk');
|
|
266
293
|
const anthropic = new Anthropic({ apiKey });
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
294
|
+
|
|
295
|
+
const models = [];
|
|
296
|
+
let hasMore = true;
|
|
297
|
+
let afterId = undefined;
|
|
298
|
+
|
|
299
|
+
// Using pagination to fetch all models
|
|
300
|
+
while (hasMore) {
|
|
301
|
+
const response = await anthropic.models.list({
|
|
302
|
+
limit: 100,
|
|
303
|
+
...(afterId && { after_id: afterId }),
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
models.push(...response.data);
|
|
307
|
+
hasMore = response.has_more;
|
|
308
|
+
if (hasMore && response.data.length > 0) {
|
|
309
|
+
afterId = response.last_id;
|
|
310
|
+
}
|
|
284
311
|
}
|
|
285
312
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
// Claude 3.5
|
|
292
|
-
'claude-3-5-sonnet-20241022',
|
|
293
|
-
'claude-3-5-sonnet-20240620',
|
|
294
|
-
'claude-3-5-haiku-20241022',
|
|
295
|
-
// Claude 3
|
|
296
|
-
'claude-3-opus-20240229',
|
|
297
|
-
'claude-3-sonnet-20240229',
|
|
298
|
-
'claude-3-haiku-20240307',
|
|
299
|
-
// Claude 2 (Legacy)
|
|
300
|
-
'claude-2.1',
|
|
301
|
-
'claude-2.0',
|
|
302
|
-
'claude-instant-1.2'
|
|
303
|
-
];
|
|
304
|
-
|
|
305
|
-
return knownModels;
|
|
313
|
+
if (models.length > 0) {
|
|
314
|
+
const modelIds = models.map(m => m.id).sort();
|
|
315
|
+
spinner.succeed(`Found ${modelIds.length} Anthropic models`);
|
|
316
|
+
return modelIds;
|
|
317
|
+
}
|
|
306
318
|
} catch (error) {
|
|
307
|
-
spinner.
|
|
308
|
-
console.log(chalk.yellow(' Using default model list\n'));
|
|
309
|
-
return provider.defaultModels;
|
|
319
|
+
spinner.warn(`Failed to fetch Anthropic models: ${error.message}`);
|
|
310
320
|
}
|
|
321
|
+
console.log(chalk.yellow(' Using default model list\n'));
|
|
322
|
+
return provider.defaultModels;
|
|
311
323
|
|
|
312
324
|
case 'openai':
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
325
|
+
try {
|
|
326
|
+
const OpenAI = require('openai');
|
|
327
|
+
const openai = new OpenAI({ apiKey });
|
|
328
|
+
const response = await openai.models.list();
|
|
329
|
+
|
|
330
|
+
// Filter for chat-capable models and exclude audio/image models
|
|
331
|
+
const chatModels = response.data
|
|
332
|
+
.filter(m => {
|
|
333
|
+
const id = m.id;
|
|
334
|
+
// Exclude specific non-chat models
|
|
335
|
+
if (id.includes('dall-e') || id.includes('tts') || id.includes('whisper') ||
|
|
336
|
+
id.includes('embedding') || id.includes('moderation')) return false;
|
|
337
|
+
|
|
338
|
+
// Include known chat families
|
|
339
|
+
if (id.startsWith('gpt-') || id.startsWith('o1') || id.startsWith('o3')) return true;
|
|
340
|
+
|
|
341
|
+
return false;
|
|
342
|
+
})
|
|
343
|
+
.map(m => m.id)
|
|
344
|
+
.sort();
|
|
345
|
+
|
|
346
|
+
if (chatModels.length > 0) {
|
|
347
|
+
spinner.succeed(`Found ${chatModels.length} OpenAI chat models`);
|
|
348
|
+
return chatModels;
|
|
349
|
+
}
|
|
350
|
+
} catch (error) {
|
|
351
|
+
spinner.warn(`Failed to fetch OpenAI models: ${error.message}`);
|
|
352
|
+
}
|
|
353
|
+
console.log(chalk.yellow(' Using default model list\n'));
|
|
354
|
+
return provider.defaultModels;
|
|
327
355
|
|
|
328
356
|
case 'google':
|
|
329
357
|
try {
|
|
330
358
|
const fetch = require('node-fetch');
|
|
331
359
|
|
|
332
|
-
// Use Google's REST API to list available models
|
|
360
|
+
// Use Google's REST API to list available models (using stable v1 with header)
|
|
333
361
|
const response = await fetch(
|
|
334
|
-
`https://generativelanguage.googleapis.com/
|
|
362
|
+
`https://generativelanguage.googleapis.com/v1/models`,
|
|
363
|
+
{
|
|
364
|
+
headers: {
|
|
365
|
+
'x-goog-api-key': apiKey,
|
|
366
|
+
'Content-Type': 'application/json'
|
|
367
|
+
}
|
|
368
|
+
}
|
|
335
369
|
);
|
|
336
370
|
|
|
337
371
|
if (!response.ok) {
|
|
@@ -355,15 +389,40 @@ async function fetchAvailableModels(provider, apiKey) {
|
|
|
355
389
|
return availableModels;
|
|
356
390
|
}
|
|
357
391
|
}
|
|
358
|
-
|
|
359
|
-
// Fallback to default list
|
|
360
|
-
spinner.warn('No models found via API, using curated list');
|
|
361
|
-
return provider.defaultModels;
|
|
362
392
|
} catch (error) {
|
|
363
|
-
|
|
364
|
-
console.log(chalk.yellow(' Using default model list\n'));
|
|
365
|
-
return provider.defaultModels;
|
|
393
|
+
spinner.warn(`Failed to fetch Google models: ${error.message}`);
|
|
366
394
|
}
|
|
395
|
+
console.log(chalk.yellow(' Using default model list\n'));
|
|
396
|
+
return provider.defaultModels;
|
|
397
|
+
|
|
398
|
+
case 'perplexity':
|
|
399
|
+
try {
|
|
400
|
+
// Perplexity doesn't have a list models endpoint, so we validate known ones
|
|
401
|
+
// by performing a very cheap token count or dry-run if possible,
|
|
402
|
+
// but for now we rely on the default list as it is static but we can try to validate
|
|
403
|
+
// the API key with a simple request to 'sonar' which is their fastest model.
|
|
404
|
+
const OpenAI = require('openai');
|
|
405
|
+
const client = new OpenAI({
|
|
406
|
+
apiKey,
|
|
407
|
+
baseURL: 'https://api.perplexity.ai'
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// Simple validation check
|
|
411
|
+
await client.models.list(); // Some OpenAI compatible endpoints support this, let's try
|
|
412
|
+
|
|
413
|
+
// If list() works, we filter, otherwise we might fallback to defaults.
|
|
414
|
+
// Note: Perplexity API documentation says standard OpenAI endpoints are supported.
|
|
415
|
+
// If list() returns models, great. If not, we use defaults.
|
|
416
|
+
// However, Perplexity typically DOES NOT implement the /models endpoint fully dynamically
|
|
417
|
+
// like OpenAI. It often returns a static list or might error.
|
|
418
|
+
// Let's assume for safety we use the defaults but verified via a simple call.
|
|
419
|
+
|
|
420
|
+
spinner.succeed('Perplexity API connected');
|
|
421
|
+
return provider.defaultModels; // Return defaults as they are curated for the platform
|
|
422
|
+
} catch(error) {
|
|
423
|
+
spinner.warn(`Perplexity connectivity check failed: ${error.message}`);
|
|
424
|
+
}
|
|
425
|
+
return provider.defaultModels;
|
|
367
426
|
|
|
368
427
|
case 'openrouter':
|
|
369
428
|
try {
|
|
@@ -528,6 +587,7 @@ async function configureAIProvider(projectPath = process.cwd()) {
|
|
|
528
587
|
|
|
529
588
|
// Check if API key exists
|
|
530
589
|
let apiKey = process.env[selectedProvider.envVar] || existingEnv[selectedProvider.envVar];
|
|
590
|
+
let isNewKey = false;
|
|
531
591
|
|
|
532
592
|
if (!apiKey) {
|
|
533
593
|
console.log(chalk.yellow(`\n⚠️ ${selectedProvider.envVar} not found\n`));
|
|
@@ -553,6 +613,7 @@ async function configureAIProvider(projectPath = process.cwd()) {
|
|
|
553
613
|
]);
|
|
554
614
|
|
|
555
615
|
apiKey = manualKey.trim();
|
|
616
|
+
isNewKey = true;
|
|
556
617
|
|
|
557
618
|
// Save to .env file
|
|
558
619
|
await saveToEnvFile(envPath, selectedProvider.envVar, apiKey);
|
|
@@ -568,32 +629,61 @@ async function configureAIProvider(projectPath = process.cwd()) {
|
|
|
568
629
|
}
|
|
569
630
|
|
|
570
631
|
// Validate API key by testing basic connectivity
|
|
571
|
-
|
|
572
|
-
|
|
632
|
+
// Skip validation ONLY if we are using an existing key that matches the currently active provider
|
|
633
|
+
// This avoids redundant checks, but we still validate if the user explicitly switched providers
|
|
634
|
+
// or entered a new key.
|
|
635
|
+
|
|
636
|
+
const isActiveProvider = (process.env.ADF_CURRENT_PROVIDER === selectedProvider.id);
|
|
637
|
+
const shouldSkipValidation = !isNewKey && isActiveProvider;
|
|
638
|
+
|
|
639
|
+
if (shouldSkipValidation) {
|
|
640
|
+
console.log(chalk.gray(' Skipping validation for currently active provider...'));
|
|
641
|
+
} else {
|
|
642
|
+
const ora = require('ora');
|
|
643
|
+
const validationSpinner = ora('Validating API key...').start();
|
|
573
644
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
645
|
+
try {
|
|
646
|
+
// For Google, we need to pass a model to validate properly
|
|
647
|
+
const validationModel = selectedProvider.id === 'google' ? 'gemini-1.5-flash' : null;
|
|
648
|
+
await validateAPIKeyWithProvider(selectedProvider, apiKey, validationModel);
|
|
649
|
+
validationSpinner.succeed(chalk.green('API key validated successfully'));
|
|
650
|
+
} catch (error) {
|
|
651
|
+
validationSpinner.fail(chalk.red('API key validation failed'));
|
|
652
|
+
console.log(chalk.red(`\nError: ${error.message}\n`));
|
|
653
|
+
console.log(chalk.yellow('The API key appears to be invalid or has connectivity issues.'));
|
|
654
|
+
|
|
655
|
+
// Check if this was a stored key (from .env or environment)
|
|
656
|
+
// If so, delete it immediately to prevent infinite loops and force fresh entry
|
|
657
|
+
console.log(chalk.yellow('\n🗑️ Removing invalid stored API key to allow re-entry...'));
|
|
658
|
+
|
|
659
|
+
// Always clear from process.env
|
|
660
|
+
delete process.env[selectedProvider.envVar];
|
|
661
|
+
process.env[selectedProvider.envVar] = ''; // Ensure it is empty string at minimum
|
|
662
|
+
|
|
663
|
+
// Always clear from .env file
|
|
664
|
+
if (existingEnv[selectedProvider.envVar]) {
|
|
665
|
+
delete existingEnv[selectedProvider.envVar];
|
|
666
|
+
await saveEnvFile(envPath, existingEnv);
|
|
667
|
+
}
|
|
668
|
+
console.log(chalk.green('✓ Invalid key removed.'));
|
|
582
669
|
|
|
583
|
-
|
|
584
|
-
{
|
|
585
|
-
type: 'confirm',
|
|
586
|
-
name: 'retry',
|
|
587
|
-
message: 'Try again with a different API key?',
|
|
588
|
-
default: true
|
|
589
|
-
}
|
|
590
|
-
]);
|
|
670
|
+
console.log(chalk.gray('Please check your API key and try again.\n'));
|
|
591
671
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
672
|
+
const { retry } = await inquirer.prompt([
|
|
673
|
+
{
|
|
674
|
+
type: 'confirm',
|
|
675
|
+
name: 'retry',
|
|
676
|
+
message: 'Try again with a different API key?',
|
|
677
|
+
default: true
|
|
678
|
+
}
|
|
679
|
+
]);
|
|
680
|
+
|
|
681
|
+
if (retry) {
|
|
682
|
+
return configureAIProvider(projectPath);
|
|
683
|
+
} else {
|
|
684
|
+
process.exit(1);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
597
687
|
}
|
|
598
688
|
|
|
599
689
|
// Fetch available models (only after successful validation)
|
|
@@ -755,6 +845,8 @@ module.exports = {
|
|
|
755
845
|
configureAIProvider,
|
|
756
846
|
detectAvailableProviders,
|
|
757
847
|
validateAPIKey,
|
|
848
|
+
validateAPIKeyWithProvider,
|
|
849
|
+
fetchAvailableModels,
|
|
758
850
|
AI_PROVIDERS,
|
|
759
851
|
loadEnvIntoProcess,
|
|
760
852
|
getEnvFilePath,
|
package/lib/commands/config.js
CHANGED
|
@@ -22,8 +22,8 @@ const CONFIG_CATEGORIES = {
|
|
|
22
22
|
value: 'ai-analysis'
|
|
23
23
|
},
|
|
24
24
|
IDE_DEPLOYMENT: {
|
|
25
|
-
name: '
|
|
26
|
-
description: 'Deploy requirements to
|
|
25
|
+
name: 'Tool Deployment',
|
|
26
|
+
description: 'Deploy requirements to 12+ AI-native tools (Windsurf, Cursor, Kiro, Trae, etc.)',
|
|
27
27
|
value: 'ide-deployment'
|
|
28
28
|
},
|
|
29
29
|
LEARNING_SYSTEM: {
|
|
@@ -206,6 +206,9 @@ async function config() {
|
|
|
206
206
|
default:
|
|
207
207
|
console.log(chalk.red('\n❌ Configuration category not implemented yet.\n'));
|
|
208
208
|
}
|
|
209
|
+
|
|
210
|
+
// Safe exit to prevent hanging processes while avoiding race conditions
|
|
211
|
+
setTimeout(() => process.exit(0), 100);
|
|
209
212
|
}
|
|
210
213
|
|
|
211
214
|
/**
|
|
@@ -331,17 +334,24 @@ async function configureIDEDeploymentCategory(cwd, deploymentStatus) {
|
|
|
331
334
|
{
|
|
332
335
|
type: 'checkbox',
|
|
333
336
|
name: 'tools',
|
|
334
|
-
message: 'Select
|
|
337
|
+
message: 'Select tools to deploy to (space to select, enter to confirm):',
|
|
335
338
|
choices: [
|
|
336
339
|
{ name: 'Windsurf', value: 'windsurf', checked: deploymentStatus.tools.includes('Windsurf') },
|
|
337
340
|
{ name: 'Cursor', value: 'cursor', checked: deploymentStatus.tools.includes('Cursor') },
|
|
338
341
|
{ name: 'VSCode/Copilot', value: 'vscode', checked: deploymentStatus.tools.includes('VSCode') },
|
|
342
|
+
{ name: 'Kiro AI', value: 'kiro' },
|
|
343
|
+
{ name: 'Trae AI', value: 'trae' },
|
|
344
|
+
{ name: 'Zed Editor', value: 'zed' },
|
|
339
345
|
{ name: 'Claude Code', value: 'claude-code', checked: deploymentStatus.tools.includes('Claude Code') },
|
|
340
|
-
{ name: '
|
|
346
|
+
{ name: 'OpenCode CLI', value: 'opencode' },
|
|
347
|
+
{ name: 'Gemini CLI', value: 'gemini-cli' },
|
|
348
|
+
{ name: 'DeepAgent', value: 'deepagent' },
|
|
349
|
+
{ name: 'Codex CLI', value: 'codex-cli' },
|
|
350
|
+
{ name: 'Antigravity', value: 'antigravity' }
|
|
341
351
|
],
|
|
342
352
|
validate: (answer) => {
|
|
343
353
|
if (answer.length === 0) {
|
|
344
|
-
return 'You must choose at least one
|
|
354
|
+
return 'You must choose at least one tool.';
|
|
345
355
|
}
|
|
346
356
|
return true;
|
|
347
357
|
}
|
package/lib/commands/deploy.js
CHANGED
|
@@ -324,8 +324,11 @@ async function deploy(tool, options) {
|
|
|
324
324
|
if (options.list) {
|
|
325
325
|
console.log(chalk.cyan.bold('\n📋 Available Deployment Tools:\n'));
|
|
326
326
|
|
|
327
|
-
|
|
328
|
-
|
|
327
|
+
const sortedTools = Object.entries(TOOLS).sort((a, b) => a[0].localeCompare(b[0]));
|
|
328
|
+
|
|
329
|
+
for (const [key, value] of sortedTools) {
|
|
330
|
+
const configInfo = value.configFile.endsWith('/') ? `${value.configFile}*` : value.configFile;
|
|
331
|
+
console.log(chalk.green(` ${key.padEnd(20)}`) + chalk.gray(`${value.name.padEnd(25)} (${configInfo})`));
|
|
329
332
|
}
|
|
330
333
|
|
|
331
334
|
console.log(chalk.yellow('\nUsage: adf deploy <tool>\n'));
|
package/lib/commands/init.js
CHANGED
|
@@ -35,8 +35,18 @@ async function init(options) {
|
|
|
35
35
|
const hasOtherFrameworks = detectedFrameworks.filter(f => f !== 'adf').length > 0;
|
|
36
36
|
|
|
37
37
|
if (hasOtherFrameworks) {
|
|
38
|
+
const frameworkNames = {
|
|
39
|
+
'agent-native': 'Agent-Native',
|
|
40
|
+
'openspec': 'OpenSpec',
|
|
41
|
+
'specification-driven': 'Specification-Driven'
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const displayNames = detectedFrameworks
|
|
45
|
+
.filter(f => f !== 'adf')
|
|
46
|
+
.map(f => frameworkNames[f] || f);
|
|
47
|
+
|
|
38
48
|
console.log(chalk.cyan('📦 Existing Development Frameworks Detected:'));
|
|
39
|
-
console.log(chalk.gray(` ${
|
|
49
|
+
console.log(chalk.gray(` ${displayNames.join(', ')}\n`));
|
|
40
50
|
|
|
41
51
|
const { action } = await inquirer.prompt([
|
|
42
52
|
{
|
|
@@ -283,13 +293,13 @@ async function init(options) {
|
|
|
283
293
|
|
|
284
294
|
if (options.rapid) {
|
|
285
295
|
workflow = 'rapid';
|
|
286
|
-
console.log(chalk.blue('\nUsing:
|
|
296
|
+
console.log(chalk.blue('\nUsing: Level 1: Rapid (Agent-Native) - from --rapid flag'));
|
|
287
297
|
} else if (options.balanced) {
|
|
288
298
|
workflow = 'balanced';
|
|
289
|
-
console.log(chalk.blue('\nUsing:
|
|
299
|
+
console.log(chalk.blue('\nUsing: Level 2: Balanced (OpenSpec) - from --balanced flag'));
|
|
290
300
|
} else if (options.comprehensive) {
|
|
291
301
|
workflow = 'comprehensive';
|
|
292
|
-
console.log(chalk.blue('\nUsing:
|
|
302
|
+
console.log(chalk.blue('\nUsing: Level 3: Comprehensive (Agent-Native) - from --comprehensive flag'));
|
|
293
303
|
} else {
|
|
294
304
|
// Interactive workflow selection
|
|
295
305
|
workflow = await getWorkflowRecommendation(projectType);
|
|
@@ -460,9 +460,9 @@ class Interviewer {
|
|
|
460
460
|
|
|
461
461
|
getFrameworkName() {
|
|
462
462
|
const names = {
|
|
463
|
-
rapid: '
|
|
464
|
-
balanced: '
|
|
465
|
-
comprehensive: '
|
|
463
|
+
rapid: 'Rapid (Agent-Native)',
|
|
464
|
+
balanced: 'Balanced (OpenSpec)',
|
|
465
|
+
comprehensive: 'Comprehensive (Agent-Native)'
|
|
466
466
|
};
|
|
467
467
|
return names[this.framework] || 'Requirements Document';
|
|
468
468
|
}
|
|
@@ -7,7 +7,7 @@ const path = require('path');
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
async function generatePRP(answers, outputPath) {
|
|
10
|
-
const prp = `#
|
|
10
|
+
const prp = `# Rapid (Agent-Native) Specification (PRP)
|
|
11
11
|
|
|
12
12
|
**Generated:** ${new Date().toISOString()}
|
|
13
13
|
|
|
@@ -136,7 +136,7 @@ ${answers['bal-26'] || 'Not provided'}
|
|
|
136
136
|
`;
|
|
137
137
|
|
|
138
138
|
// Specification
|
|
139
|
-
const specification = `# Specification
|
|
139
|
+
const specification = `# Balanced (OpenSpec) Specification
|
|
140
140
|
|
|
141
141
|
**Generated:** ${new Date().toISOString()}
|
|
142
142
|
|
|
@@ -309,21 +309,21 @@ async function generateBMAD(answers, outputPath) {
|
|
|
309
309
|
// Full BMAD implementation would include PRD, Architecture, and Stories
|
|
310
310
|
await generateBalanced(answers, outputPath);
|
|
311
311
|
|
|
312
|
-
const prd = `#
|
|
312
|
+
const prd = `# Comprehensive (Agent-Native) PRD
|
|
313
313
|
|
|
314
314
|
**Generated:** ${new Date().toISOString()}
|
|
315
315
|
|
|
316
316
|
## Business Overview
|
|
317
|
-
[
|
|
317
|
+
[Agent-Native questions would populate this section]
|
|
318
318
|
|
|
319
319
|
## Market Analysis
|
|
320
|
-
[
|
|
320
|
+
[Agent-Native questions would populate this section]
|
|
321
321
|
|
|
322
322
|
## Complete Requirements
|
|
323
323
|
See specification.md for detailed requirements.
|
|
324
324
|
`;
|
|
325
325
|
|
|
326
|
-
const architecture = `# Architecture
|
|
326
|
+
const architecture = `# Comprehensive (Agent-Native) Architecture
|
|
327
327
|
|
|
328
328
|
**Generated:** ${new Date().toISOString()}
|
|
329
329
|
|
|
@@ -331,7 +331,7 @@ See specification.md for detailed requirements.
|
|
|
331
331
|
See plan.md for technical architecture details.
|
|
332
332
|
|
|
333
333
|
## Advanced Architecture Considerations
|
|
334
|
-
[
|
|
334
|
+
[Agent-Native architecture questions would populate this]
|
|
335
335
|
`;
|
|
336
336
|
|
|
337
337
|
await fs.writeFile(path.join(outputPath, 'prd.md'), prd, 'utf-8');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Framework Question Definitions
|
|
2
|
-
//
|
|
2
|
+
// Level 1: Rapid (Agent-Native), Level 2: Balanced (OpenSpec), Level 3: Comprehensive (Agent-Native)
|
|
3
3
|
|
|
4
4
|
const prpQuestions = [
|
|
5
5
|
// Phase 1: Goal Definition (4 questions)
|
|
@@ -258,7 +258,7 @@ const prpQuestions = [
|
|
|
258
258
|
}
|
|
259
259
|
];
|
|
260
260
|
|
|
261
|
-
// Balanced Framework Questions (
|
|
261
|
+
// Balanced Framework Questions (Level 2: OpenSpec)
|
|
262
262
|
const balancedQuestions = [
|
|
263
263
|
...prpQuestions, // Include all PRP questions
|
|
264
264
|
|
|
@@ -631,7 +631,7 @@ const balancedQuestions = [
|
|
|
631
631
|
}
|
|
632
632
|
];
|
|
633
633
|
|
|
634
|
-
//
|
|
634
|
+
// Comprehensive Framework Questions (Level 3: Agent-Native)
|
|
635
635
|
const bmadQuestions = [
|
|
636
636
|
...balancedQuestions, // Include all 50 Balanced questions
|
|
637
637
|
|
|
@@ -259,7 +259,7 @@ When working on this project, you MUST:
|
|
|
259
259
|
---
|
|
260
260
|
|
|
261
261
|
*Generated by [ADF CLI](https://www.npmjs.com/package/@iservu-inc/adf-cli) v${this.getADFVersion()}*
|
|
262
|
-
*Framework: Rapid
|
|
262
|
+
*Framework: Rapid (Agent-Native) | Session: ${sessionId}*
|
|
263
263
|
`;
|
|
264
264
|
}
|
|
265
265
|
|
|
@@ -400,7 +400,7 @@ When working on this project, you MUST:
|
|
|
400
400
|
---
|
|
401
401
|
|
|
402
402
|
*Generated by [ADF CLI](https://www.npmjs.com/package/@iservu-inc/adf-cli) v${this.getADFVersion()}*
|
|
403
|
-
*Framework: Balanced (
|
|
403
|
+
*Framework: Balanced (OpenSpec) | Session: ${sessionId}*
|
|
404
404
|
`;
|
|
405
405
|
}
|
|
406
406
|
|
|
@@ -609,7 +609,7 @@ When working on this project, you MUST:
|
|
|
609
609
|
---
|
|
610
610
|
|
|
611
611
|
*Generated by [ADF CLI](https://www.npmjs.com/package/@iservu-inc/adf-cli) v${this.getADFVersion()}*
|
|
612
|
-
*Framework:
|
|
612
|
+
*Framework: Comprehensive (Agent-Native) | Session: ${sessionId}*
|
|
613
613
|
`;
|
|
614
614
|
}
|
|
615
615
|
|
|
@@ -117,9 +117,9 @@ agents:
|
|
|
117
117
|
*/
|
|
118
118
|
getFrameworkName() {
|
|
119
119
|
const names = {
|
|
120
|
-
'rapid': 'Rapid
|
|
121
|
-
'balanced': 'Balanced (
|
|
122
|
-
'comprehensive': '
|
|
120
|
+
'rapid': 'Rapid (Agent-Native)',
|
|
121
|
+
'balanced': 'Balanced (OpenSpec)',
|
|
122
|
+
'comprehensive': 'Comprehensive (Agent-Native)'
|
|
123
123
|
};
|
|
124
124
|
return names[this.framework] || this.framework;
|
|
125
125
|
}
|
|
@@ -123,7 +123,7 @@ ${validation || 'See PRP for validation criteria'}
|
|
|
123
123
|
|
|
124
124
|
---
|
|
125
125
|
|
|
126
|
-
*Generated by ADF CLI v${this.getADFVersion()} from
|
|
126
|
+
*Generated by ADF CLI v${this.getADFVersion()} from Rapid (Agent-Native) framework*
|
|
127
127
|
*This is a .cursor/rules file. The legacy .cursorrules file is deprecated.*
|
|
128
128
|
`;
|
|
129
129
|
}
|
|
@@ -201,7 +201,7 @@ ${this.extractSection(plan, 'Code Style') || this.extractSection(plan, 'Coding S
|
|
|
201
201
|
|
|
202
202
|
---
|
|
203
203
|
|
|
204
|
-
*Generated by ADF CLI v${this.getADFVersion()} from Balanced framework*
|
|
204
|
+
*Generated by ADF CLI v${this.getADFVersion()} from Balanced (OpenSpec) framework*
|
|
205
205
|
*This is a .cursor/rules file. The legacy .cursorrules file is deprecated.*
|
|
206
206
|
`;
|
|
207
207
|
}
|
|
@@ -288,7 +288,7 @@ ${this.extractSection(architecture, 'System Overview') || this.extractSection(ar
|
|
|
288
288
|
|
|
289
289
|
---
|
|
290
290
|
|
|
291
|
-
*Generated by ADF CLI v${this.getADFVersion()} from
|
|
291
|
+
*Generated by ADF CLI v${this.getADFVersion()} from Comprehensive (Agent-Native) framework*
|
|
292
292
|
*This is a .cursor/rules file. The legacy .cursorrules file is deprecated.*
|
|
293
293
|
`;
|
|
294
294
|
}
|