codebakers 1.0.45 → 2.0.1
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 +275 -60
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4260 -0
- package/install.bat +9 -0
- package/package.json +71 -115
- package/src/channels/discord.ts +5 -0
- package/src/channels/slack.ts +5 -0
- package/src/channels/sms.ts +4 -0
- package/src/channels/telegram.ts +5 -0
- package/src/channels/whatsapp.ts +7 -0
- package/src/commands/check.ts +365 -0
- package/src/commands/code.ts +684 -0
- package/src/commands/connect.ts +12 -0
- package/src/commands/deploy.ts +414 -0
- package/src/commands/design.ts +298 -0
- package/src/commands/fix.ts +20 -0
- package/src/commands/gateway.ts +604 -0
- package/src/commands/generate.ts +178 -0
- package/src/commands/init.ts +574 -0
- package/src/commands/learn.ts +36 -0
- package/src/commands/security.ts +102 -0
- package/src/commands/setup.ts +448 -0
- package/src/commands/status.ts +56 -0
- package/src/index.ts +278 -0
- package/src/patterns/loader.ts +337 -0
- package/src/services/github.ts +61 -0
- package/src/services/supabase.ts +147 -0
- package/src/services/vercel.ts +61 -0
- package/src/utils/claude-md.ts +287 -0
- package/src/utils/config.ts +282 -0
- package/src/utils/updates.ts +27 -0
- package/tsconfig.json +17 -10
- package/.vscodeignore +0 -18
- package/LICENSE +0 -21
- package/codebakers-1.0.0.vsix +0 -0
- package/codebakers-1.0.10.vsix +0 -0
- package/codebakers-1.0.11.vsix +0 -0
- package/codebakers-1.0.12.vsix +0 -0
- package/codebakers-1.0.13.vsix +0 -0
- package/codebakers-1.0.14.vsix +0 -0
- package/codebakers-1.0.15.vsix +0 -0
- package/codebakers-1.0.16.vsix +0 -0
- package/codebakers-1.0.17.vsix +0 -0
- package/codebakers-1.0.18.vsix +0 -0
- package/codebakers-1.0.19.vsix +0 -0
- package/codebakers-1.0.20.vsix +0 -0
- package/codebakers-1.0.21.vsix +0 -0
- package/codebakers-1.0.22.vsix +0 -0
- package/codebakers-1.0.23.vsix +0 -0
- package/codebakers-1.0.24.vsix +0 -0
- package/codebakers-1.0.25.vsix +0 -0
- package/codebakers-1.0.26.vsix +0 -0
- package/codebakers-1.0.27.vsix +0 -0
- package/codebakers-1.0.28.vsix +0 -0
- package/codebakers-1.0.29.vsix +0 -0
- package/codebakers-1.0.30.vsix +0 -0
- package/codebakers-1.0.31.vsix +0 -0
- package/codebakers-1.0.32.vsix +0 -0
- package/codebakers-1.0.35.vsix +0 -0
- package/codebakers-1.0.36.vsix +0 -0
- package/codebakers-1.0.37.vsix +0 -0
- package/codebakers-1.0.38.vsix +0 -0
- package/codebakers-1.0.39.vsix +0 -0
- package/codebakers-1.0.40.vsix +0 -0
- package/codebakers-1.0.41.vsix +0 -0
- package/codebakers-1.0.42.vsix +0 -0
- package/codebakers-1.0.43.vsix +0 -0
- package/codebakers-1.0.44.vsix +0 -0
- package/codebakers-1.0.45.vsix +0 -0
- package/dist/extension.js +0 -1394
- package/esbuild.js +0 -63
- package/media/icon.png +0 -0
- package/media/icon.svg +0 -7
- package/nul +0 -1
- package/preview.html +0 -547
- package/src/ChatPanelProvider.ts +0 -1815
- package/src/ChatViewProvider.ts +0 -749
- package/src/CodeBakersClient.ts +0 -1146
- package/src/CodeValidator.ts +0 -645
- package/src/FileOperations.ts +0 -410
- package/src/ProjectContext.ts +0 -526
- package/src/extension.ts +0 -332
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import open from 'open';
|
|
4
|
+
import { Config } from '../utils/config.js';
|
|
5
|
+
|
|
6
|
+
export async function setupCommand(): Promise<void> {
|
|
7
|
+
const config = new Config();
|
|
8
|
+
|
|
9
|
+
p.intro(chalk.bgCyan.black(' CodeBakers Setup '));
|
|
10
|
+
|
|
11
|
+
// Check if already configured
|
|
12
|
+
if (config.isConfigured()) {
|
|
13
|
+
const action = await p.select({
|
|
14
|
+
message: 'CodeBakers is already configured. What do you want to do?',
|
|
15
|
+
options: [
|
|
16
|
+
{ value: 'view', label: '👀 View connected services' },
|
|
17
|
+
{ value: 'add', label: '➕ Add another service' },
|
|
18
|
+
{ value: 'update', label: '🔄 Update credentials' },
|
|
19
|
+
{ value: 'reset', label: '🗑️ Reset all configuration' },
|
|
20
|
+
{ value: 'back', label: '← Back' },
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (p.isCancel(action) || action === 'back') {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (action === 'view') {
|
|
29
|
+
showConnectedServices(config);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (action === 'reset') {
|
|
34
|
+
const confirm = await p.confirm({
|
|
35
|
+
message: 'Are you sure? This will remove all credentials and settings.',
|
|
36
|
+
});
|
|
37
|
+
if (confirm) {
|
|
38
|
+
// Reset config - in real implementation would clear the config
|
|
39
|
+
p.outro(chalk.yellow('Configuration reset. Run `codebakers setup` again.'));
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (action === 'add') {
|
|
45
|
+
await addService(config);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// First-time setup
|
|
51
|
+
p.note(
|
|
52
|
+
`Let's connect your accounts. This only takes a few minutes.
|
|
53
|
+
|
|
54
|
+
${chalk.dim('Your credentials are stored locally in ~/.codebakers/')}
|
|
55
|
+
${chalk.dim('and are never sent to our servers.')}`,
|
|
56
|
+
'Welcome to CodeBakers!'
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// Required services
|
|
60
|
+
const requiredServices = [
|
|
61
|
+
{ name: 'GitHub', key: 'github', required: true },
|
|
62
|
+
{ name: 'Vercel', key: 'vercel', required: true },
|
|
63
|
+
{ name: 'Supabase', key: 'supabase', required: true },
|
|
64
|
+
{ name: 'Anthropic (Claude)', key: 'anthropic', required: true },
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
// Optional services
|
|
68
|
+
const optionalServices = [
|
|
69
|
+
{ name: 'OpenAI', key: 'openai' },
|
|
70
|
+
{ name: 'Stripe', key: 'stripe' },
|
|
71
|
+
{ name: 'Twilio', key: 'twilio' },
|
|
72
|
+
{ name: 'VAPI', key: 'vapi' },
|
|
73
|
+
{ name: 'Resend', key: 'resend' },
|
|
74
|
+
{ name: 'ElevenLabs', key: 'elevenLabs' },
|
|
75
|
+
{ name: 'Microsoft Graph', key: 'microsoft' },
|
|
76
|
+
{ name: 'Google APIs', key: 'google' },
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
p.log.step('Connecting required services...');
|
|
80
|
+
|
|
81
|
+
// Connect required services
|
|
82
|
+
for (const service of requiredServices) {
|
|
83
|
+
await connectService(config, service.key, service.name, true);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Ask about optional services
|
|
87
|
+
const addOptional = await p.confirm({
|
|
88
|
+
message: 'Do you want to connect optional services? (Stripe, Twilio, etc.)',
|
|
89
|
+
initialValue: false,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (addOptional && !p.isCancel(addOptional)) {
|
|
93
|
+
const selected = await p.multiselect({
|
|
94
|
+
message: 'Select services to connect:',
|
|
95
|
+
options: optionalServices.map(s => ({
|
|
96
|
+
value: s.key,
|
|
97
|
+
label: s.name,
|
|
98
|
+
})),
|
|
99
|
+
required: false,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
if (!p.isCancel(selected)) {
|
|
103
|
+
for (const serviceKey of selected) {
|
|
104
|
+
const service = optionalServices.find(s => s.key === serviceKey);
|
|
105
|
+
if (service) {
|
|
106
|
+
await connectService(config, service.key, service.name, false);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Copy patterns
|
|
113
|
+
p.log.step('Installing CodeBakers patterns...');
|
|
114
|
+
await installPatterns(config);
|
|
115
|
+
|
|
116
|
+
p.outro(chalk.green('✓ Setup complete! Run `codebakers init` to create your first project.'));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function connectService(
|
|
120
|
+
config: Config,
|
|
121
|
+
serviceKey: string,
|
|
122
|
+
serviceName: string,
|
|
123
|
+
required: boolean
|
|
124
|
+
): Promise<boolean> {
|
|
125
|
+
const spinner = p.spinner();
|
|
126
|
+
|
|
127
|
+
switch (serviceKey) {
|
|
128
|
+
case 'github': {
|
|
129
|
+
p.log.info(`${chalk.bold('GitHub')} - Opens browser for OAuth authorization`);
|
|
130
|
+
|
|
131
|
+
const proceed = await p.confirm({
|
|
132
|
+
message: 'Open browser to authorize GitHub?',
|
|
133
|
+
initialValue: true,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (p.isCancel(proceed) || !proceed) {
|
|
137
|
+
if (required) {
|
|
138
|
+
p.log.warn('GitHub is required. Skipping for now.');
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// In real implementation, this would:
|
|
144
|
+
// 1. Start local server for OAuth callback
|
|
145
|
+
// 2. Open GitHub OAuth URL
|
|
146
|
+
// 3. Handle callback and save token
|
|
147
|
+
p.log.info(chalk.dim('Opening browser...'));
|
|
148
|
+
await open('https://github.com/login/oauth/authorize?client_id=YOUR_CLIENT_ID&scope=repo,user');
|
|
149
|
+
|
|
150
|
+
const token = await p.text({
|
|
151
|
+
message: 'Paste your GitHub token (or press Enter if OAuth completed):',
|
|
152
|
+
placeholder: 'ghp_...',
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (!p.isCancel(token) && token) {
|
|
156
|
+
config.setCredentials('github', { token: token as string });
|
|
157
|
+
p.log.success('GitHub connected!');
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
case 'vercel': {
|
|
164
|
+
p.log.info(`${chalk.bold('Vercel')} - Opens browser for OAuth authorization`);
|
|
165
|
+
|
|
166
|
+
const proceed = await p.confirm({
|
|
167
|
+
message: 'Open browser to authorize Vercel?',
|
|
168
|
+
initialValue: true,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
if (p.isCancel(proceed) || !proceed) {
|
|
172
|
+
if (required) {
|
|
173
|
+
p.log.warn('Vercel is required. Skipping for now.');
|
|
174
|
+
}
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
p.log.info(chalk.dim('Opening browser...'));
|
|
179
|
+
await open('https://vercel.com/account/tokens');
|
|
180
|
+
|
|
181
|
+
const token = await p.text({
|
|
182
|
+
message: 'Paste your Vercel token:',
|
|
183
|
+
placeholder: 'vercel_...',
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
if (!p.isCancel(token) && token) {
|
|
187
|
+
config.setCredentials('vercel', { token: token as string });
|
|
188
|
+
p.log.success('Vercel connected!');
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
case 'supabase': {
|
|
195
|
+
p.log.info(`${chalk.bold('Supabase')} - Opens browser for OAuth authorization`);
|
|
196
|
+
|
|
197
|
+
const proceed = await p.confirm({
|
|
198
|
+
message: 'Open browser to authorize Supabase?',
|
|
199
|
+
initialValue: true,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
if (p.isCancel(proceed) || !proceed) {
|
|
203
|
+
if (required) {
|
|
204
|
+
p.log.warn('Supabase is required. Skipping for now.');
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
p.log.info(chalk.dim('Opening browser...'));
|
|
210
|
+
await open('https://supabase.com/dashboard/account/tokens');
|
|
211
|
+
|
|
212
|
+
const token = await p.text({
|
|
213
|
+
message: 'Paste your Supabase access token:',
|
|
214
|
+
placeholder: 'sbp_...',
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
if (!p.isCancel(token) && token) {
|
|
218
|
+
config.setCredentials('supabase', { accessToken: token as string });
|
|
219
|
+
p.log.success('Supabase connected!');
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
case 'anthropic': {
|
|
226
|
+
p.log.info(`${chalk.bold('Anthropic (Claude)')} - Powers the AI coding agent`);
|
|
227
|
+
|
|
228
|
+
const openBrowser = await p.confirm({
|
|
229
|
+
message: 'Open browser to get API key?',
|
|
230
|
+
initialValue: true,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
if (openBrowser && !p.isCancel(openBrowser)) {
|
|
234
|
+
await open('https://console.anthropic.com/settings/keys');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const apiKey = await p.text({
|
|
238
|
+
message: 'Paste your Anthropic API key:',
|
|
239
|
+
placeholder: 'sk-ant-...',
|
|
240
|
+
validate: (value) => {
|
|
241
|
+
if (!value && required) return 'API key is required';
|
|
242
|
+
if (value && !value.startsWith('sk-ant-')) return 'Invalid API key format';
|
|
243
|
+
return undefined;
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if (!p.isCancel(apiKey) && apiKey) {
|
|
248
|
+
config.setCredentials('anthropic', { apiKey: apiKey as string });
|
|
249
|
+
p.log.success('Anthropic connected!');
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
case 'openai': {
|
|
256
|
+
const openBrowser = await p.confirm({
|
|
257
|
+
message: 'Open browser to get OpenAI API key?',
|
|
258
|
+
initialValue: true,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
if (openBrowser && !p.isCancel(openBrowser)) {
|
|
262
|
+
await open('https://platform.openai.com/api-keys');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const apiKey = await p.text({
|
|
266
|
+
message: 'Paste your OpenAI API key:',
|
|
267
|
+
placeholder: 'sk-...',
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
if (!p.isCancel(apiKey) && apiKey) {
|
|
271
|
+
config.setCredentials('openai', { apiKey: apiKey as string });
|
|
272
|
+
p.log.success('OpenAI connected!');
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
case 'stripe': {
|
|
279
|
+
const openBrowser = await p.confirm({
|
|
280
|
+
message: 'Open browser to get Stripe API keys?',
|
|
281
|
+
initialValue: true,
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
if (openBrowser && !p.isCancel(openBrowser)) {
|
|
285
|
+
await open('https://dashboard.stripe.com/apikeys');
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const secretKey = await p.text({
|
|
289
|
+
message: 'Paste your Stripe secret key:',
|
|
290
|
+
placeholder: 'sk_live_... or sk_test_...',
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
if (!p.isCancel(secretKey) && secretKey) {
|
|
294
|
+
config.setCredentials('stripe', { secretKey: secretKey as string });
|
|
295
|
+
p.log.success('Stripe connected!');
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
case 'twilio': {
|
|
302
|
+
const openBrowser = await p.confirm({
|
|
303
|
+
message: 'Open browser to get Twilio credentials?',
|
|
304
|
+
initialValue: true,
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
if (openBrowser && !p.isCancel(openBrowser)) {
|
|
308
|
+
await open('https://console.twilio.com/');
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const accountSid = await p.text({
|
|
312
|
+
message: 'Paste your Twilio Account SID:',
|
|
313
|
+
placeholder: 'AC...',
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const authToken = await p.text({
|
|
317
|
+
message: 'Paste your Twilio Auth Token:',
|
|
318
|
+
placeholder: '...',
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
if (!p.isCancel(accountSid) && !p.isCancel(authToken) && accountSid && authToken) {
|
|
322
|
+
config.setCredentials('twilio', {
|
|
323
|
+
accountSid: accountSid as string,
|
|
324
|
+
authToken: authToken as string
|
|
325
|
+
});
|
|
326
|
+
p.log.success('Twilio connected!');
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
case 'vapi': {
|
|
333
|
+
const openBrowser = await p.confirm({
|
|
334
|
+
message: 'Open browser to get VAPI API key?',
|
|
335
|
+
initialValue: true,
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
if (openBrowser && !p.isCancel(openBrowser)) {
|
|
339
|
+
await open('https://dashboard.vapi.ai/');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const apiKey = await p.text({
|
|
343
|
+
message: 'Paste your VAPI API key:',
|
|
344
|
+
placeholder: '...',
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
if (!p.isCancel(apiKey) && apiKey) {
|
|
348
|
+
config.setCredentials('vapi', { apiKey: apiKey as string });
|
|
349
|
+
p.log.success('VAPI connected!');
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
case 'resend': {
|
|
356
|
+
const openBrowser = await p.confirm({
|
|
357
|
+
message: 'Open browser to get Resend API key?',
|
|
358
|
+
initialValue: true,
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
if (openBrowser && !p.isCancel(openBrowser)) {
|
|
362
|
+
await open('https://resend.com/api-keys');
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const apiKey = await p.text({
|
|
366
|
+
message: 'Paste your Resend API key:',
|
|
367
|
+
placeholder: 're_...',
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
if (!p.isCancel(apiKey) && apiKey) {
|
|
371
|
+
config.setCredentials('resend', { apiKey: apiKey as string });
|
|
372
|
+
p.log.success('Resend connected!');
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
default:
|
|
379
|
+
p.log.warn(`Service ${serviceName} not yet implemented`);
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async function addService(config: Config): Promise<void> {
|
|
387
|
+
const services = [
|
|
388
|
+
{ value: 'github', label: 'GitHub' },
|
|
389
|
+
{ value: 'vercel', label: 'Vercel' },
|
|
390
|
+
{ value: 'supabase', label: 'Supabase' },
|
|
391
|
+
{ value: 'anthropic', label: 'Anthropic (Claude)' },
|
|
392
|
+
{ value: 'openai', label: 'OpenAI' },
|
|
393
|
+
{ value: 'stripe', label: 'Stripe' },
|
|
394
|
+
{ value: 'twilio', label: 'Twilio' },
|
|
395
|
+
{ value: 'vapi', label: 'VAPI' },
|
|
396
|
+
{ value: 'resend', label: 'Resend' },
|
|
397
|
+
{ value: 'elevenLabs', label: 'ElevenLabs' },
|
|
398
|
+
{ value: 'microsoft', label: 'Microsoft Graph' },
|
|
399
|
+
{ value: 'google', label: 'Google APIs' },
|
|
400
|
+
];
|
|
401
|
+
|
|
402
|
+
const service = await p.select({
|
|
403
|
+
message: 'Which service do you want to connect?',
|
|
404
|
+
options: services,
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
if (!p.isCancel(service)) {
|
|
408
|
+
const serviceInfo = services.find(s => s.value === service);
|
|
409
|
+
if (serviceInfo) {
|
|
410
|
+
await connectService(config, serviceInfo.value, serviceInfo.label, false);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function showConnectedServices(config: Config): void {
|
|
416
|
+
const services = [
|
|
417
|
+
{ key: 'github', name: 'GitHub' },
|
|
418
|
+
{ key: 'vercel', name: 'Vercel' },
|
|
419
|
+
{ key: 'supabase', name: 'Supabase' },
|
|
420
|
+
{ key: 'anthropic', name: 'Anthropic' },
|
|
421
|
+
{ key: 'openai', name: 'OpenAI' },
|
|
422
|
+
{ key: 'stripe', name: 'Stripe' },
|
|
423
|
+
{ key: 'twilio', name: 'Twilio' },
|
|
424
|
+
{ key: 'vapi', name: 'VAPI' },
|
|
425
|
+
{ key: 'resend', name: 'Resend' },
|
|
426
|
+
{ key: 'elevenLabs', name: 'ElevenLabs' },
|
|
427
|
+
{ key: 'microsoft', name: 'Microsoft' },
|
|
428
|
+
{ key: 'google', name: 'Google' },
|
|
429
|
+
];
|
|
430
|
+
|
|
431
|
+
console.log('\n' + chalk.bold('Connected Services:') + '\n');
|
|
432
|
+
|
|
433
|
+
for (const service of services) {
|
|
434
|
+
const creds = config.getCredentials(service.key);
|
|
435
|
+
const isConnected = creds && Object.values(creds).some(v => v);
|
|
436
|
+
const status = isConnected ? chalk.green('✓ Connected') : chalk.dim('○ Not connected');
|
|
437
|
+
console.log(` ${service.name.padEnd(15)} ${status}`);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
console.log('');
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
async function installPatterns(config: Config): Promise<void> {
|
|
444
|
+
// In real implementation, this would copy the pattern files
|
|
445
|
+
// from the bundled templates to ~/.codebakers/patterns/
|
|
446
|
+
const patternsDir = config.getPatternsDir();
|
|
447
|
+
p.log.info(chalk.dim(`Patterns installed to ${patternsDir}`));
|
|
448
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// src/commands/status.ts
|
|
2
|
+
import * as p from '@clack/prompts';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import * as 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
|
+
}
|