codebakers 2.5.3 → 3.0.0
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 +54 -255
- package/dist/chunk-HOWR3YTF.js +146 -0
- package/dist/index.d.ts +0 -3
- package/dist/index.js +10489 -7994
- package/dist/terminal-6ZQVP6R7.js +10 -0
- package/package.json +26 -41
- package/AUDIT_REPORT.md +0 -138
- package/dist/advisors-RWRTSJRR.js +0 -7
- package/dist/chunk-ASIJIQYC.js +0 -320
- package/dist/chunk-D44U3IEA.js +0 -565
- package/dist/chunk-LANM5XQW.js +0 -326
- package/dist/prd-RYITSL6Q.js +0 -7
- package/install.bat +0 -9
- package/installers/CodeBakers-Install.bat +0 -207
- package/installers/CodeBakers-Install.command +0 -232
- package/installers/README.md +0 -157
- package/installers/mac/assets/README.txt +0 -31
- package/installers/mac/build-mac-installer.sh +0 -240
- package/installers/windows/CodeBakers.iss +0 -256
- package/installers/windows/assets/README.txt +0 -16
- package/installers/windows/scripts/post-install.bat +0 -15
- package/src/channels/discord.ts +0 -5
- package/src/channels/slack.ts +0 -5
- package/src/channels/sms.ts +0 -4
- package/src/channels/telegram.ts +0 -5
- package/src/channels/whatsapp.ts +0 -7
- package/src/commands/advisors.ts +0 -699
- package/src/commands/build.ts +0 -1025
- package/src/commands/check.ts +0 -365
- package/src/commands/code.ts +0 -806
- package/src/commands/connect.ts +0 -12
- package/src/commands/deploy.ts +0 -448
- package/src/commands/design.ts +0 -298
- package/src/commands/fix.ts +0 -20
- package/src/commands/gateway.ts +0 -604
- package/src/commands/generate.ts +0 -178
- package/src/commands/init.ts +0 -634
- package/src/commands/integrate.ts +0 -884
- package/src/commands/learn.ts +0 -36
- package/src/commands/migrate.ts +0 -419
- package/src/commands/prd-maker.ts +0 -588
- package/src/commands/prd.ts +0 -419
- package/src/commands/security.ts +0 -102
- package/src/commands/setup.ts +0 -600
- package/src/commands/status.ts +0 -56
- package/src/commands/website.ts +0 -741
- package/src/index.ts +0 -627
- package/src/patterns/loader.ts +0 -337
- package/src/services/github.ts +0 -61
- package/src/services/supabase.ts +0 -147
- package/src/services/vercel.ts +0 -61
- package/src/utils/claude-md.ts +0 -287
- package/src/utils/config.ts +0 -375
- package/src/utils/display.ts +0 -338
- package/src/utils/files.ts +0 -418
- package/src/utils/nlp.ts +0 -312
- package/src/utils/ui.ts +0 -441
- package/src/utils/updates.ts +0 -8
- package/src/utils/voice.ts +0 -323
- package/tsconfig.json +0 -26
package/src/commands/setup.ts
DELETED
|
@@ -1,600 +0,0 @@
|
|
|
1
|
-
import * as p from '@clack/prompts';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import boxen from 'boxen';
|
|
4
|
-
import open from 'open';
|
|
5
|
-
import { Config } from '../utils/config.js';
|
|
6
|
-
|
|
7
|
-
// ============================================================================
|
|
8
|
-
// SERVICE DEFINITIONS
|
|
9
|
-
// ============================================================================
|
|
10
|
-
|
|
11
|
-
interface ServiceDef {
|
|
12
|
-
key: string;
|
|
13
|
-
name: string;
|
|
14
|
-
description: string;
|
|
15
|
-
whyNeeded: string;
|
|
16
|
-
url: string;
|
|
17
|
-
steps: string[]; // Step-by-step instructions
|
|
18
|
-
fields: Array<{
|
|
19
|
-
key: string;
|
|
20
|
-
label: string;
|
|
21
|
-
placeholder: string;
|
|
22
|
-
hint?: string;
|
|
23
|
-
validate?: (v: string) => string | undefined;
|
|
24
|
-
}>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const SERVICES: Record<string, ServiceDef> = {
|
|
28
|
-
anthropic: {
|
|
29
|
-
key: 'anthropic',
|
|
30
|
-
name: 'Anthropic (Claude)',
|
|
31
|
-
description: 'Powers the AI coding agent',
|
|
32
|
-
whyNeeded: 'This is REQUIRED. Without it, CodeBakers cannot generate any code.',
|
|
33
|
-
url: 'https://console.anthropic.com/settings/keys',
|
|
34
|
-
steps: [
|
|
35
|
-
'Sign up or log in to Anthropic Console',
|
|
36
|
-
'Click "Create Key"',
|
|
37
|
-
'Give it a name like "CodeBakers"',
|
|
38
|
-
'Copy the key (starts with sk-ant-)',
|
|
39
|
-
],
|
|
40
|
-
fields: [{
|
|
41
|
-
key: 'apiKey',
|
|
42
|
-
label: 'Paste your Anthropic API Key',
|
|
43
|
-
placeholder: 'sk-ant-...',
|
|
44
|
-
hint: 'Starts with sk-ant-',
|
|
45
|
-
validate: (v) => {
|
|
46
|
-
if (!v) return 'API key is required';
|
|
47
|
-
if (!v.startsWith('sk-ant-')) return 'Should start with sk-ant-';
|
|
48
|
-
return undefined;
|
|
49
|
-
},
|
|
50
|
-
}],
|
|
51
|
-
},
|
|
52
|
-
github: {
|
|
53
|
-
key: 'github',
|
|
54
|
-
name: 'GitHub',
|
|
55
|
-
description: 'Create repos and push code',
|
|
56
|
-
whyNeeded: 'Needed to create repositories and save your code. Skip if you\'ll manage git manually.',
|
|
57
|
-
url: 'https://github.com/settings/tokens/new?scopes=repo,user&description=CodeBakers',
|
|
58
|
-
steps: [
|
|
59
|
-
'Log in to GitHub',
|
|
60
|
-
'The "repo" and "user" boxes should already be checked',
|
|
61
|
-
'Scroll down and click "Generate token"',
|
|
62
|
-
'Copy the token (starts with ghp_)',
|
|
63
|
-
],
|
|
64
|
-
fields: [{
|
|
65
|
-
key: 'token',
|
|
66
|
-
label: 'Paste your GitHub Token',
|
|
67
|
-
placeholder: 'ghp_...',
|
|
68
|
-
hint: 'Starts with ghp_ or github_pat_',
|
|
69
|
-
validate: (v) => {
|
|
70
|
-
if (!v) return 'Token is required';
|
|
71
|
-
if (!v.startsWith('ghp_') && !v.startsWith('github_pat_')) {
|
|
72
|
-
return 'Should start with ghp_ or github_pat_';
|
|
73
|
-
}
|
|
74
|
-
return undefined;
|
|
75
|
-
},
|
|
76
|
-
}],
|
|
77
|
-
},
|
|
78
|
-
vercel: {
|
|
79
|
-
key: 'vercel',
|
|
80
|
-
name: 'Vercel',
|
|
81
|
-
description: 'Deploy your apps to production',
|
|
82
|
-
whyNeeded: 'Needed to deploy apps automatically. Skip if you\'ll deploy manually.',
|
|
83
|
-
url: 'https://vercel.com/account/tokens',
|
|
84
|
-
steps: [
|
|
85
|
-
'Log in to Vercel',
|
|
86
|
-
'Click "Create" button',
|
|
87
|
-
'Name it "CodeBakers"',
|
|
88
|
-
'Click "Create Token"',
|
|
89
|
-
'Copy the token',
|
|
90
|
-
],
|
|
91
|
-
fields: [{
|
|
92
|
-
key: 'token',
|
|
93
|
-
label: 'Paste your Vercel Token',
|
|
94
|
-
placeholder: 'vercel_...',
|
|
95
|
-
hint: 'The token you just created',
|
|
96
|
-
}],
|
|
97
|
-
},
|
|
98
|
-
supabase: {
|
|
99
|
-
key: 'supabase',
|
|
100
|
-
name: 'Supabase',
|
|
101
|
-
description: 'Database and authentication',
|
|
102
|
-
whyNeeded: 'Needed for database features. Skip if you\'ll set up databases manually.',
|
|
103
|
-
url: 'https://supabase.com/dashboard/account/tokens',
|
|
104
|
-
steps: [
|
|
105
|
-
'Log in to Supabase',
|
|
106
|
-
'Click "Generate new token"',
|
|
107
|
-
'Name it "CodeBakers"',
|
|
108
|
-
'Copy the token',
|
|
109
|
-
],
|
|
110
|
-
fields: [{
|
|
111
|
-
key: 'accessToken',
|
|
112
|
-
label: 'Paste your Supabase Token',
|
|
113
|
-
placeholder: 'sbp_...',
|
|
114
|
-
hint: 'Starts with sbp_',
|
|
115
|
-
}],
|
|
116
|
-
},
|
|
117
|
-
openai: {
|
|
118
|
-
key: 'openai',
|
|
119
|
-
name: 'OpenAI',
|
|
120
|
-
description: 'GPT models, embeddings, DALL-E',
|
|
121
|
-
whyNeeded: 'Optional. Only if you want to use OpenAI alongside Claude.',
|
|
122
|
-
url: 'https://platform.openai.com/api-keys',
|
|
123
|
-
steps: [
|
|
124
|
-
'Log in to OpenAI',
|
|
125
|
-
'Click "Create new secret key"',
|
|
126
|
-
'Copy the key',
|
|
127
|
-
],
|
|
128
|
-
fields: [{
|
|
129
|
-
key: 'apiKey',
|
|
130
|
-
label: 'Paste your OpenAI API Key',
|
|
131
|
-
placeholder: 'sk-...',
|
|
132
|
-
}],
|
|
133
|
-
},
|
|
134
|
-
stripe: {
|
|
135
|
-
key: 'stripe',
|
|
136
|
-
name: 'Stripe',
|
|
137
|
-
description: 'Payment processing',
|
|
138
|
-
whyNeeded: 'Optional. Only if your app accepts payments.',
|
|
139
|
-
url: 'https://dashboard.stripe.com/apikeys',
|
|
140
|
-
steps: [
|
|
141
|
-
'Log in to Stripe',
|
|
142
|
-
'Copy your Secret key (starts with sk_)',
|
|
143
|
-
],
|
|
144
|
-
fields: [{
|
|
145
|
-
key: 'secretKey',
|
|
146
|
-
label: 'Paste your Stripe Secret Key',
|
|
147
|
-
placeholder: 'sk_live_... or sk_test_...',
|
|
148
|
-
}],
|
|
149
|
-
},
|
|
150
|
-
twilio: {
|
|
151
|
-
key: 'twilio',
|
|
152
|
-
name: 'Twilio',
|
|
153
|
-
description: 'SMS, voice calls, WhatsApp',
|
|
154
|
-
whyNeeded: 'Optional. Only if your app sends SMS or makes calls.',
|
|
155
|
-
url: 'https://console.twilio.com/',
|
|
156
|
-
steps: [
|
|
157
|
-
'Log in to Twilio',
|
|
158
|
-
'Find Account SID on the dashboard',
|
|
159
|
-
'Find Auth Token on the dashboard',
|
|
160
|
-
],
|
|
161
|
-
fields: [
|
|
162
|
-
{
|
|
163
|
-
key: 'accountSid',
|
|
164
|
-
label: 'Account SID',
|
|
165
|
-
placeholder: 'AC...',
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
key: 'authToken',
|
|
169
|
-
label: 'Auth Token',
|
|
170
|
-
placeholder: '...',
|
|
171
|
-
},
|
|
172
|
-
],
|
|
173
|
-
},
|
|
174
|
-
resend: {
|
|
175
|
-
key: 'resend',
|
|
176
|
-
name: 'Resend',
|
|
177
|
-
description: 'Email sending',
|
|
178
|
-
whyNeeded: 'Optional. Only if your app sends emails.',
|
|
179
|
-
url: 'https://resend.com/api-keys',
|
|
180
|
-
steps: [
|
|
181
|
-
'Log in to Resend',
|
|
182
|
-
'Click "Create API Key"',
|
|
183
|
-
'Copy the key',
|
|
184
|
-
],
|
|
185
|
-
fields: [{
|
|
186
|
-
key: 'apiKey',
|
|
187
|
-
label: 'Paste your Resend API Key',
|
|
188
|
-
placeholder: 're_...',
|
|
189
|
-
}],
|
|
190
|
-
},
|
|
191
|
-
vapi: {
|
|
192
|
-
key: 'vapi',
|
|
193
|
-
name: 'VAPI',
|
|
194
|
-
description: 'Voice AI agents',
|
|
195
|
-
whyNeeded: 'Optional. Only if you\'re building voice agents.',
|
|
196
|
-
url: 'https://dashboard.vapi.ai/',
|
|
197
|
-
steps: [
|
|
198
|
-
'Log in to VAPI',
|
|
199
|
-
'Go to Settings > API Keys',
|
|
200
|
-
'Copy your API key',
|
|
201
|
-
],
|
|
202
|
-
fields: [{
|
|
203
|
-
key: 'apiKey',
|
|
204
|
-
label: 'Paste your VAPI API Key',
|
|
205
|
-
placeholder: '...',
|
|
206
|
-
}],
|
|
207
|
-
},
|
|
208
|
-
elevenlabs: {
|
|
209
|
-
key: 'elevenlabs',
|
|
210
|
-
name: 'ElevenLabs',
|
|
211
|
-
description: 'AI voice generation',
|
|
212
|
-
whyNeeded: 'Optional. Only if you want AI-generated voices.',
|
|
213
|
-
url: 'https://elevenlabs.io/app/settings/api-keys',
|
|
214
|
-
steps: [
|
|
215
|
-
'Log in to ElevenLabs',
|
|
216
|
-
'Click "Create API Key"',
|
|
217
|
-
'Copy the key',
|
|
218
|
-
],
|
|
219
|
-
fields: [{
|
|
220
|
-
key: 'apiKey',
|
|
221
|
-
label: 'Paste your ElevenLabs API Key',
|
|
222
|
-
placeholder: '...',
|
|
223
|
-
}],
|
|
224
|
-
},
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
const CORE_SERVICES = ['anthropic', 'github', 'vercel', 'supabase'];
|
|
228
|
-
const OPTIONAL_SERVICES = ['openai', 'stripe', 'twilio', 'resend', 'vapi', 'elevenlabs'];
|
|
229
|
-
|
|
230
|
-
// ============================================================================
|
|
231
|
-
// MAIN SETUP COMMAND
|
|
232
|
-
// ============================================================================
|
|
233
|
-
|
|
234
|
-
export async function setupCommand(): Promise<void> {
|
|
235
|
-
const config = new Config();
|
|
236
|
-
|
|
237
|
-
// Check if already configured
|
|
238
|
-
const hasAnthropic = !!config.getCredentials('anthropic')?.apiKey;
|
|
239
|
-
|
|
240
|
-
if (hasAnthropic) {
|
|
241
|
-
// Already has minimum setup - show management menu
|
|
242
|
-
await showManagementMenu(config);
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// =========================================================================
|
|
247
|
-
// FIRST TIME SETUP - Step by step with clear instructions
|
|
248
|
-
// =========================================================================
|
|
249
|
-
|
|
250
|
-
console.log(boxen(
|
|
251
|
-
chalk.bold.cyan('Welcome to CodeBakers Setup!\n\n') +
|
|
252
|
-
chalk.white('We need to connect a few services to get started.\n\n') +
|
|
253
|
-
chalk.dim('Your credentials are stored locally on your computer\n') +
|
|
254
|
-
chalk.dim('in ~/.codebakers/ and never sent to our servers.\n\n') +
|
|
255
|
-
chalk.yellow('Required: ') + chalk.white('Anthropic API key (for AI)\n') +
|
|
256
|
-
chalk.dim('Optional: GitHub, Vercel, Supabase (for full features)'),
|
|
257
|
-
{ padding: 1, borderColor: 'cyan', borderStyle: 'round' }
|
|
258
|
-
));
|
|
259
|
-
|
|
260
|
-
// STEP 1: Anthropic (REQUIRED)
|
|
261
|
-
console.log(chalk.bold.cyan('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
262
|
-
console.log(chalk.bold.cyan(' STEP 1 of 4: Anthropic API Key (Required)'));
|
|
263
|
-
console.log(chalk.bold.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
264
|
-
|
|
265
|
-
console.log(chalk.white(' Anthropic (Claude)'));
|
|
266
|
-
console.log(chalk.dim(' Powers the AI coding agent\n'));
|
|
267
|
-
|
|
268
|
-
// Check if they have an account
|
|
269
|
-
const hasAccount = await p.select({
|
|
270
|
-
message: 'Do you have an Anthropic account?',
|
|
271
|
-
options: [
|
|
272
|
-
{ value: 'yes', label: '✓ Yes, I have an API key ready' },
|
|
273
|
-
{ value: 'no', label: '✗ No, I need to sign up (free)' },
|
|
274
|
-
],
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
if (p.isCancel(hasAccount)) {
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (hasAccount === 'no') {
|
|
282
|
-
console.log(chalk.yellow('\n No problem! Let\'s get you signed up.\n'));
|
|
283
|
-
console.log(chalk.white(' Steps:'));
|
|
284
|
-
console.log(chalk.cyan(' 1. ') + 'Click "Sign Up" on the page that opens');
|
|
285
|
-
console.log(chalk.cyan(' 2. ') + 'Create your account (email + password)');
|
|
286
|
-
console.log(chalk.cyan(' 3. ') + 'Once logged in, go to Settings → API Keys');
|
|
287
|
-
console.log(chalk.cyan(' 4. ') + 'Click "Create Key"');
|
|
288
|
-
console.log(chalk.cyan(' 5. ') + 'Copy the key and paste it here\n');
|
|
289
|
-
|
|
290
|
-
const openSignup = await p.confirm({
|
|
291
|
-
message: 'Open Anthropic signup page?',
|
|
292
|
-
initialValue: true,
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
if (openSignup && !p.isCancel(openSignup)) {
|
|
296
|
-
await open('https://console.anthropic.com/');
|
|
297
|
-
console.log(chalk.dim('\n Take your time - come back when you have your API key.\n'));
|
|
298
|
-
}
|
|
299
|
-
} else {
|
|
300
|
-
// They have an account, show regular instructions
|
|
301
|
-
console.log(chalk.bold.white('\n Here\'s what to do:\n'));
|
|
302
|
-
console.log(chalk.cyan(' 1. ') + 'Log in to Anthropic Console');
|
|
303
|
-
console.log(chalk.cyan(' 2. ') + 'Go to Settings → API Keys');
|
|
304
|
-
console.log(chalk.cyan(' 3. ') + 'Click "Create Key"');
|
|
305
|
-
console.log(chalk.cyan(' 4. ') + 'Copy the key (starts with sk-ant-)');
|
|
306
|
-
console.log('');
|
|
307
|
-
|
|
308
|
-
const openBrowser = await p.confirm({
|
|
309
|
-
message: 'Open Anthropic Console?',
|
|
310
|
-
initialValue: true,
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
if (openBrowser && !p.isCancel(openBrowser)) {
|
|
314
|
-
await open('https://console.anthropic.com/settings/keys');
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Now collect the API key
|
|
319
|
-
console.log('');
|
|
320
|
-
const apiKey = await p.text({
|
|
321
|
-
message: 'Paste your Anthropic API Key:',
|
|
322
|
-
placeholder: 'sk-ant-...',
|
|
323
|
-
validate: (v) => {
|
|
324
|
-
if (!v) return 'API key is required';
|
|
325
|
-
if (!v.startsWith('sk-ant-')) return 'Should start with sk-ant-';
|
|
326
|
-
return undefined;
|
|
327
|
-
},
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
if (p.isCancel(apiKey) || !apiKey) {
|
|
331
|
-
console.log(chalk.red('\n ❌ Anthropic API key is required to use CodeBakers.'));
|
|
332
|
-
console.log(chalk.dim(' Run `codebakers setup` when you\'re ready to try again.\n'));
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
config.setCredentials('anthropic', { apiKey: apiKey as string });
|
|
337
|
-
console.log(chalk.green('\n ✓ Anthropic connected successfully!\n'));
|
|
338
|
-
|
|
339
|
-
// STEP 2: GitHub (Optional but recommended)
|
|
340
|
-
console.log(chalk.bold.cyan('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
341
|
-
console.log(chalk.bold.cyan(' STEP 2 of 4: GitHub Token (Recommended)'));
|
|
342
|
-
console.log(chalk.bold.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
343
|
-
|
|
344
|
-
await connectServiceWithInstructions(config, SERVICES.github, false);
|
|
345
|
-
|
|
346
|
-
// STEP 3: Vercel (Optional but recommended)
|
|
347
|
-
console.log(chalk.bold.cyan('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
348
|
-
console.log(chalk.bold.cyan(' STEP 3 of 4: Vercel Token (Recommended)'));
|
|
349
|
-
console.log(chalk.bold.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
350
|
-
|
|
351
|
-
await connectServiceWithInstructions(config, SERVICES.vercel, false);
|
|
352
|
-
|
|
353
|
-
// STEP 4: Supabase (Optional)
|
|
354
|
-
console.log(chalk.bold.cyan('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
355
|
-
console.log(chalk.bold.cyan(' STEP 4 of 4: Supabase Token (Optional)'));
|
|
356
|
-
console.log(chalk.bold.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
357
|
-
|
|
358
|
-
await connectServiceWithInstructions(config, SERVICES.supabase, false);
|
|
359
|
-
|
|
360
|
-
// =========================================================================
|
|
361
|
-
// SETUP COMPLETE - Show what to do next
|
|
362
|
-
// =========================================================================
|
|
363
|
-
|
|
364
|
-
const connectedServices = CORE_SERVICES.filter(key => config.getCredentials(key)).map(key => SERVICES[key].name);
|
|
365
|
-
|
|
366
|
-
console.log(boxen(
|
|
367
|
-
chalk.bold.green('✓ Setup Complete!\n\n') +
|
|
368
|
-
chalk.white('Connected: ') + chalk.cyan(connectedServices.join(', ')) + '\n\n' +
|
|
369
|
-
chalk.bold.white('What to do next:\n\n') +
|
|
370
|
-
chalk.cyan('1. ') + chalk.white('Open a terminal and navigate to where you want to build:\n') +
|
|
371
|
-
chalk.dim(' cd C:\\dev\\my-project\n') +
|
|
372
|
-
chalk.dim(' (or any folder where you want to create your project)\n\n') +
|
|
373
|
-
chalk.cyan('2. ') + chalk.white('Run CodeBakers:\n') +
|
|
374
|
-
chalk.dim(' codebakers\n\n') +
|
|
375
|
-
chalk.bold.white('Or try these commands directly:\n\n') +
|
|
376
|
-
chalk.dim(' codebakers website ') + chalk.white('Build a website by describing it\n') +
|
|
377
|
-
chalk.dim(' codebakers init ') + chalk.white('Create a new project from scratch\n') +
|
|
378
|
-
chalk.dim(' codebakers help ') + chalk.white('See all available commands'),
|
|
379
|
-
{ padding: 1, borderColor: 'green', borderStyle: 'round' }
|
|
380
|
-
));
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// ============================================================================
|
|
384
|
-
// CONNECT SERVICE WITH DETAILED INSTRUCTIONS
|
|
385
|
-
// ============================================================================
|
|
386
|
-
|
|
387
|
-
async function connectServiceWithInstructions(
|
|
388
|
-
config: Config,
|
|
389
|
-
service: ServiceDef,
|
|
390
|
-
required: boolean
|
|
391
|
-
): Promise<boolean> {
|
|
392
|
-
|
|
393
|
-
// Show what this service does
|
|
394
|
-
console.log(chalk.white(` ${service.name}`));
|
|
395
|
-
console.log(chalk.dim(` ${service.description}\n`));
|
|
396
|
-
|
|
397
|
-
if (!required) {
|
|
398
|
-
console.log(chalk.yellow(` ${service.whyNeeded}\n`));
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Ask if they want to connect or skip
|
|
402
|
-
const action = await p.select({
|
|
403
|
-
message: `Connect ${service.name}?`,
|
|
404
|
-
options: required ? [
|
|
405
|
-
{ value: 'connect', label: '✓ Yes, let\'s connect it' },
|
|
406
|
-
] : [
|
|
407
|
-
{ value: 'connect', label: '✓ Yes, connect it' },
|
|
408
|
-
{ value: 'skip', label: '→ Skip for now' },
|
|
409
|
-
],
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
if (p.isCancel(action) || action === 'skip') {
|
|
413
|
-
if (!required) {
|
|
414
|
-
console.log(chalk.dim(`\n Skipped ${service.name}. You can add it later with: codebakers setup\n`));
|
|
415
|
-
}
|
|
416
|
-
return false;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// Show step-by-step instructions
|
|
420
|
-
console.log(chalk.bold.white('\n Here\'s what to do:\n'));
|
|
421
|
-
service.steps.forEach((step, i) => {
|
|
422
|
-
console.log(chalk.cyan(` ${i + 1}. `) + chalk.white(step));
|
|
423
|
-
});
|
|
424
|
-
console.log('');
|
|
425
|
-
|
|
426
|
-
// Ask to open browser
|
|
427
|
-
const openBrowser = await p.confirm({
|
|
428
|
-
message: 'Open the website in your browser?',
|
|
429
|
-
initialValue: true,
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
if (openBrowser && !p.isCancel(openBrowser)) {
|
|
433
|
-
console.log(chalk.dim(`\n Opening: ${service.url}\n`));
|
|
434
|
-
await open(service.url);
|
|
435
|
-
|
|
436
|
-
// Give user time to get the key
|
|
437
|
-
console.log(chalk.dim(' Complete the steps above, then paste your key below.\n'));
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// Collect credentials
|
|
441
|
-
const credentials: Record<string, string> = {};
|
|
442
|
-
|
|
443
|
-
for (const field of service.fields) {
|
|
444
|
-
const value = await p.text({
|
|
445
|
-
message: field.label + (field.hint ? chalk.dim(` (${field.hint})`) : '') + ':',
|
|
446
|
-
placeholder: field.placeholder,
|
|
447
|
-
validate: field.validate,
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
if (p.isCancel(value)) return false;
|
|
451
|
-
|
|
452
|
-
if (!value) {
|
|
453
|
-
if (required) {
|
|
454
|
-
console.log(chalk.red(`\n ${field.label} is required.\n`));
|
|
455
|
-
return false;
|
|
456
|
-
}
|
|
457
|
-
console.log(chalk.dim(`\n Skipped ${service.name}.\n`));
|
|
458
|
-
return false;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
credentials[field.key] = value as string;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// Save credentials
|
|
465
|
-
config.setCredentials(service.key, credentials);
|
|
466
|
-
console.log(chalk.green(`\n ✓ ${service.name} connected successfully!\n`));
|
|
467
|
-
|
|
468
|
-
return true;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// ============================================================================
|
|
472
|
-
// MANAGEMENT MENU (for already-configured users)
|
|
473
|
-
// ============================================================================
|
|
474
|
-
|
|
475
|
-
async function showManagementMenu(config: Config): Promise<void> {
|
|
476
|
-
// Show current status
|
|
477
|
-
console.log(chalk.bold.cyan('\n CodeBakers Settings\n'));
|
|
478
|
-
|
|
479
|
-
const allServices = [...CORE_SERVICES, ...OPTIONAL_SERVICES];
|
|
480
|
-
const connected = allServices.filter(key => config.getCredentials(key));
|
|
481
|
-
const notConnected = allServices.filter(key => !config.getCredentials(key));
|
|
482
|
-
|
|
483
|
-
console.log(chalk.green(' Connected:'));
|
|
484
|
-
connected.forEach(key => {
|
|
485
|
-
console.log(chalk.green(` ✓ ${SERVICES[key].name}`));
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
if (notConnected.length > 0) {
|
|
489
|
-
console.log(chalk.dim('\n Not connected:'));
|
|
490
|
-
notConnected.forEach(key => {
|
|
491
|
-
console.log(chalk.dim(` ○ ${SERVICES[key].name}`));
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
console.log('');
|
|
495
|
-
|
|
496
|
-
const action = await p.select({
|
|
497
|
-
message: 'What would you like to do?',
|
|
498
|
-
options: [
|
|
499
|
-
{ value: 'add', label: '➕ Add a service' },
|
|
500
|
-
{ value: 'update', label: '🔄 Update a service' },
|
|
501
|
-
{ value: 'reset', label: '🗑️ Reset all settings' },
|
|
502
|
-
{ value: 'back', label: '← Back' },
|
|
503
|
-
],
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
if (p.isCancel(action) || action === 'back') {
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
switch (action) {
|
|
511
|
-
case 'add':
|
|
512
|
-
await addService(config);
|
|
513
|
-
break;
|
|
514
|
-
case 'update':
|
|
515
|
-
await updateService(config);
|
|
516
|
-
break;
|
|
517
|
-
case 'reset':
|
|
518
|
-
await resetConfig(config);
|
|
519
|
-
break;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
// ============================================================================
|
|
524
|
-
// ADD SERVICE
|
|
525
|
-
// ============================================================================
|
|
526
|
-
|
|
527
|
-
async function addService(config: Config): Promise<void> {
|
|
528
|
-
const allServices = [...CORE_SERVICES, ...OPTIONAL_SERVICES];
|
|
529
|
-
const unconnected = allServices.filter(key => !config.getCredentials(key));
|
|
530
|
-
|
|
531
|
-
if (unconnected.length === 0) {
|
|
532
|
-
console.log(chalk.green('\n All services are already connected!\n'));
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
const selected = await p.select({
|
|
537
|
-
message: 'Select service to add:',
|
|
538
|
-
options: unconnected.map(key => ({
|
|
539
|
-
value: key,
|
|
540
|
-
label: `${SERVICES[key].name} - ${SERVICES[key].description}`,
|
|
541
|
-
})),
|
|
542
|
-
});
|
|
543
|
-
|
|
544
|
-
if (p.isCancel(selected)) return;
|
|
545
|
-
|
|
546
|
-
await connectServiceWithInstructions(config, SERVICES[selected as string], false);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// ============================================================================
|
|
550
|
-
// UPDATE SERVICE
|
|
551
|
-
// ============================================================================
|
|
552
|
-
|
|
553
|
-
async function updateService(config: Config): Promise<void> {
|
|
554
|
-
const allServices = [...CORE_SERVICES, ...OPTIONAL_SERVICES];
|
|
555
|
-
const connected = allServices.filter(key => config.getCredentials(key));
|
|
556
|
-
|
|
557
|
-
if (connected.length === 0) {
|
|
558
|
-
console.log(chalk.yellow('\n No services connected yet.\n'));
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
const selected = await p.select({
|
|
563
|
-
message: 'Select service to update:',
|
|
564
|
-
options: connected.map(key => ({
|
|
565
|
-
value: key,
|
|
566
|
-
label: SERVICES[key].name,
|
|
567
|
-
})),
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
if (p.isCancel(selected)) return;
|
|
571
|
-
|
|
572
|
-
await connectServiceWithInstructions(config, SERVICES[selected as string], false);
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// ============================================================================
|
|
576
|
-
// RESET CONFIG
|
|
577
|
-
// ============================================================================
|
|
578
|
-
|
|
579
|
-
async function resetConfig(config: Config): Promise<void> {
|
|
580
|
-
console.log(chalk.yellow('\n ⚠️ This will remove ALL your saved API keys.\n'));
|
|
581
|
-
|
|
582
|
-
const confirm = await p.confirm({
|
|
583
|
-
message: 'Are you sure?',
|
|
584
|
-
initialValue: false,
|
|
585
|
-
});
|
|
586
|
-
|
|
587
|
-
if (!confirm || p.isCancel(confirm)) {
|
|
588
|
-
console.log(chalk.dim('\n Cancelled.\n'));
|
|
589
|
-
return;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
// Clear all credentials
|
|
593
|
-
const allServices = [...CORE_SERVICES, ...OPTIONAL_SERVICES];
|
|
594
|
-
for (const key of allServices) {
|
|
595
|
-
config.setCredentials(key, null as any);
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
console.log(chalk.green('\n ✓ All settings reset.\n'));
|
|
599
|
-
console.log(chalk.dim(' Run `codebakers setup` to configure again.\n'));
|
|
600
|
-
}
|
package/src/commands/status.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// src/commands/status.ts
|
|
2
|
-
import * as p from '@clack/prompts';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import fs from 'fs-extra';
|
|
5
|
-
import * as path from 'path';
|
|
6
|
-
import { Config } from '../utils/config.js';
|
|
7
|
-
|
|
8
|
-
export async function statusCommand(): Promise<void> {
|
|
9
|
-
const config = new Config();
|
|
10
|
-
const cwd = process.cwd();
|
|
11
|
-
|
|
12
|
-
p.intro(chalk.bgCyan.black(' Project Status '));
|
|
13
|
-
|
|
14
|
-
if (!config.isInProject()) {
|
|
15
|
-
// Show all projects
|
|
16
|
-
const projects = config.getProjects();
|
|
17
|
-
|
|
18
|
-
if (projects.length === 0) {
|
|
19
|
-
p.log.info('No projects found. Run `codebakers init` to create one.');
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
console.log(chalk.bold('\nYour Projects:\n'));
|
|
24
|
-
|
|
25
|
-
for (const project of projects) {
|
|
26
|
-
const exists = await fs.pathExists(project.path);
|
|
27
|
-
const status = exists ? chalk.green('✓') : chalk.red('✗');
|
|
28
|
-
console.log(` ${status} ${project.name}`);
|
|
29
|
-
console.log(chalk.dim(` ${project.path}`));
|
|
30
|
-
console.log('');
|
|
31
|
-
}
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Show current project status
|
|
36
|
-
const projectConfig = await fs.readJson(
|
|
37
|
-
path.join(cwd, '.codebakers', 'config.json')
|
|
38
|
-
).catch(() => ({}));
|
|
39
|
-
|
|
40
|
-
const packageJson = await fs.readJson(
|
|
41
|
-
path.join(cwd, 'package.json')
|
|
42
|
-
).catch(() => ({}));
|
|
43
|
-
|
|
44
|
-
console.log(`
|
|
45
|
-
${chalk.bold('Project:')} ${packageJson.name || path.basename(cwd)}
|
|
46
|
-
${chalk.bold('Framework:')} ${projectConfig.framework || 'unknown'}
|
|
47
|
-
${chalk.bold('UI:')} ${projectConfig.ui || 'unknown'}
|
|
48
|
-
|
|
49
|
-
${chalk.bold('Quick Actions:')}
|
|
50
|
-
${chalk.cyan('codebakers code')} — AI coding agent
|
|
51
|
-
${chalk.cyan('codebakers check')} — Pattern enforcement
|
|
52
|
-
${chalk.cyan('codebakers deploy')} — Deploy to production
|
|
53
|
-
`);
|
|
54
|
-
|
|
55
|
-
p.outro('');
|
|
56
|
-
}
|