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.
Files changed (82) hide show
  1. package/README.md +275 -60
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +4260 -0
  4. package/install.bat +9 -0
  5. package/package.json +71 -115
  6. package/src/channels/discord.ts +5 -0
  7. package/src/channels/slack.ts +5 -0
  8. package/src/channels/sms.ts +4 -0
  9. package/src/channels/telegram.ts +5 -0
  10. package/src/channels/whatsapp.ts +7 -0
  11. package/src/commands/check.ts +365 -0
  12. package/src/commands/code.ts +684 -0
  13. package/src/commands/connect.ts +12 -0
  14. package/src/commands/deploy.ts +414 -0
  15. package/src/commands/design.ts +298 -0
  16. package/src/commands/fix.ts +20 -0
  17. package/src/commands/gateway.ts +604 -0
  18. package/src/commands/generate.ts +178 -0
  19. package/src/commands/init.ts +574 -0
  20. package/src/commands/learn.ts +36 -0
  21. package/src/commands/security.ts +102 -0
  22. package/src/commands/setup.ts +448 -0
  23. package/src/commands/status.ts +56 -0
  24. package/src/index.ts +278 -0
  25. package/src/patterns/loader.ts +337 -0
  26. package/src/services/github.ts +61 -0
  27. package/src/services/supabase.ts +147 -0
  28. package/src/services/vercel.ts +61 -0
  29. package/src/utils/claude-md.ts +287 -0
  30. package/src/utils/config.ts +282 -0
  31. package/src/utils/updates.ts +27 -0
  32. package/tsconfig.json +17 -10
  33. package/.vscodeignore +0 -18
  34. package/LICENSE +0 -21
  35. package/codebakers-1.0.0.vsix +0 -0
  36. package/codebakers-1.0.10.vsix +0 -0
  37. package/codebakers-1.0.11.vsix +0 -0
  38. package/codebakers-1.0.12.vsix +0 -0
  39. package/codebakers-1.0.13.vsix +0 -0
  40. package/codebakers-1.0.14.vsix +0 -0
  41. package/codebakers-1.0.15.vsix +0 -0
  42. package/codebakers-1.0.16.vsix +0 -0
  43. package/codebakers-1.0.17.vsix +0 -0
  44. package/codebakers-1.0.18.vsix +0 -0
  45. package/codebakers-1.0.19.vsix +0 -0
  46. package/codebakers-1.0.20.vsix +0 -0
  47. package/codebakers-1.0.21.vsix +0 -0
  48. package/codebakers-1.0.22.vsix +0 -0
  49. package/codebakers-1.0.23.vsix +0 -0
  50. package/codebakers-1.0.24.vsix +0 -0
  51. package/codebakers-1.0.25.vsix +0 -0
  52. package/codebakers-1.0.26.vsix +0 -0
  53. package/codebakers-1.0.27.vsix +0 -0
  54. package/codebakers-1.0.28.vsix +0 -0
  55. package/codebakers-1.0.29.vsix +0 -0
  56. package/codebakers-1.0.30.vsix +0 -0
  57. package/codebakers-1.0.31.vsix +0 -0
  58. package/codebakers-1.0.32.vsix +0 -0
  59. package/codebakers-1.0.35.vsix +0 -0
  60. package/codebakers-1.0.36.vsix +0 -0
  61. package/codebakers-1.0.37.vsix +0 -0
  62. package/codebakers-1.0.38.vsix +0 -0
  63. package/codebakers-1.0.39.vsix +0 -0
  64. package/codebakers-1.0.40.vsix +0 -0
  65. package/codebakers-1.0.41.vsix +0 -0
  66. package/codebakers-1.0.42.vsix +0 -0
  67. package/codebakers-1.0.43.vsix +0 -0
  68. package/codebakers-1.0.44.vsix +0 -0
  69. package/codebakers-1.0.45.vsix +0 -0
  70. package/dist/extension.js +0 -1394
  71. package/esbuild.js +0 -63
  72. package/media/icon.png +0 -0
  73. package/media/icon.svg +0 -7
  74. package/nul +0 -1
  75. package/preview.html +0 -547
  76. package/src/ChatPanelProvider.ts +0 -1815
  77. package/src/ChatViewProvider.ts +0 -749
  78. package/src/CodeBakersClient.ts +0 -1146
  79. package/src/CodeValidator.ts +0 -645
  80. package/src/FileOperations.ts +0 -410
  81. package/src/ProjectContext.ts +0 -526
  82. package/src/extension.ts +0 -332
package/src/index.ts ADDED
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import * as p from '@clack/prompts';
5
+ import chalk from 'chalk';
6
+ import boxen from 'boxen';
7
+ import gradient from 'gradient-string';
8
+ import { Config } from './utils/config.js';
9
+ import { checkForUpdates } from './utils/updates.js';
10
+ import { setupCommand } from './commands/setup.js';
11
+ import { initCommand } from './commands/init.js';
12
+ import { codeCommand } from './commands/code.js';
13
+ import { checkCommand } from './commands/check.js';
14
+ import { deployCommand } from './commands/deploy.js';
15
+ import { connectCommand } from './commands/connect.js';
16
+ import { statusCommand } from './commands/status.js';
17
+ import { gatewayCommand } from './commands/gateway.js';
18
+ import { learnCommand } from './commands/learn.js';
19
+ import { securityCommand } from './commands/security.js';
20
+ import { generateCommand } from './commands/generate.js';
21
+ import { fixCommand } from './commands/fix.js';
22
+ import { designCommand } from './commands/design.js';
23
+
24
+ const VERSION = '1.0.0';
25
+
26
+ // ASCII art logo
27
+ const logo = `
28
+ ██████╗ ██████╗ ██████╗ ███████╗██████╗ █████╗ ██╗ ██╗███████╗██████╗ ███████╗
29
+ ██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗██╔══██╗██║ ██╔╝██╔════╝██╔══██╗██╔════╝
30
+ ██║ ██║ ██║██║ ██║█████╗ ██████╔╝███████║█████╔╝ █████╗ ██████╔╝███████╗
31
+ ██║ ██║ ██║██║ ██║██╔══╝ ██╔══██╗██╔══██║██╔═██╗ ██╔══╝ ██╔══██╗╚════██║
32
+ ╚██████╗╚██████╔╝██████╔╝███████╗██████╔╝██║ ██║██║ ██╗███████╗██║ ██║███████║
33
+ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝
34
+ `;
35
+
36
+ // Main interactive menu
37
+ async function showMainMenu(): Promise<void> {
38
+ const config = new Config();
39
+ const isSetup = config.isConfigured();
40
+
41
+ // Show logo
42
+ console.log(gradient.pastel.multiline(logo));
43
+ console.log(chalk.dim(` v${VERSION} — AI dev team that follows the rules\n`));
44
+
45
+ // If not setup, run setup wizard
46
+ if (!isSetup) {
47
+ console.log(boxen(
48
+ chalk.yellow('Welcome to CodeBakers! Let\'s get you set up.'),
49
+ { padding: 1, borderColor: 'yellow', borderStyle: 'round' }
50
+ ));
51
+ await setupCommand();
52
+ return;
53
+ }
54
+
55
+ // Check if in a project directory
56
+ const inProject = config.isInProject();
57
+
58
+ // Main menu
59
+ const action = await p.select({
60
+ message: 'What do you want to do?',
61
+ options: inProject ? [
62
+ { value: 'code', label: '💬 Code with AI', hint: 'build features, fix bugs' },
63
+ { value: 'check', label: '🔍 Check code quality', hint: 'run pattern enforcement' },
64
+ { value: 'deploy', label: '🚀 Deploy', hint: 'deploy to Vercel' },
65
+ { value: 'fix', label: '🔧 Fix errors', hint: 'auto-fix build/deploy errors' },
66
+ { value: 'generate', label: '⚡ Generate', hint: 'scaffold components, pages' },
67
+ { value: 'status', label: '📊 Project status', hint: 'view project health' },
68
+ { value: 'separator1', label: '─────────────────────────' },
69
+ { value: 'connect', label: '🔗 Connect service', hint: 'add integrations' },
70
+ { value: 'gateway', label: '📱 Channel gateway', hint: 'WhatsApp, Telegram, etc.' },
71
+ { value: 'learn', label: '🧠 Learning settings', hint: 'view what I\'ve learned' },
72
+ { value: 'security', label: '🔒 Security audit', hint: 'check for vulnerabilities' },
73
+ { value: 'design', label: '🎨 Design system', hint: 'set profile, colors' },
74
+ { value: 'separator2', label: '─────────────────────────' },
75
+ { value: 'new', label: '🆕 Create new project' },
76
+ { value: 'settings', label: '⚙️ Settings' },
77
+ { value: 'help', label: '❓ Help' },
78
+ ] : [
79
+ { value: 'new', label: '🆕 Create new project' },
80
+ { value: 'open', label: '📂 Open existing project' },
81
+ { value: 'status', label: '📊 View all projects' },
82
+ { value: 'separator1', label: '─────────────────────────' },
83
+ { value: 'connect', label: '🔗 Connect service' },
84
+ { value: 'gateway', label: '📱 Channel gateway', hint: 'WhatsApp, Telegram, etc.' },
85
+ { value: 'learn', label: '🧠 Learning settings' },
86
+ { value: 'settings', label: '⚙️ Settings' },
87
+ { value: 'help', label: '❓ Help' },
88
+ ]
89
+ });
90
+
91
+ if (p.isCancel(action)) {
92
+ p.cancel('Goodbye!');
93
+ process.exit(0);
94
+ }
95
+
96
+ // Handle actions
97
+ switch (action) {
98
+ case 'code':
99
+ await codeCommand();
100
+ break;
101
+ case 'check':
102
+ await checkCommand();
103
+ break;
104
+ case 'deploy':
105
+ await deployCommand();
106
+ break;
107
+ case 'fix':
108
+ await fixCommand();
109
+ break;
110
+ case 'generate':
111
+ await generateCommand();
112
+ break;
113
+ case 'status':
114
+ await statusCommand();
115
+ break;
116
+ case 'connect':
117
+ await connectCommand();
118
+ break;
119
+ case 'gateway':
120
+ await gatewayCommand();
121
+ break;
122
+ case 'learn':
123
+ await learnCommand();
124
+ break;
125
+ case 'security':
126
+ await securityCommand();
127
+ break;
128
+ case 'design':
129
+ await designCommand();
130
+ break;
131
+ case 'new':
132
+ await initCommand();
133
+ break;
134
+ case 'settings':
135
+ await setupCommand();
136
+ break;
137
+ case 'help':
138
+ showHelp();
139
+ break;
140
+ default:
141
+ // Separators, do nothing
142
+ await showMainMenu();
143
+ }
144
+ }
145
+
146
+ function showHelp(): void {
147
+ console.log(boxen(`
148
+ ${chalk.bold('CodeBakers CLI')} — AI dev team that follows the rules
149
+
150
+ ${chalk.bold('Commands:')}
151
+ ${chalk.cyan('codebakers')} Interactive menu (or just run with no args)
152
+ ${chalk.cyan('codebakers init')} Create a new project
153
+ ${chalk.cyan('codebakers code')} Start AI coding session
154
+ ${chalk.cyan('codebakers check')} Run pattern enforcement
155
+ ${chalk.cyan('codebakers deploy')} Deploy to production
156
+ ${chalk.cyan('codebakers fix')} Auto-fix errors
157
+ ${chalk.cyan('codebakers generate')} Generate components/pages
158
+ ${chalk.cyan('codebakers connect')} Connect external services
159
+ ${chalk.cyan('codebakers gateway')} Manage messaging channels
160
+ ${chalk.cyan('codebakers status')} View project status
161
+ ${chalk.cyan('codebakers security')} Run security audit
162
+ ${chalk.cyan('codebakers learn')} View/manage learning
163
+
164
+ ${chalk.bold('Help at any time:')}
165
+ Press ${chalk.yellow('?')} during any command to get contextual help
166
+
167
+ ${chalk.bold('Documentation:')}
168
+ ${chalk.dim('https://codebakers.dev/docs')}
169
+ `, { padding: 1, borderColor: 'cyan', borderStyle: 'round' }));
170
+ }
171
+
172
+ // CLI setup with Commander
173
+ const program = new Command();
174
+
175
+ program
176
+ .name('codebakers')
177
+ .description('AI dev team that follows the rules')
178
+ .version(VERSION)
179
+ .action(showMainMenu);
180
+
181
+ program
182
+ .command('setup')
183
+ .description('Configure CodeBakers (first-time setup)')
184
+ .action(setupCommand);
185
+
186
+ program
187
+ .command('init')
188
+ .description('Create a new project')
189
+ .option('-n, --name <name>', 'Project name')
190
+ .option('-t, --template <template>', 'Template (nextjs, voice-agent, saas)')
191
+ .option('--no-git', 'Skip GitHub repo creation')
192
+ .option('--no-vercel', 'Skip Vercel deployment')
193
+ .option('--no-supabase', 'Skip Supabase setup')
194
+ .action(initCommand);
195
+
196
+ program
197
+ .command('code [prompt]')
198
+ .description('Start AI coding session')
199
+ .option('-w, --watch', 'Watch mode - continuous assistance')
200
+ .action(codeCommand);
201
+
202
+ program
203
+ .command('check')
204
+ .description('Run CodeBakers pattern enforcement')
205
+ .option('-f, --fix', 'Auto-fix violations')
206
+ .option('--watch', 'Watch mode')
207
+ .action(checkCommand);
208
+
209
+ program
210
+ .command('deploy')
211
+ .description('Deploy to production')
212
+ .option('-p, --preview', 'Deploy to preview only')
213
+ .option('--no-check', 'Skip pattern check')
214
+ .action(deployCommand);
215
+
216
+ program
217
+ .command('fix')
218
+ .description('Auto-fix build and deployment errors')
219
+ .option('--auto', 'Fix without asking')
220
+ .action(fixCommand);
221
+
222
+ program
223
+ .command('generate <type>')
224
+ .alias('g')
225
+ .description('Generate components, pages, API routes')
226
+ .option('-n, --name <name>', 'Name of the generated item')
227
+ .action(generateCommand);
228
+
229
+ program
230
+ .command('connect [service]')
231
+ .description('Connect external services (Stripe, VAPI, etc.)')
232
+ .action(connectCommand);
233
+
234
+ program
235
+ .command('gateway')
236
+ .description('Manage messaging channel gateway')
237
+ .option('--start', 'Start the gateway')
238
+ .option('--stop', 'Stop the gateway')
239
+ .option('--status', 'Show gateway status')
240
+ .action(gatewayCommand);
241
+
242
+ program
243
+ .command('status')
244
+ .description('View project status and health')
245
+ .option('-a, --all', 'Show all projects')
246
+ .action(statusCommand);
247
+
248
+ program
249
+ .command('security')
250
+ .description('Run security audit')
251
+ .option('--fix', 'Auto-fix security issues')
252
+ .action(securityCommand);
253
+
254
+ program
255
+ .command('learn')
256
+ .description('View and manage learning settings')
257
+ .option('--forget <item>', 'Forget a learned preference')
258
+ .option('--reset', 'Reset all learning')
259
+ .option('--export', 'Export learned patterns')
260
+ .action(learnCommand);
261
+
262
+ program
263
+ .command('design [action]')
264
+ .description('Manage design system (profile, palette, check)')
265
+ .action(designCommand);
266
+
267
+ // Parse args or show menu
268
+ const args = process.argv.slice(2);
269
+
270
+ if (args.length === 0) {
271
+ // Check for updates in background
272
+ checkForUpdates().catch(() => {});
273
+
274
+ // Show interactive menu
275
+ showMainMenu().catch(console.error);
276
+ } else {
277
+ program.parse();
278
+ }
@@ -0,0 +1,337 @@
1
+ import * as fs from 'fs-extra';
2
+ import * as path from 'path';
3
+ import { Config } from '../utils/config.js';
4
+
5
+ // Embedded core patterns (extracted from your CLAUDE.md)
6
+ const CORE_PATTERNS = `
7
+ # CODEBAKERS CORE PATTERNS
8
+
9
+ ## ABSOLUTE PROHIBITIONS
10
+
11
+ These will NEVER appear in your code:
12
+
13
+ \`\`\`typescript
14
+ // ❌ BANNED - NON-FUNCTIONAL CODE
15
+ onClick={handleClick} // where handleClick doesn't exist
16
+ onSubmit={handleSubmit} // where handleSubmit doesn't exist
17
+ href="/some-page" // where the page doesn't exist
18
+
19
+ // ❌ BANNED - INCOMPLETE CODE
20
+ TODO: // No TODOs ever
21
+ FIXME: // No FIXMEs ever
22
+ // ... // No placeholder comments
23
+ throw new Error('Not implemented')
24
+
25
+ // ❌ BANNED - DEBUG CODE
26
+ console.log('test') // No debug logs
27
+ debugger; // No debugger statements
28
+
29
+ // ❌ BANNED - TYPE SAFETY VIOLATIONS
30
+ any // No 'any' types
31
+ @ts-ignore // No ignoring TypeScript
32
+ as any // No casting to any
33
+
34
+ // ❌ BANNED - SECURITY VIOLATIONS
35
+ eval() // No eval ever
36
+ innerHTML = // No direct innerHTML
37
+ dangerouslySetInnerHTML // Without DOMPurify
38
+ \`\`\`
39
+
40
+ ## MANDATORY PATTERNS
41
+
42
+ ### Every Button MUST Have:
43
+
44
+ \`\`\`typescript
45
+ <Button
46
+ onClick={handleAction}
47
+ disabled={isLoading || isDisabled}
48
+ aria-label="Descriptive action name"
49
+ >
50
+ {isLoading ? (
51
+ <>
52
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
53
+ Processing...
54
+ </>
55
+ ) : (
56
+ 'Action Name'
57
+ )}
58
+ </Button>
59
+
60
+ // The handler MUST exist and be complete:
61
+ const handleAction = async () => {
62
+ setIsLoading(true);
63
+ try {
64
+ await performAction();
65
+ toast.success('Action completed successfully');
66
+ } catch (error) {
67
+ const message = error instanceof Error ? error.message : 'Action failed';
68
+ toast.error(message);
69
+ } finally {
70
+ setIsLoading(false);
71
+ }
72
+ };
73
+ \`\`\`
74
+
75
+ ### Every Form MUST Have:
76
+
77
+ 1. React Hook Form with Zod validation
78
+ 2. Loading state during submission
79
+ 3. Error messages for each field
80
+ 4. Success/error toast notifications
81
+ 5. Proper disabled state while submitting
82
+
83
+ ### Every Async Operation MUST Have:
84
+
85
+ \`\`\`typescript
86
+ const [data, setData] = useState<DataType | null>(null);
87
+ const [isLoading, setIsLoading] = useState(false);
88
+ const [error, setError] = useState<string | null>(null);
89
+
90
+ const fetchData = async () => {
91
+ setIsLoading(true);
92
+ setError(null);
93
+
94
+ try {
95
+ const response = await fetch('/api/data');
96
+ if (!response.ok) throw new Error(\`HTTP \${response.status}\`);
97
+ const result = await response.json();
98
+ setData(result.data);
99
+ } catch (err) {
100
+ const message = err instanceof Error ? err.message : 'Failed to fetch';
101
+ setError(message);
102
+ toast.error(message);
103
+ } finally {
104
+ setIsLoading(false);
105
+ }
106
+ };
107
+ \`\`\`
108
+
109
+ ### Every List MUST Have:
110
+
111
+ 1. Loading state with spinner/skeleton
112
+ 2. Error state with retry button
113
+ 3. Empty state with helpful message
114
+ 4. Success state with data
115
+
116
+ ## FILE STRUCTURE
117
+
118
+ \`\`\`
119
+ src/
120
+ ├── app/ # Next.js App Router
121
+ │ ├── (auth)/ # Routes requiring authentication
122
+ │ ├── (public)/ # Public routes
123
+ │ ├── (marketing)/ # Marketing pages
124
+ │ ├── api/ # API routes
125
+ │ └── layout.tsx # Root layout
126
+ ├── components/
127
+ │ ├── ui/ # shadcn/ui components
128
+ │ ├── forms/ # Form components
129
+ │ ├── layouts/ # Layout components
130
+ │ └── [feature]/ # Feature-specific components
131
+ ├── lib/
132
+ │ ├── supabase/ # Supabase clients
133
+ │ ├── utils.ts # Utility functions
134
+ │ └── validations.ts # Zod schemas
135
+ ├── hooks/ # Custom React hooks
136
+ ├── types/ # TypeScript types
137
+ ├── stores/ # Zustand stores
138
+ └── services/ # Business logic
139
+ \`\`\`
140
+
141
+ ## API ROUTE PATTERN
142
+
143
+ \`\`\`typescript
144
+ import { NextRequest, NextResponse } from 'next/server';
145
+ import { z } from 'zod';
146
+ import { createServerClient } from '@/lib/supabase/server';
147
+
148
+ const requestSchema = z.object({
149
+ // Define request body schema
150
+ });
151
+
152
+ export async function POST(request: NextRequest) {
153
+ try {
154
+ // 1. Auth check
155
+ const supabase = createServerClient();
156
+ const { data: { user }, error: authError } = await supabase.auth.getUser();
157
+
158
+ if (authError || !user) {
159
+ return NextResponse.json(
160
+ { error: 'Unauthorized' },
161
+ { status: 401 }
162
+ );
163
+ }
164
+
165
+ // 2. Validate input
166
+ const body = await request.json();
167
+ const result = requestSchema.safeParse(body);
168
+
169
+ if (!result.success) {
170
+ return NextResponse.json(
171
+ { error: 'Validation failed', details: result.error.flatten() },
172
+ { status: 400 }
173
+ );
174
+ }
175
+
176
+ // 3. Business logic
177
+ const data = result.data;
178
+ // ... do something
179
+
180
+ // 4. Return success
181
+ return NextResponse.json({ data }, { status: 201 });
182
+
183
+ } catch (error) {
184
+ console.error('[API] Error:', error);
185
+ return NextResponse.json(
186
+ { error: 'Internal server error' },
187
+ { status: 500 }
188
+ );
189
+ }
190
+ }
191
+ \`\`\`
192
+
193
+ ## SUPABASE RLS PATTERN
194
+
195
+ Every table MUST have Row Level Security enabled:
196
+
197
+ \`\`\`sql
198
+ -- Enable RLS
199
+ ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;
200
+
201
+ -- User can only see their own data
202
+ CREATE POLICY "Users can view own data"
203
+ ON your_table FOR SELECT
204
+ TO authenticated
205
+ USING (user_id = auth.uid());
206
+
207
+ -- User can only insert their own data
208
+ CREATE POLICY "Users can insert own data"
209
+ ON your_table FOR INSERT
210
+ TO authenticated
211
+ WITH CHECK (user_id = auth.uid());
212
+
213
+ -- User can only update their own data
214
+ CREATE POLICY "Users can update own data"
215
+ ON your_table FOR UPDATE
216
+ TO authenticated
217
+ USING (user_id = auth.uid())
218
+ WITH CHECK (user_id = auth.uid());
219
+
220
+ -- User can only delete their own data
221
+ CREATE POLICY "Users can delete own data"
222
+ ON your_table FOR DELETE
223
+ TO authenticated
224
+ USING (user_id = auth.uid());
225
+ \`\`\`
226
+
227
+ ## STATE MANAGEMENT
228
+
229
+ Use Zustand for global state:
230
+
231
+ \`\`\`typescript
232
+ import { create } from 'zustand';
233
+
234
+ interface AppState {
235
+ user: User | null;
236
+ isLoading: boolean;
237
+ setUser: (user: User | null) => void;
238
+ reset: () => void;
239
+ }
240
+
241
+ export const useAppStore = create<AppState>((set) => ({
242
+ user: null,
243
+ isLoading: false,
244
+ setUser: (user) => set({ user }),
245
+ reset: () => set({ user: null, isLoading: false }),
246
+ }));
247
+ \`\`\`
248
+
249
+ ## ERROR HANDLING
250
+
251
+ Use typed error classes:
252
+
253
+ \`\`\`typescript
254
+ export class AppError extends Error {
255
+ constructor(
256
+ message: string,
257
+ public code: string,
258
+ public statusCode: number = 500
259
+ ) {
260
+ super(message);
261
+ }
262
+ }
263
+
264
+ export class AuthenticationError extends AppError {
265
+ constructor(message = 'Authentication required') {
266
+ super(message, 'AUTH_ERROR', 401);
267
+ }
268
+ }
269
+
270
+ export class ValidationError extends AppError {
271
+ constructor(message = 'Validation failed', public details?: Record<string, string[]>) {
272
+ super(message, 'VALIDATION_ERROR', 400);
273
+ }
274
+ }
275
+ \`\`\`
276
+ `;
277
+
278
+ export async function loadPatterns(config: Config): Promise<string> {
279
+ const projectDir = process.cwd();
280
+ const patterns: string[] = [CORE_PATTERNS];
281
+
282
+ // Load project-specific patterns if they exist
283
+ const projectPatternDir = path.join(projectDir, '.codebakers', 'patterns');
284
+ if (await fs.pathExists(projectPatternDir)) {
285
+ const files = await fs.readdir(projectPatternDir);
286
+ for (const file of files) {
287
+ if (file.endsWith('.md')) {
288
+ const content = await fs.readFile(path.join(projectPatternDir, file), 'utf-8');
289
+ patterns.push(content);
290
+ }
291
+ }
292
+ }
293
+
294
+ // Load global patterns
295
+ const globalPatternDir = config.getPatternsDir();
296
+ if (await fs.pathExists(globalPatternDir)) {
297
+ const files = await fs.readdir(globalPatternDir);
298
+ for (const file of files.slice(0, 10)) { // Limit to avoid context overflow
299
+ if (file.endsWith('.md')) {
300
+ const content = await fs.readFile(path.join(globalPatternDir, file), 'utf-8');
301
+ // Truncate if too long
302
+ patterns.push(content.slice(0, 10000));
303
+ }
304
+ }
305
+ }
306
+
307
+ return patterns.join('\n\n---\n\n');
308
+ }
309
+
310
+ export async function validateAgainstPatterns(
311
+ code: string,
312
+ patterns: string
313
+ ): Promise<{ valid: boolean; violations: string[] }> {
314
+ const violations: string[] = [];
315
+
316
+ // Check for banned patterns
317
+ if (code.includes(': any') && !code.includes('// @allow-any')) {
318
+ violations.push('Use of "any" type detected');
319
+ }
320
+ if (code.includes('@ts-ignore')) {
321
+ violations.push('@ts-ignore detected');
322
+ }
323
+ if (/console\.log\(/.test(code)) {
324
+ violations.push('console.log detected');
325
+ }
326
+ if (/TODO:|FIXME:/.test(code)) {
327
+ violations.push('TODO/FIXME comment detected');
328
+ }
329
+ if (/eval\s*\(/.test(code)) {
330
+ violations.push('eval() detected - security risk');
331
+ }
332
+
333
+ return {
334
+ valid: violations.length === 0,
335
+ violations,
336
+ };
337
+ }
@@ -0,0 +1,61 @@
1
+ import { Octokit } from '@octokit/rest';
2
+ import { Config } from '../utils/config.js';
3
+
4
+ export class GitHubService {
5
+ private octokit: Octokit;
6
+ private config: Config;
7
+
8
+ constructor(config: Config) {
9
+ this.config = config;
10
+ const creds = config.getCredentials('github');
11
+
12
+ if (!creds?.token) {
13
+ throw new Error('GitHub not configured. Run `codebakers setup`.');
14
+ }
15
+
16
+ this.octokit = new Octokit({ auth: creds.token });
17
+ }
18
+
19
+ async createRepo(name: string, options: { private?: boolean } = {}): Promise<{
20
+ id: number;
21
+ name: string;
22
+ full_name: string;
23
+ html_url: string;
24
+ clone_url: string;
25
+ }> {
26
+ const response = await this.octokit.repos.createForAuthenticatedUser({
27
+ name,
28
+ private: options.private ?? true,
29
+ auto_init: false,
30
+ });
31
+
32
+ return {
33
+ id: response.data.id,
34
+ name: response.data.name,
35
+ full_name: response.data.full_name,
36
+ html_url: response.data.html_url,
37
+ clone_url: response.data.clone_url,
38
+ };
39
+ }
40
+
41
+ async getUser(): Promise<{ login: string; name: string | null }> {
42
+ const response = await this.octokit.users.getAuthenticated();
43
+ return {
44
+ login: response.data.login,
45
+ name: response.data.name,
46
+ };
47
+ }
48
+
49
+ async listRepos(): Promise<Array<{ name: string; full_name: string; private: boolean }>> {
50
+ const response = await this.octokit.repos.listForAuthenticatedUser({
51
+ sort: 'updated',
52
+ per_page: 100,
53
+ });
54
+
55
+ return response.data.map(repo => ({
56
+ name: repo.name,
57
+ full_name: repo.full_name,
58
+ private: repo.private,
59
+ }));
60
+ }
61
+ }