@codebakers/cli 3.9.16 → 3.9.18
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/dist/mcp/server.js +216 -1
- package/package.json +1 -1
- package/src/mcp/server.ts +246 -3
package/dist/mcp/server.js
CHANGED
|
@@ -835,6 +835,15 @@ class CodeBakersServer {
|
|
|
835
835
|
items: { type: 'string' },
|
|
836
836
|
description: 'Files that were created/modified for this feature',
|
|
837
837
|
},
|
|
838
|
+
envVarsAdded: {
|
|
839
|
+
type: 'array',
|
|
840
|
+
items: { type: 'string' },
|
|
841
|
+
description: 'New environment variables added during implementation (e.g., ["PAYPAL_CLIENT_ID", "PAYPAL_SECRET"])',
|
|
842
|
+
},
|
|
843
|
+
schemaModified: {
|
|
844
|
+
type: 'boolean',
|
|
845
|
+
description: 'Set to true if database schema (db/schema.ts) was modified',
|
|
846
|
+
},
|
|
838
847
|
},
|
|
839
848
|
required: ['feature'],
|
|
840
849
|
},
|
|
@@ -1475,6 +1484,27 @@ class CodeBakersServer {
|
|
|
1475
1484
|
},
|
|
1476
1485
|
},
|
|
1477
1486
|
},
|
|
1487
|
+
{
|
|
1488
|
+
name: 'setup_services',
|
|
1489
|
+
description: 'Help users configure external services (Supabase, OpenAI, Anthropic). Use at project start or when env vars are missing. Explains WHY each service is needed, guides users to get their own API keys, and validates the keys work. Does NOT assume users need all services - asks one at a time based on what they want to build.',
|
|
1490
|
+
inputSchema: {
|
|
1491
|
+
type: 'object',
|
|
1492
|
+
properties: {
|
|
1493
|
+
services: {
|
|
1494
|
+
type: 'array',
|
|
1495
|
+
items: {
|
|
1496
|
+
type: 'string',
|
|
1497
|
+
enum: ['supabase', 'openai', 'anthropic', 'all'],
|
|
1498
|
+
},
|
|
1499
|
+
description: 'Which services to help configure. Use "all" to check all services, or specify individual ones.',
|
|
1500
|
+
},
|
|
1501
|
+
checkOnly: {
|
|
1502
|
+
type: 'boolean',
|
|
1503
|
+
description: 'If true, only checks which services are missing without prompting for setup. Useful for initial detection.',
|
|
1504
|
+
},
|
|
1505
|
+
},
|
|
1506
|
+
},
|
|
1507
|
+
},
|
|
1478
1508
|
// Engineering workflow tools
|
|
1479
1509
|
...engineering_tools_js_1.ENGINEERING_TOOLS,
|
|
1480
1510
|
],
|
|
@@ -1609,6 +1639,8 @@ class CodeBakersServer {
|
|
|
1609
1639
|
return this.handleProjectDashboardUrl();
|
|
1610
1640
|
case 'resume_session':
|
|
1611
1641
|
return this.handleResumeSession(args);
|
|
1642
|
+
case 'setup_services':
|
|
1643
|
+
return this.handleSetupServices(args);
|
|
1612
1644
|
// Engineering workflow tools
|
|
1613
1645
|
case 'engineering_start':
|
|
1614
1646
|
case 'engineering_scope':
|
|
@@ -3587,6 +3619,177 @@ Just describe what you want to build! I'll automatically:
|
|
|
3587
3619
|
}],
|
|
3588
3620
|
};
|
|
3589
3621
|
}
|
|
3622
|
+
handleSetupServices(args) {
|
|
3623
|
+
const { services = ['all'], checkOnly = false } = args;
|
|
3624
|
+
const cwd = process.cwd();
|
|
3625
|
+
// Define service explanations - WHY users need each service
|
|
3626
|
+
const SERVICE_INFO = {
|
|
3627
|
+
supabase: {
|
|
3628
|
+
name: 'Supabase',
|
|
3629
|
+
why: `**Why you might need Supabase:**
|
|
3630
|
+
- 📦 **Database** - Store your users, products, orders, etc.
|
|
3631
|
+
- 🔐 **Authentication** - Login, signup, OAuth (Google, GitHub, etc.)
|
|
3632
|
+
- ⚡ **Real-time** - Live updates without refreshing the page
|
|
3633
|
+
- 📁 **Storage** - File uploads (images, documents)
|
|
3634
|
+
|
|
3635
|
+
If your app needs to save ANY data or have user accounts, you need this.`,
|
|
3636
|
+
envVars: ['NEXT_PUBLIC_SUPABASE_URL', 'NEXT_PUBLIC_SUPABASE_ANON_KEY', 'SUPABASE_SERVICE_ROLE_KEY'],
|
|
3637
|
+
howToGet: `**How to get your Supabase keys:**
|
|
3638
|
+
|
|
3639
|
+
1. Go to https://supabase.com and create a free account (or sign in)
|
|
3640
|
+
2. Click "New project" and create a project
|
|
3641
|
+
3. Wait ~2 minutes for the project to initialize
|
|
3642
|
+
4. Go to **Project Settings** → **API** (in the left sidebar)
|
|
3643
|
+
5. Copy these values:
|
|
3644
|
+
|
|
3645
|
+
- **Project URL** → use for \`NEXT_PUBLIC_SUPABASE_URL\`
|
|
3646
|
+
- **anon/public key** → use for \`NEXT_PUBLIC_SUPABASE_ANON_KEY\`
|
|
3647
|
+
- **service_role key** → use for \`SUPABASE_SERVICE_ROLE_KEY\` (keep this SECRET!)
|
|
3648
|
+
|
|
3649
|
+
⚠️ The service_role key has FULL access - never expose it in client code.`,
|
|
3650
|
+
},
|
|
3651
|
+
openai: {
|
|
3652
|
+
name: 'OpenAI',
|
|
3653
|
+
why: `**Why you might need OpenAI:**
|
|
3654
|
+
- 🤖 **GPT Models** - Generate text, answer questions, chat
|
|
3655
|
+
- 🔍 **Embeddings** - Semantic search, finding similar content
|
|
3656
|
+
- 🎨 **DALL-E** - Generate images from text
|
|
3657
|
+
|
|
3658
|
+
If you want AI features like chatbots, content generation, or smart search, you need this.`,
|
|
3659
|
+
envVars: ['OPENAI_API_KEY'],
|
|
3660
|
+
howToGet: `**How to get your OpenAI API key:**
|
|
3661
|
+
|
|
3662
|
+
1. Go to https://platform.openai.com and sign up (or sign in)
|
|
3663
|
+
2. Click your profile icon → "View API keys"
|
|
3664
|
+
3. Click "Create new secret key"
|
|
3665
|
+
4. Give it a name (e.g., "My App")
|
|
3666
|
+
5. Copy the key immediately (you won't see it again!)
|
|
3667
|
+
|
|
3668
|
+
- Use this for \`OPENAI_API_KEY\`
|
|
3669
|
+
|
|
3670
|
+
💰 **Pricing Note:** OpenAI charges per token (roughly per word).
|
|
3671
|
+
- GPT-4: ~$0.03/1K input, ~$0.06/1K output
|
|
3672
|
+
- GPT-3.5: ~$0.0005/1K input, ~$0.0015/1K output
|
|
3673
|
+
|
|
3674
|
+
Start with GPT-3.5-turbo for development to save costs.`,
|
|
3675
|
+
},
|
|
3676
|
+
anthropic: {
|
|
3677
|
+
name: 'Anthropic (Claude)',
|
|
3678
|
+
why: `**Why you might need Anthropic:**
|
|
3679
|
+
- 🧠 **Claude Models** - Often better at following complex instructions
|
|
3680
|
+
- 💻 **Coding Tasks** - Claude excels at code generation and review
|
|
3681
|
+
- 📝 **Long Documents** - Handles very long context windows
|
|
3682
|
+
|
|
3683
|
+
If you want AI features and prefer Claude over GPT (or want both as fallback).`,
|
|
3684
|
+
envVars: ['ANTHROPIC_API_KEY'],
|
|
3685
|
+
howToGet: `**How to get your Anthropic API key:**
|
|
3686
|
+
|
|
3687
|
+
1. Go to https://console.anthropic.com and sign up (or sign in)
|
|
3688
|
+
2. Go to "API Keys" in the left sidebar
|
|
3689
|
+
3. Click "Create Key"
|
|
3690
|
+
4. Give it a name and copy the key
|
|
3691
|
+
|
|
3692
|
+
- Use this for \`ANTHROPIC_API_KEY\`
|
|
3693
|
+
|
|
3694
|
+
💰 **Pricing Note:** Anthropic charges per token.
|
|
3695
|
+
- Claude 3 Opus: ~$15/M input, ~$75/M output (most capable)
|
|
3696
|
+
- Claude 3 Sonnet: ~$3/M input, ~$15/M output (balanced)
|
|
3697
|
+
- Claude 3 Haiku: ~$0.25/M input, ~$1.25/M output (fastest/cheapest)`,
|
|
3698
|
+
},
|
|
3699
|
+
};
|
|
3700
|
+
// Check which services to process
|
|
3701
|
+
const servicesToCheck = services.includes('all')
|
|
3702
|
+
? ['supabase', 'openai', 'anthropic']
|
|
3703
|
+
: services.filter(s => s !== 'all');
|
|
3704
|
+
// Check .env file for existing vars
|
|
3705
|
+
const envPath = path.join(cwd, '.env');
|
|
3706
|
+
const envLocalPath = path.join(cwd, '.env.local');
|
|
3707
|
+
let envContent = '';
|
|
3708
|
+
if (fs.existsSync(envLocalPath)) {
|
|
3709
|
+
envContent = fs.readFileSync(envLocalPath, 'utf-8');
|
|
3710
|
+
}
|
|
3711
|
+
else if (fs.existsSync(envPath)) {
|
|
3712
|
+
envContent = fs.readFileSync(envPath, 'utf-8');
|
|
3713
|
+
}
|
|
3714
|
+
// Parse existing env vars
|
|
3715
|
+
const existingVars = new Set();
|
|
3716
|
+
for (const line of envContent.split('\n')) {
|
|
3717
|
+
const match = line.match(/^([A-Z_][A-Z0-9_]*)=/);
|
|
3718
|
+
if (match) {
|
|
3719
|
+
existingVars.add(match[1]);
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
// Check each service
|
|
3723
|
+
const results = [];
|
|
3724
|
+
for (const serviceKey of servicesToCheck) {
|
|
3725
|
+
const info = SERVICE_INFO[serviceKey];
|
|
3726
|
+
if (!info)
|
|
3727
|
+
continue;
|
|
3728
|
+
const missingVars = info.envVars.filter(v => !existingVars.has(v));
|
|
3729
|
+
results.push({
|
|
3730
|
+
service: serviceKey,
|
|
3731
|
+
configured: missingVars.length === 0,
|
|
3732
|
+
missingVars,
|
|
3733
|
+
info,
|
|
3734
|
+
});
|
|
3735
|
+
}
|
|
3736
|
+
// Build response
|
|
3737
|
+
let response = `# 🔧 Service Configuration Check\n\n`;
|
|
3738
|
+
const configured = results.filter(r => r.configured);
|
|
3739
|
+
const missing = results.filter(r => !r.configured);
|
|
3740
|
+
if (configured.length > 0) {
|
|
3741
|
+
response += `## ✅ Already Configured\n`;
|
|
3742
|
+
for (const r of configured) {
|
|
3743
|
+
response += `- **${r.info.name}** - All env vars present\n`;
|
|
3744
|
+
}
|
|
3745
|
+
response += `\n`;
|
|
3746
|
+
}
|
|
3747
|
+
if (missing.length === 0) {
|
|
3748
|
+
response += `All requested services are configured! 🎉\n\n`;
|
|
3749
|
+
response += `If you need to reconfigure any service, add the specific service name (e.g., \`setup_services({ services: ['supabase'] })\`).\n`;
|
|
3750
|
+
}
|
|
3751
|
+
else {
|
|
3752
|
+
response += `## ⚠️ Missing Configuration\n\n`;
|
|
3753
|
+
for (const r of missing) {
|
|
3754
|
+
response += `### ${r.info.name}\n\n`;
|
|
3755
|
+
response += `**Missing:** \`${r.missingVars.join('`, `')}\`\n\n`;
|
|
3756
|
+
if (checkOnly) {
|
|
3757
|
+
// Just show what's missing
|
|
3758
|
+
response += `---\n\n`;
|
|
3759
|
+
}
|
|
3760
|
+
else {
|
|
3761
|
+
// Show full explanation
|
|
3762
|
+
response += `${r.info.why}\n\n`;
|
|
3763
|
+
response += `${r.info.howToGet}\n\n`;
|
|
3764
|
+
response += `---\n\n`;
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
if (checkOnly) {
|
|
3768
|
+
response += `\nRun \`setup_services({ checkOnly: false })\` to get setup instructions for each service.\n`;
|
|
3769
|
+
}
|
|
3770
|
+
else {
|
|
3771
|
+
response += `## Next Steps\n\n`;
|
|
3772
|
+
response += `1. Decide which services you actually need for your project\n`;
|
|
3773
|
+
response += `2. Create accounts and get API keys for those services\n`;
|
|
3774
|
+
response += `3. Add the keys to your \`.env.local\` file:\n\n`;
|
|
3775
|
+
response += `\`\`\`bash\n`;
|
|
3776
|
+
for (const r of missing) {
|
|
3777
|
+
for (const v of r.missingVars) {
|
|
3778
|
+
response += `${v}=your_key_here\n`;
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
response += `\`\`\`\n\n`;
|
|
3782
|
+
response += `4. Restart your dev server after adding keys\n\n`;
|
|
3783
|
+
response += `**Don't need a service?** That's fine! Only configure what you'll actually use.\n`;
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
return {
|
|
3787
|
+
content: [{
|
|
3788
|
+
type: 'text',
|
|
3789
|
+
text: response,
|
|
3790
|
+
}],
|
|
3791
|
+
};
|
|
3792
|
+
}
|
|
3590
3793
|
handleRunTests(args) {
|
|
3591
3794
|
const { filter, watch = false } = args;
|
|
3592
3795
|
const cwd = process.cwd();
|
|
@@ -3922,12 +4125,21 @@ Just describe what you want to build! I'll automatically:
|
|
|
3922
4125
|
* Runs local checks (tests, TypeScript), then validates with server
|
|
3923
4126
|
*/
|
|
3924
4127
|
async handleValidateComplete(args) {
|
|
3925
|
-
const { feature, files = [] } = args;
|
|
4128
|
+
const { feature, files = [], envVarsAdded = [], schemaModified: schemaModifiedArg } = args;
|
|
3926
4129
|
const cwd = process.cwd();
|
|
3927
4130
|
let testsExist = false;
|
|
3928
4131
|
let testsPass = false;
|
|
3929
4132
|
let typescriptPass = false;
|
|
3930
4133
|
const testsWritten = [];
|
|
4134
|
+
// v3.9.17: Auto-detect schema modifications if not explicitly provided
|
|
4135
|
+
let schemaModified = schemaModifiedArg;
|
|
4136
|
+
if (schemaModified === undefined) {
|
|
4137
|
+
// Check if schema file was in the modified files list
|
|
4138
|
+
schemaModified = files.some(f => f.includes('schema.ts') ||
|
|
4139
|
+
f.includes('schema/') ||
|
|
4140
|
+
f.includes('db/schema') ||
|
|
4141
|
+
f.includes('drizzle/'));
|
|
4142
|
+
}
|
|
3931
4143
|
// v6.1: Code analysis for compliance scoring
|
|
3932
4144
|
const codeAnalysis = {};
|
|
3933
4145
|
// Step 1: Get session token (from memory or state file)
|
|
@@ -4105,6 +4317,9 @@ Just describe what you want to build! I'll automatically:
|
|
|
4105
4317
|
testsPassed: testsPass,
|
|
4106
4318
|
typescriptPassed: typescriptPass,
|
|
4107
4319
|
codeAnalysis, // v6.1: Send code analysis for compliance scoring
|
|
4320
|
+
// v3.9.17: Environment and schema validation
|
|
4321
|
+
envVarsAdded: envVarsAdded.length > 0 ? envVarsAdded : undefined,
|
|
4322
|
+
schemaModified,
|
|
4108
4323
|
}),
|
|
4109
4324
|
});
|
|
4110
4325
|
const result = await response.json();
|
package/package.json
CHANGED
package/src/mcp/server.ts
CHANGED
|
@@ -917,6 +917,15 @@ class CodeBakersServer {
|
|
|
917
917
|
items: { type: 'string' },
|
|
918
918
|
description: 'Files that were created/modified for this feature',
|
|
919
919
|
},
|
|
920
|
+
envVarsAdded: {
|
|
921
|
+
type: 'array',
|
|
922
|
+
items: { type: 'string' },
|
|
923
|
+
description: 'New environment variables added during implementation (e.g., ["PAYPAL_CLIENT_ID", "PAYPAL_SECRET"])',
|
|
924
|
+
},
|
|
925
|
+
schemaModified: {
|
|
926
|
+
type: 'boolean',
|
|
927
|
+
description: 'Set to true if database schema (db/schema.ts) was modified',
|
|
928
|
+
},
|
|
920
929
|
},
|
|
921
930
|
required: ['feature'],
|
|
922
931
|
},
|
|
@@ -1589,6 +1598,28 @@ class CodeBakersServer {
|
|
|
1589
1598
|
},
|
|
1590
1599
|
},
|
|
1591
1600
|
},
|
|
1601
|
+
{
|
|
1602
|
+
name: 'setup_services',
|
|
1603
|
+
description:
|
|
1604
|
+
'Help users configure external services (Supabase, OpenAI, Anthropic). Use at project start or when env vars are missing. Explains WHY each service is needed, guides users to get their own API keys, and validates the keys work. Does NOT assume users need all services - asks one at a time based on what they want to build.',
|
|
1605
|
+
inputSchema: {
|
|
1606
|
+
type: 'object' as const,
|
|
1607
|
+
properties: {
|
|
1608
|
+
services: {
|
|
1609
|
+
type: 'array',
|
|
1610
|
+
items: {
|
|
1611
|
+
type: 'string',
|
|
1612
|
+
enum: ['supabase', 'openai', 'anthropic', 'all'],
|
|
1613
|
+
},
|
|
1614
|
+
description: 'Which services to help configure. Use "all" to check all services, or specify individual ones.',
|
|
1615
|
+
},
|
|
1616
|
+
checkOnly: {
|
|
1617
|
+
type: 'boolean',
|
|
1618
|
+
description: 'If true, only checks which services are missing without prompting for setup. Useful for initial detection.',
|
|
1619
|
+
},
|
|
1620
|
+
},
|
|
1621
|
+
},
|
|
1622
|
+
},
|
|
1592
1623
|
// Engineering workflow tools
|
|
1593
1624
|
...ENGINEERING_TOOLS,
|
|
1594
1625
|
],
|
|
@@ -1686,7 +1717,7 @@ class CodeBakersServer {
|
|
|
1686
1717
|
return this.handleGenerateTests(args as { file?: string; feature?: string; testType?: 'unit' | 'integration' | 'e2e' });
|
|
1687
1718
|
|
|
1688
1719
|
case 'validate_complete':
|
|
1689
|
-
return this.handleValidateComplete(args as { feature: string; files?: string[] });
|
|
1720
|
+
return this.handleValidateComplete(args as { feature: string; files?: string[]; envVarsAdded?: string[]; schemaModified?: boolean });
|
|
1690
1721
|
|
|
1691
1722
|
case 'discover_patterns':
|
|
1692
1723
|
return this.handleDiscoverPatterns(args as { task: string; files?: string[]; keywords?: string[] });
|
|
@@ -1840,6 +1871,9 @@ class CodeBakersServer {
|
|
|
1840
1871
|
case 'resume_session':
|
|
1841
1872
|
return this.handleResumeSession(args as { reason?: string });
|
|
1842
1873
|
|
|
1874
|
+
case 'setup_services':
|
|
1875
|
+
return this.handleSetupServices(args as { services?: string[]; checkOnly?: boolean });
|
|
1876
|
+
|
|
1843
1877
|
// Engineering workflow tools
|
|
1844
1878
|
case 'engineering_start':
|
|
1845
1879
|
case 'engineering_scope':
|
|
@@ -4032,6 +4066,200 @@ Just describe what you want to build! I'll automatically:
|
|
|
4032
4066
|
};
|
|
4033
4067
|
}
|
|
4034
4068
|
|
|
4069
|
+
private handleSetupServices(args: { services?: string[]; checkOnly?: boolean }) {
|
|
4070
|
+
const { services = ['all'], checkOnly = false } = args;
|
|
4071
|
+
const cwd = process.cwd();
|
|
4072
|
+
|
|
4073
|
+
// Define service explanations - WHY users need each service
|
|
4074
|
+
const SERVICE_INFO: Record<string, {
|
|
4075
|
+
name: string;
|
|
4076
|
+
why: string;
|
|
4077
|
+
envVars: string[];
|
|
4078
|
+
howToGet: string;
|
|
4079
|
+
validateUrl?: string;
|
|
4080
|
+
}> = {
|
|
4081
|
+
supabase: {
|
|
4082
|
+
name: 'Supabase',
|
|
4083
|
+
why: `**Why you might need Supabase:**
|
|
4084
|
+
- 📦 **Database** - Store your users, products, orders, etc.
|
|
4085
|
+
- 🔐 **Authentication** - Login, signup, OAuth (Google, GitHub, etc.)
|
|
4086
|
+
- ⚡ **Real-time** - Live updates without refreshing the page
|
|
4087
|
+
- 📁 **Storage** - File uploads (images, documents)
|
|
4088
|
+
|
|
4089
|
+
If your app needs to save ANY data or have user accounts, you need this.`,
|
|
4090
|
+
envVars: ['NEXT_PUBLIC_SUPABASE_URL', 'NEXT_PUBLIC_SUPABASE_ANON_KEY', 'SUPABASE_SERVICE_ROLE_KEY'],
|
|
4091
|
+
howToGet: `**How to get your Supabase keys:**
|
|
4092
|
+
|
|
4093
|
+
1. Go to https://supabase.com and create a free account (or sign in)
|
|
4094
|
+
2. Click "New project" and create a project
|
|
4095
|
+
3. Wait ~2 minutes for the project to initialize
|
|
4096
|
+
4. Go to **Project Settings** → **API** (in the left sidebar)
|
|
4097
|
+
5. Copy these values:
|
|
4098
|
+
|
|
4099
|
+
- **Project URL** → use for \`NEXT_PUBLIC_SUPABASE_URL\`
|
|
4100
|
+
- **anon/public key** → use for \`NEXT_PUBLIC_SUPABASE_ANON_KEY\`
|
|
4101
|
+
- **service_role key** → use for \`SUPABASE_SERVICE_ROLE_KEY\` (keep this SECRET!)
|
|
4102
|
+
|
|
4103
|
+
⚠️ The service_role key has FULL access - never expose it in client code.`,
|
|
4104
|
+
},
|
|
4105
|
+
openai: {
|
|
4106
|
+
name: 'OpenAI',
|
|
4107
|
+
why: `**Why you might need OpenAI:**
|
|
4108
|
+
- 🤖 **GPT Models** - Generate text, answer questions, chat
|
|
4109
|
+
- 🔍 **Embeddings** - Semantic search, finding similar content
|
|
4110
|
+
- 🎨 **DALL-E** - Generate images from text
|
|
4111
|
+
|
|
4112
|
+
If you want AI features like chatbots, content generation, or smart search, you need this.`,
|
|
4113
|
+
envVars: ['OPENAI_API_KEY'],
|
|
4114
|
+
howToGet: `**How to get your OpenAI API key:**
|
|
4115
|
+
|
|
4116
|
+
1. Go to https://platform.openai.com and sign up (or sign in)
|
|
4117
|
+
2. Click your profile icon → "View API keys"
|
|
4118
|
+
3. Click "Create new secret key"
|
|
4119
|
+
4. Give it a name (e.g., "My App")
|
|
4120
|
+
5. Copy the key immediately (you won't see it again!)
|
|
4121
|
+
|
|
4122
|
+
- Use this for \`OPENAI_API_KEY\`
|
|
4123
|
+
|
|
4124
|
+
💰 **Pricing Note:** OpenAI charges per token (roughly per word).
|
|
4125
|
+
- GPT-4: ~$0.03/1K input, ~$0.06/1K output
|
|
4126
|
+
- GPT-3.5: ~$0.0005/1K input, ~$0.0015/1K output
|
|
4127
|
+
|
|
4128
|
+
Start with GPT-3.5-turbo for development to save costs.`,
|
|
4129
|
+
},
|
|
4130
|
+
anthropic: {
|
|
4131
|
+
name: 'Anthropic (Claude)',
|
|
4132
|
+
why: `**Why you might need Anthropic:**
|
|
4133
|
+
- 🧠 **Claude Models** - Often better at following complex instructions
|
|
4134
|
+
- 💻 **Coding Tasks** - Claude excels at code generation and review
|
|
4135
|
+
- 📝 **Long Documents** - Handles very long context windows
|
|
4136
|
+
|
|
4137
|
+
If you want AI features and prefer Claude over GPT (or want both as fallback).`,
|
|
4138
|
+
envVars: ['ANTHROPIC_API_KEY'],
|
|
4139
|
+
howToGet: `**How to get your Anthropic API key:**
|
|
4140
|
+
|
|
4141
|
+
1. Go to https://console.anthropic.com and sign up (or sign in)
|
|
4142
|
+
2. Go to "API Keys" in the left sidebar
|
|
4143
|
+
3. Click "Create Key"
|
|
4144
|
+
4. Give it a name and copy the key
|
|
4145
|
+
|
|
4146
|
+
- Use this for \`ANTHROPIC_API_KEY\`
|
|
4147
|
+
|
|
4148
|
+
💰 **Pricing Note:** Anthropic charges per token.
|
|
4149
|
+
- Claude 3 Opus: ~$15/M input, ~$75/M output (most capable)
|
|
4150
|
+
- Claude 3 Sonnet: ~$3/M input, ~$15/M output (balanced)
|
|
4151
|
+
- Claude 3 Haiku: ~$0.25/M input, ~$1.25/M output (fastest/cheapest)`,
|
|
4152
|
+
},
|
|
4153
|
+
};
|
|
4154
|
+
|
|
4155
|
+
// Check which services to process
|
|
4156
|
+
const servicesToCheck = services.includes('all')
|
|
4157
|
+
? ['supabase', 'openai', 'anthropic']
|
|
4158
|
+
: services.filter(s => s !== 'all');
|
|
4159
|
+
|
|
4160
|
+
// Check .env file for existing vars
|
|
4161
|
+
const envPath = path.join(cwd, '.env');
|
|
4162
|
+
const envLocalPath = path.join(cwd, '.env.local');
|
|
4163
|
+
let envContent = '';
|
|
4164
|
+
|
|
4165
|
+
if (fs.existsSync(envLocalPath)) {
|
|
4166
|
+
envContent = fs.readFileSync(envLocalPath, 'utf-8');
|
|
4167
|
+
} else if (fs.existsSync(envPath)) {
|
|
4168
|
+
envContent = fs.readFileSync(envPath, 'utf-8');
|
|
4169
|
+
}
|
|
4170
|
+
|
|
4171
|
+
// Parse existing env vars
|
|
4172
|
+
const existingVars = new Set<string>();
|
|
4173
|
+
for (const line of envContent.split('\n')) {
|
|
4174
|
+
const match = line.match(/^([A-Z_][A-Z0-9_]*)=/);
|
|
4175
|
+
if (match) {
|
|
4176
|
+
existingVars.add(match[1]);
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
|
|
4180
|
+
// Check each service
|
|
4181
|
+
const results: Array<{
|
|
4182
|
+
service: string;
|
|
4183
|
+
configured: boolean;
|
|
4184
|
+
missingVars: string[];
|
|
4185
|
+
info: typeof SERVICE_INFO[string];
|
|
4186
|
+
}> = [];
|
|
4187
|
+
|
|
4188
|
+
for (const serviceKey of servicesToCheck) {
|
|
4189
|
+
const info = SERVICE_INFO[serviceKey];
|
|
4190
|
+
if (!info) continue;
|
|
4191
|
+
|
|
4192
|
+
const missingVars = info.envVars.filter(v => !existingVars.has(v));
|
|
4193
|
+
results.push({
|
|
4194
|
+
service: serviceKey,
|
|
4195
|
+
configured: missingVars.length === 0,
|
|
4196
|
+
missingVars,
|
|
4197
|
+
info,
|
|
4198
|
+
});
|
|
4199
|
+
}
|
|
4200
|
+
|
|
4201
|
+
// Build response
|
|
4202
|
+
let response = `# 🔧 Service Configuration Check\n\n`;
|
|
4203
|
+
|
|
4204
|
+
const configured = results.filter(r => r.configured);
|
|
4205
|
+
const missing = results.filter(r => !r.configured);
|
|
4206
|
+
|
|
4207
|
+
if (configured.length > 0) {
|
|
4208
|
+
response += `## ✅ Already Configured\n`;
|
|
4209
|
+
for (const r of configured) {
|
|
4210
|
+
response += `- **${r.info.name}** - All env vars present\n`;
|
|
4211
|
+
}
|
|
4212
|
+
response += `\n`;
|
|
4213
|
+
}
|
|
4214
|
+
|
|
4215
|
+
if (missing.length === 0) {
|
|
4216
|
+
response += `All requested services are configured! 🎉\n\n`;
|
|
4217
|
+
response += `If you need to reconfigure any service, add the specific service name (e.g., \`setup_services({ services: ['supabase'] })\`).\n`;
|
|
4218
|
+
} else {
|
|
4219
|
+
response += `## ⚠️ Missing Configuration\n\n`;
|
|
4220
|
+
|
|
4221
|
+
for (const r of missing) {
|
|
4222
|
+
response += `### ${r.info.name}\n\n`;
|
|
4223
|
+
response += `**Missing:** \`${r.missingVars.join('`, `')}\`\n\n`;
|
|
4224
|
+
|
|
4225
|
+
if (checkOnly) {
|
|
4226
|
+
// Just show what's missing
|
|
4227
|
+
response += `---\n\n`;
|
|
4228
|
+
} else {
|
|
4229
|
+
// Show full explanation
|
|
4230
|
+
response += `${r.info.why}\n\n`;
|
|
4231
|
+
response += `${r.info.howToGet}\n\n`;
|
|
4232
|
+
response += `---\n\n`;
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4235
|
+
|
|
4236
|
+
if (checkOnly) {
|
|
4237
|
+
response += `\nRun \`setup_services({ checkOnly: false })\` to get setup instructions for each service.\n`;
|
|
4238
|
+
} else {
|
|
4239
|
+
response += `## Next Steps\n\n`;
|
|
4240
|
+
response += `1. Decide which services you actually need for your project\n`;
|
|
4241
|
+
response += `2. Create accounts and get API keys for those services\n`;
|
|
4242
|
+
response += `3. Add the keys to your \`.env.local\` file:\n\n`;
|
|
4243
|
+
response += `\`\`\`bash\n`;
|
|
4244
|
+
for (const r of missing) {
|
|
4245
|
+
for (const v of r.missingVars) {
|
|
4246
|
+
response += `${v}=your_key_here\n`;
|
|
4247
|
+
}
|
|
4248
|
+
}
|
|
4249
|
+
response += `\`\`\`\n\n`;
|
|
4250
|
+
response += `4. Restart your dev server after adding keys\n\n`;
|
|
4251
|
+
response += `**Don't need a service?** That's fine! Only configure what you'll actually use.\n`;
|
|
4252
|
+
}
|
|
4253
|
+
}
|
|
4254
|
+
|
|
4255
|
+
return {
|
|
4256
|
+
content: [{
|
|
4257
|
+
type: 'text' as const,
|
|
4258
|
+
text: response,
|
|
4259
|
+
}],
|
|
4260
|
+
};
|
|
4261
|
+
}
|
|
4262
|
+
|
|
4035
4263
|
private handleRunTests(args: { filter?: string; watch?: boolean }) {
|
|
4036
4264
|
const { filter, watch = false } = args;
|
|
4037
4265
|
const cwd = process.cwd();
|
|
@@ -4384,14 +4612,26 @@ Just describe what you want to build! I'll automatically:
|
|
|
4384
4612
|
* MANDATORY: Validate that a feature is complete before AI can say "done" (v6.0 Server-Side)
|
|
4385
4613
|
* Runs local checks (tests, TypeScript), then validates with server
|
|
4386
4614
|
*/
|
|
4387
|
-
private async handleValidateComplete(args: { feature: string; files?: string[] }) {
|
|
4388
|
-
const { feature, files = [] } = args;
|
|
4615
|
+
private async handleValidateComplete(args: { feature: string; files?: string[]; envVarsAdded?: string[]; schemaModified?: boolean }) {
|
|
4616
|
+
const { feature, files = [], envVarsAdded = [], schemaModified: schemaModifiedArg } = args;
|
|
4389
4617
|
const cwd = process.cwd();
|
|
4390
4618
|
let testsExist = false;
|
|
4391
4619
|
let testsPass = false;
|
|
4392
4620
|
let typescriptPass = false;
|
|
4393
4621
|
const testsWritten: string[] = [];
|
|
4394
4622
|
|
|
4623
|
+
// v3.9.17: Auto-detect schema modifications if not explicitly provided
|
|
4624
|
+
let schemaModified = schemaModifiedArg;
|
|
4625
|
+
if (schemaModified === undefined) {
|
|
4626
|
+
// Check if schema file was in the modified files list
|
|
4627
|
+
schemaModified = files.some(f =>
|
|
4628
|
+
f.includes('schema.ts') ||
|
|
4629
|
+
f.includes('schema/') ||
|
|
4630
|
+
f.includes('db/schema') ||
|
|
4631
|
+
f.includes('drizzle/')
|
|
4632
|
+
);
|
|
4633
|
+
}
|
|
4634
|
+
|
|
4395
4635
|
// v6.1: Code analysis for compliance scoring
|
|
4396
4636
|
const codeAnalysis: {
|
|
4397
4637
|
hasErrorHandling?: boolean;
|
|
@@ -4584,6 +4824,9 @@ Just describe what you want to build! I'll automatically:
|
|
|
4584
4824
|
testsPassed: testsPass,
|
|
4585
4825
|
typescriptPassed: typescriptPass,
|
|
4586
4826
|
codeAnalysis, // v6.1: Send code analysis for compliance scoring
|
|
4827
|
+
// v3.9.17: Environment and schema validation
|
|
4828
|
+
envVarsAdded: envVarsAdded.length > 0 ? envVarsAdded : undefined,
|
|
4829
|
+
schemaModified,
|
|
4587
4830
|
}),
|
|
4588
4831
|
});
|
|
4589
4832
|
|