@codebakers/cli 3.9.17 → 3.9.19
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 +199 -0
- package/package.json +1 -1
- package/src/mcp/server.ts +224 -0
package/dist/mcp/server.js
CHANGED
|
@@ -1484,6 +1484,27 @@ class CodeBakersServer {
|
|
|
1484
1484
|
},
|
|
1485
1485
|
},
|
|
1486
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
|
+
},
|
|
1487
1508
|
// Engineering workflow tools
|
|
1488
1509
|
...engineering_tools_js_1.ENGINEERING_TOOLS,
|
|
1489
1510
|
],
|
|
@@ -1618,6 +1639,8 @@ class CodeBakersServer {
|
|
|
1618
1639
|
return this.handleProjectDashboardUrl();
|
|
1619
1640
|
case 'resume_session':
|
|
1620
1641
|
return this.handleResumeSession(args);
|
|
1642
|
+
case 'setup_services':
|
|
1643
|
+
return this.handleSetupServices(args);
|
|
1621
1644
|
// Engineering workflow tools
|
|
1622
1645
|
case 'engineering_start':
|
|
1623
1646
|
case 'engineering_scope':
|
|
@@ -3596,6 +3619,182 @@ Just describe what you want to build! I'll automatically:
|
|
|
3596
3619
|
}],
|
|
3597
3620
|
};
|
|
3598
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 using the instructions above\n`;
|
|
3774
|
+
response += `3. **Paste your keys here in chat** and I'll add them to your \`.env.local\` file for you!\n\n`;
|
|
3775
|
+
response += `Example: Just paste something like:\n`;
|
|
3776
|
+
response += `\`\`\`\n`;
|
|
3777
|
+
response += `Here are my keys:\n`;
|
|
3778
|
+
for (const r of missing) {
|
|
3779
|
+
if (r.missingVars.length > 0) {
|
|
3780
|
+
response += `${r.info.name}: sk-xxx... (your actual key)\n`;
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
response += `\`\`\`\n\n`;
|
|
3784
|
+
response += `I'll automatically:\n`;
|
|
3785
|
+
response += `- Create \`.env.local\` if it doesn't exist\n`;
|
|
3786
|
+
response += `- Add the correct variable names\n`;
|
|
3787
|
+
response += `- Keep your existing env vars safe\n\n`;
|
|
3788
|
+
response += `**Don't need a service?** That's fine! Only configure what you'll actually use.\n`;
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
return {
|
|
3792
|
+
content: [{
|
|
3793
|
+
type: 'text',
|
|
3794
|
+
text: response,
|
|
3795
|
+
}],
|
|
3796
|
+
};
|
|
3797
|
+
}
|
|
3599
3798
|
handleRunTests(args) {
|
|
3600
3799
|
const { filter, watch = false } = args;
|
|
3601
3800
|
const cwd = process.cwd();
|
package/package.json
CHANGED
package/src/mcp/server.ts
CHANGED
|
@@ -1598,6 +1598,28 @@ class CodeBakersServer {
|
|
|
1598
1598
|
},
|
|
1599
1599
|
},
|
|
1600
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
|
+
},
|
|
1601
1623
|
// Engineering workflow tools
|
|
1602
1624
|
...ENGINEERING_TOOLS,
|
|
1603
1625
|
],
|
|
@@ -1849,6 +1871,9 @@ class CodeBakersServer {
|
|
|
1849
1871
|
case 'resume_session':
|
|
1850
1872
|
return this.handleResumeSession(args as { reason?: string });
|
|
1851
1873
|
|
|
1874
|
+
case 'setup_services':
|
|
1875
|
+
return this.handleSetupServices(args as { services?: string[]; checkOnly?: boolean });
|
|
1876
|
+
|
|
1852
1877
|
// Engineering workflow tools
|
|
1853
1878
|
case 'engineering_start':
|
|
1854
1879
|
case 'engineering_scope':
|
|
@@ -4041,6 +4066,205 @@ Just describe what you want to build! I'll automatically:
|
|
|
4041
4066
|
};
|
|
4042
4067
|
}
|
|
4043
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 using the instructions above\n`;
|
|
4242
|
+
response += `3. **Paste your keys here in chat** and I'll add them to your \`.env.local\` file for you!\n\n`;
|
|
4243
|
+
response += `Example: Just paste something like:\n`;
|
|
4244
|
+
response += `\`\`\`\n`;
|
|
4245
|
+
response += `Here are my keys:\n`;
|
|
4246
|
+
for (const r of missing) {
|
|
4247
|
+
if (r.missingVars.length > 0) {
|
|
4248
|
+
response += `${r.info.name}: sk-xxx... (your actual key)\n`;
|
|
4249
|
+
}
|
|
4250
|
+
}
|
|
4251
|
+
response += `\`\`\`\n\n`;
|
|
4252
|
+
response += `I'll automatically:\n`;
|
|
4253
|
+
response += `- Create \`.env.local\` if it doesn't exist\n`;
|
|
4254
|
+
response += `- Add the correct variable names\n`;
|
|
4255
|
+
response += `- Keep your existing env vars safe\n\n`;
|
|
4256
|
+
response += `**Don't need a service?** That's fine! Only configure what you'll actually use.\n`;
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
|
|
4260
|
+
return {
|
|
4261
|
+
content: [{
|
|
4262
|
+
type: 'text' as const,
|
|
4263
|
+
text: response,
|
|
4264
|
+
}],
|
|
4265
|
+
};
|
|
4266
|
+
}
|
|
4267
|
+
|
|
4044
4268
|
private handleRunTests(args: { filter?: string; watch?: boolean }) {
|
|
4045
4269
|
const { filter, watch = false } = args;
|
|
4046
4270
|
const cwd = process.cwd();
|