codebakers 2.0.2 → 2.0.4

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/index.js CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import * as p15 from "@clack/prompts";
6
- import chalk16 from "chalk";
5
+ import * as p16 from "@clack/prompts";
6
+ import chalk17 from "chalk";
7
7
  import boxen from "boxen";
8
8
  import gradient from "gradient-string";
9
9
 
@@ -135,7 +135,75 @@ var Config = class {
135
135
  const cwd = process.cwd();
136
136
  const codebakersDir = path.join(cwd, ".codebakers");
137
137
  const claudeFile = path.join(cwd, "CLAUDE.md");
138
- return fs.existsSync(codebakersDir) || fs.existsSync(claudeFile);
138
+ if (fs.existsSync(codebakersDir) || fs.existsSync(claudeFile)) {
139
+ return true;
140
+ }
141
+ const projectIndicators = [
142
+ "package.json",
143
+ "next.config.js",
144
+ "next.config.mjs",
145
+ "next.config.ts",
146
+ "vite.config.ts",
147
+ "vite.config.js",
148
+ "remix.config.js",
149
+ "astro.config.mjs"
150
+ ];
151
+ const hasProjectFile = projectIndicators.some(
152
+ (file) => fs.existsSync(path.join(cwd, file))
153
+ );
154
+ if (hasProjectFile) {
155
+ this.autoInitExisting(cwd);
156
+ return true;
157
+ }
158
+ return false;
159
+ }
160
+ // Auto-initialize CodeBakers in an existing project
161
+ autoInitExisting(cwd) {
162
+ try {
163
+ let framework = "unknown";
164
+ let ui = "unknown";
165
+ if (fs.existsSync(path.join(cwd, "next.config.js")) || fs.existsSync(path.join(cwd, "next.config.mjs")) || fs.existsSync(path.join(cwd, "next.config.ts"))) {
166
+ framework = "nextjs";
167
+ } else if (fs.existsSync(path.join(cwd, "vite.config.ts")) || fs.existsSync(path.join(cwd, "vite.config.js"))) {
168
+ framework = "vite";
169
+ } else if (fs.existsSync(path.join(cwd, "remix.config.js"))) {
170
+ framework = "remix";
171
+ } else if (fs.existsSync(path.join(cwd, "astro.config.mjs"))) {
172
+ framework = "astro";
173
+ }
174
+ const pkgPath = path.join(cwd, "package.json");
175
+ if (fs.existsSync(pkgPath)) {
176
+ const pkg = fs.readJsonSync(pkgPath);
177
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
178
+ if (deps["@shadcn/ui"] || deps["class-variance-authority"]) {
179
+ ui = "shadcn";
180
+ } else if (deps["@chakra-ui/react"]) {
181
+ ui = "chakra";
182
+ } else if (deps["@mantine/core"]) {
183
+ ui = "mantine";
184
+ } else if (deps["@mui/material"]) {
185
+ ui = "mui";
186
+ }
187
+ }
188
+ const configDir = path.join(cwd, ".codebakers");
189
+ fs.ensureDirSync(configDir);
190
+ const config = {
191
+ name: path.basename(cwd),
192
+ framework,
193
+ ui,
194
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
195
+ autoDetected: true
196
+ };
197
+ fs.writeJsonSync(path.join(configDir, "config.json"), config, { spaces: 2 });
198
+ const gitignorePath = path.join(cwd, ".gitignore");
199
+ if (fs.existsSync(gitignorePath)) {
200
+ const gitignore = fs.readFileSync(gitignorePath, "utf-8");
201
+ if (!gitignore.includes(".codebakers")) {
202
+ fs.appendFileSync(gitignorePath, "\n# CodeBakers\n.codebakers/\n");
203
+ }
204
+ }
205
+ } catch {
206
+ }
139
207
  }
140
208
  // Get current project config
141
209
  getProjectConfig() {
@@ -304,10 +372,10 @@ async function setupCommand() {
304
372
  return;
305
373
  }
306
374
  if (action === "reset") {
307
- const confirm8 = await p.confirm({
375
+ const confirm9 = await p.confirm({
308
376
  message: "Are you sure? This will remove all credentials and settings."
309
377
  });
310
- if (confirm8) {
378
+ if (confirm9) {
311
379
  p.outro(chalk2.yellow("Configuration reset. Run `codebakers setup` again."));
312
380
  }
313
381
  return;
@@ -371,7 +439,7 @@ ${chalk2.dim("and are never sent to our servers.")}`,
371
439
  p.outro(chalk2.green("\u2713 Setup complete! Run `codebakers init` to create your first project."));
372
440
  }
373
441
  async function connectService(config, serviceKey, serviceName, required) {
374
- const spinner13 = p.spinner();
442
+ const spinner14 = p.spinner();
375
443
  switch (serviceKey) {
376
444
  case "github": {
377
445
  p.log.info(`${chalk2.bold("GitHub")} - Opens browser for OAuth authorization`);
@@ -845,10 +913,10 @@ var SupabaseService = class {
845
913
  throw new Error("Failed to list projects");
846
914
  }
847
915
  const projects = await response.json();
848
- return projects.map((p16) => ({
849
- id: p16.id,
850
- name: p16.name,
851
- region: p16.region
916
+ return projects.map((p17) => ({
917
+ id: p17.id,
918
+ name: p17.name,
919
+ region: p17.region
852
920
  }));
853
921
  }
854
922
  };
@@ -1268,20 +1336,20 @@ Domain: ${domain || "Vercel default"}`,
1268
1336
  p2.cancel("Project creation cancelled.");
1269
1337
  return;
1270
1338
  }
1271
- const spinner13 = p2.spinner();
1339
+ const spinner14 = p2.spinner();
1272
1340
  const projectPath = path2.join(process.cwd(), projectName);
1273
1341
  try {
1274
- spinner13.start("Creating local project...");
1342
+ spinner14.start("Creating local project...");
1275
1343
  await createLocalProject(projectPath, projectConfig);
1276
- spinner13.stop("Local project created");
1277
- spinner13.start("Installing dependencies...");
1344
+ spinner14.stop("Local project created");
1345
+ spinner14.start("Installing dependencies...");
1278
1346
  await execa2("pnpm", ["install"], { cwd: projectPath });
1279
- spinner13.stop("Dependencies installed");
1347
+ spinner14.stop("Dependencies installed");
1280
1348
  if (services.includes("github")) {
1281
- spinner13.start("Creating GitHub repository...");
1349
+ spinner14.start("Creating GitHub repository...");
1282
1350
  const github = new GitHubService(config);
1283
1351
  const repo = await github.createRepo(projectName, { private: true });
1284
- spinner13.stop(`GitHub repo created: ${repo.html_url}`);
1352
+ spinner14.stop(`GitHub repo created: ${repo.html_url}`);
1285
1353
  await execa2("git", ["init"], { cwd: projectPath });
1286
1354
  await execa2("git", ["add", "."], { cwd: projectPath });
1287
1355
  await execa2("git", ["commit", "-m", "Initial commit by CodeBakers"], { cwd: projectPath });
@@ -1289,10 +1357,10 @@ Domain: ${domain || "Vercel default"}`,
1289
1357
  await execa2("git", ["push", "-u", "origin", "main"], { cwd: projectPath });
1290
1358
  }
1291
1359
  if (services.includes("supabase")) {
1292
- spinner13.start("Creating Supabase project...");
1360
+ spinner14.start("Creating Supabase project...");
1293
1361
  const supabase = new SupabaseService(config);
1294
1362
  const project = await supabase.createProject(projectName);
1295
- spinner13.stop(`Supabase project created: ${project.name}`);
1363
+ spinner14.stop(`Supabase project created: ${project.name}`);
1296
1364
  await fs2.writeJson(
1297
1365
  path2.join(projectPath, ".codebakers", "supabase.json"),
1298
1366
  { projectId: project.id, projectUrl: project.api_url },
@@ -1300,26 +1368,26 @@ Domain: ${domain || "Vercel default"}`,
1300
1368
  );
1301
1369
  }
1302
1370
  if (services.includes("vercel")) {
1303
- spinner13.start("Creating Vercel project...");
1371
+ spinner14.start("Creating Vercel project...");
1304
1372
  const vercel = new VercelService(config);
1305
1373
  const project = await vercel.createProject(projectName);
1306
- spinner13.stop(`Vercel project created`);
1374
+ spinner14.stop(`Vercel project created`);
1307
1375
  if (domain) {
1308
- spinner13.start(`Configuring domain: ${domain}...`);
1376
+ spinner14.start(`Configuring domain: ${domain}...`);
1309
1377
  await vercel.addDomain(projectName, domain);
1310
- spinner13.stop("Domain configured");
1378
+ spinner14.stop("Domain configured");
1311
1379
  }
1312
- spinner13.start("Deploying to Vercel...");
1380
+ spinner14.start("Deploying to Vercel...");
1313
1381
  const deployment = await vercel.deploy(projectPath);
1314
- spinner13.stop(`Deployed: ${deployment.url}`);
1382
+ spinner14.stop(`Deployed: ${deployment.url}`);
1315
1383
  }
1316
- spinner13.start("Generating CLAUDE.md...");
1384
+ spinner14.start("Generating CLAUDE.md...");
1317
1385
  const claudeMd = generateClaudeMd(projectConfig);
1318
1386
  await fs2.writeFile(path2.join(projectPath, "CLAUDE.md"), claudeMd);
1319
- spinner13.stop("CLAUDE.md generated");
1320
- spinner13.start("Setting up CodeBakers enforcement...");
1387
+ spinner14.stop("CLAUDE.md generated");
1388
+ spinner14.start("Setting up CodeBakers enforcement...");
1321
1389
  await setupGitHooks(projectPath);
1322
- spinner13.stop("CodeBakers enforcement configured");
1390
+ spinner14.stop("CodeBakers enforcement configured");
1323
1391
  config.addProject({
1324
1392
  name: projectName,
1325
1393
  path: projectPath,
@@ -1339,7 +1407,7 @@ ${chalk3.dim("Shortcuts:")}
1339
1407
  ${chalk3.cyan("codebakers deploy")} \u2014 Deploy to production
1340
1408
  `));
1341
1409
  } catch (error) {
1342
- spinner13.stop("Error occurred");
1410
+ spinner14.stop("Error occurred");
1343
1411
  p2.log.error(`Failed to create project: ${error instanceof Error ? error.message : "Unknown error"}`);
1344
1412
  const cleanup = await p2.confirm({
1345
1413
  message: "Clean up partially created project?"
@@ -2065,17 +2133,17 @@ async function checkCommand(options = {}) {
2065
2133
  return;
2066
2134
  }
2067
2135
  p3.intro(chalk4.bgCyan.black(" CodeBakers Pattern Check "));
2068
- const spinner13 = p3.spinner();
2069
- spinner13.start("Analyzing code...");
2136
+ const spinner14 = p3.spinner();
2137
+ spinner14.start("Analyzing code...");
2070
2138
  const result = await runPatternCheck(options.fix || false);
2071
- spinner13.stop("Analysis complete");
2139
+ spinner14.stop("Analysis complete");
2072
2140
  displayResults(result);
2073
2141
  if (result.violations.length > 0 && options.fix) {
2074
2142
  const fixable = result.violations.filter((v) => v.autoFixable);
2075
2143
  if (fixable.length > 0) {
2076
- spinner13.start(`Auto-fixing ${fixable.length} violations...`);
2144
+ spinner14.start(`Auto-fixing ${fixable.length} violations...`);
2077
2145
  await autoFix(fixable);
2078
- spinner13.stop("Auto-fix complete");
2146
+ spinner14.stop("Auto-fix complete");
2079
2147
  }
2080
2148
  }
2081
2149
  const errors = result.violations.filter((v) => v.severity === "error");
@@ -2267,14 +2335,14 @@ async function codeCommand(prompt, options = {}) {
2267
2335
  }
2268
2336
  }
2269
2337
  async function processUserInput(userInput, messages, anthropic, systemPrompt, projectContext, config) {
2270
- const spinner13 = p4.spinner();
2338
+ const spinner14 = p4.spinner();
2271
2339
  messages.push({ role: "user", content: userInput });
2272
2340
  const wizardResult = await checkForWizard(userInput);
2273
2341
  if (wizardResult) {
2274
2342
  messages[messages.length - 1].content = wizardResult;
2275
2343
  }
2276
2344
  try {
2277
- spinner13.start("Thinking...");
2345
+ spinner14.start("Thinking...");
2278
2346
  const response = await anthropic.messages.create({
2279
2347
  model: "claude-sonnet-4-20250514",
2280
2348
  max_tokens: 8192,
@@ -2284,7 +2352,7 @@ async function processUserInput(userInput, messages, anthropic, systemPrompt, pr
2284
2352
  content: m.content
2285
2353
  }))
2286
2354
  });
2287
- spinner13.stop("");
2355
+ spinner14.stop("");
2288
2356
  const assistantMessage = response.content[0].type === "text" ? response.content[0].text : "";
2289
2357
  messages.push({ role: "assistant", content: assistantMessage });
2290
2358
  const actions = parseActions(assistantMessage);
@@ -2299,11 +2367,11 @@ async function processUserInput(userInput, messages, anthropic, systemPrompt, pr
2299
2367
  initialValue: true
2300
2368
  });
2301
2369
  if (proceed && !p4.isCancel(proceed)) {
2302
- spinner13.start("Building...");
2370
+ spinner14.start("Building...");
2303
2371
  for (const action of actions) {
2304
- await executeAction(action, spinner13);
2372
+ await executeAction(action, spinner14);
2305
2373
  }
2306
- spinner13.stop("Build complete");
2374
+ spinner14.stop("Build complete");
2307
2375
  console.log(chalk5.dim("\n\u{1F50D} Running CodeBakers check..."));
2308
2376
  const checkResult = await runPatternCheck(false);
2309
2377
  if (checkResult.violations.length > 0) {
@@ -2314,9 +2382,9 @@ async function processUserInput(userInput, messages, anthropic, systemPrompt, pr
2314
2382
  initialValue: true
2315
2383
  });
2316
2384
  if (autoFix2 && !p4.isCancel(autoFix2)) {
2317
- spinner13.start("Auto-fixing...");
2385
+ spinner14.start("Auto-fixing...");
2318
2386
  await autoFixViolations(checkResult.violations, anthropic, systemPrompt);
2319
- spinner13.stop("Violations fixed");
2387
+ spinner14.stop("Violations fixed");
2320
2388
  }
2321
2389
  } else {
2322
2390
  console.log(chalk5.green("\u2713 All patterns satisfied"));
@@ -2327,7 +2395,7 @@ async function processUserInput(userInput, messages, anthropic, systemPrompt, pr
2327
2395
  console.log("\n" + assistantMessage + "\n");
2328
2396
  }
2329
2397
  } catch (error) {
2330
- spinner13.stop("Error");
2398
+ spinner14.stop("Error");
2331
2399
  console.log(chalk5.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
2332
2400
  }
2333
2401
  }
@@ -2439,14 +2507,14 @@ function parseActions(response) {
2439
2507
  }
2440
2508
  return actions;
2441
2509
  }
2442
- async function executeAction(action, spinner13) {
2510
+ async function executeAction(action, spinner14) {
2443
2511
  const cwd = process.cwd();
2444
2512
  switch (action.type) {
2445
2513
  case "CREATE_FILE": {
2446
2514
  const filePath = path5.join(cwd, action.path);
2447
2515
  await fs5.ensureDir(path5.dirname(filePath));
2448
2516
  await fs5.writeFile(filePath, action.content);
2449
- spinner13.message(`Created ${action.path}`);
2517
+ spinner14.message(`Created ${action.path}`);
2450
2518
  break;
2451
2519
  }
2452
2520
  case "EDIT_FILE": {
@@ -2456,13 +2524,13 @@ async function executeAction(action, spinner13) {
2456
2524
  if (action.find && content.includes(action.find)) {
2457
2525
  content = content.replace(action.find, action.replace || "");
2458
2526
  await fs5.writeFile(filePath, content);
2459
- spinner13.message(`Edited ${action.path}`);
2527
+ spinner14.message(`Edited ${action.path}`);
2460
2528
  }
2461
2529
  }
2462
2530
  break;
2463
2531
  }
2464
2532
  case "RUN_COMMAND": {
2465
- spinner13.message(`Running: ${action.command}`);
2533
+ spinner14.message(`Running: ${action.command}`);
2466
2534
  const [cmd, ...args2] = action.command.split(" ");
2467
2535
  await execa3(cmd, args2, { cwd, stdio: "pipe" });
2468
2536
  break;
@@ -2471,7 +2539,7 @@ async function executeAction(action, spinner13) {
2471
2539
  const filePath = path5.join(cwd, action.path);
2472
2540
  if (await fs5.pathExists(filePath)) {
2473
2541
  await fs5.remove(filePath);
2474
- spinner13.message(`Deleted ${action.path}`);
2542
+ spinner14.message(`Deleted ${action.path}`);
2475
2543
  }
2476
2544
  break;
2477
2545
  }
@@ -2719,12 +2787,12 @@ async function deployCommand(options = {}) {
2719
2787
  return;
2720
2788
  }
2721
2789
  p5.intro(chalk6.bgCyan.black(" Deploy to Production "));
2722
- const spinner13 = p5.spinner();
2790
+ const spinner14 = p5.spinner();
2723
2791
  if (options.check !== false) {
2724
- spinner13.start("Running CodeBakers check...");
2792
+ spinner14.start("Running CodeBakers check...");
2725
2793
  const checkResult = await runPatternCheck(false);
2726
2794
  if (!checkResult.passed) {
2727
- spinner13.stop("");
2795
+ spinner14.stop("");
2728
2796
  const errors = checkResult.violations.filter((v) => v.severity === "error");
2729
2797
  if (errors.length > 0) {
2730
2798
  p5.log.error(`${errors.length} pattern violations found. Fix before deploying.`);
@@ -2745,9 +2813,9 @@ async function deployCommand(options = {}) {
2745
2813
  p5.outro(chalk6.red("Deploy cancelled."));
2746
2814
  return;
2747
2815
  }
2748
- spinner13.start("Auto-fixing with AI...");
2816
+ spinner14.start("Auto-fixing with AI...");
2749
2817
  await autoFixWithAI(config, errors);
2750
- spinner13.stop("Auto-fix complete");
2818
+ spinner14.stop("Auto-fix complete");
2751
2819
  const recheck = await runPatternCheck(false);
2752
2820
  if (!recheck.passed) {
2753
2821
  p5.log.error("Some violations remain. Manual fix required.");
@@ -2756,23 +2824,23 @@ async function deployCommand(options = {}) {
2756
2824
  }
2757
2825
  }
2758
2826
  }
2759
- spinner13.stop("Pattern check passed");
2827
+ spinner14.stop("Pattern check passed");
2760
2828
  }
2761
- spinner13.start("Running TypeScript check...");
2829
+ spinner14.start("Running TypeScript check...");
2762
2830
  try {
2763
2831
  await execa4("npx", ["tsc", "--noEmit"], { cwd: process.cwd() });
2764
- spinner13.stop("TypeScript check passed");
2832
+ spinner14.stop("TypeScript check passed");
2765
2833
  } catch (error) {
2766
- spinner13.stop("");
2834
+ spinner14.stop("");
2767
2835
  p5.log.error("TypeScript errors found.");
2768
2836
  const fix = await p5.confirm({
2769
2837
  message: "Attempt to fix TypeScript errors?",
2770
2838
  initialValue: true
2771
2839
  });
2772
2840
  if (fix && !p5.isCancel(fix)) {
2773
- spinner13.start("Fixing TypeScript errors...");
2841
+ spinner14.start("Fixing TypeScript errors...");
2774
2842
  const fixed = await fixTypeScriptErrors(config);
2775
- spinner13.stop(fixed ? "TypeScript errors fixed" : "Could not auto-fix all errors");
2843
+ spinner14.stop(fixed ? "TypeScript errors fixed" : "Could not auto-fix all errors");
2776
2844
  if (!fixed) {
2777
2845
  p5.outro(chalk6.red("Deploy cancelled."));
2778
2846
  return;
@@ -2782,12 +2850,12 @@ async function deployCommand(options = {}) {
2782
2850
  return;
2783
2851
  }
2784
2852
  }
2785
- spinner13.start("Building project...");
2853
+ spinner14.start("Building project...");
2786
2854
  try {
2787
2855
  await execa4("pnpm", ["build"], { cwd: process.cwd() });
2788
- spinner13.stop("Build successful");
2856
+ spinner14.stop("Build successful");
2789
2857
  } catch (error) {
2790
- spinner13.stop("");
2858
+ spinner14.stop("");
2791
2859
  p5.log.error("Build failed.");
2792
2860
  const errorOutput = error instanceof Error ? error.message : "Unknown error";
2793
2861
  console.log(chalk6.dim(errorOutput));
@@ -2796,16 +2864,16 @@ async function deployCommand(options = {}) {
2796
2864
  initialValue: true
2797
2865
  });
2798
2866
  if (fix && !p5.isCancel(fix)) {
2799
- spinner13.start("Fixing build errors...");
2867
+ spinner14.start("Fixing build errors...");
2800
2868
  const fixed = await fixBuildErrors(config, errorOutput);
2801
- spinner13.stop(fixed ? "Build errors fixed" : "Could not auto-fix");
2869
+ spinner14.stop(fixed ? "Build errors fixed" : "Could not auto-fix");
2802
2870
  if (fixed) {
2803
- spinner13.start("Retrying build...");
2871
+ spinner14.start("Retrying build...");
2804
2872
  try {
2805
2873
  await execa4("pnpm", ["build"], { cwd: process.cwd() });
2806
- spinner13.stop("Build successful");
2874
+ spinner14.stop("Build successful");
2807
2875
  } catch {
2808
- spinner13.stop("Build still failing");
2876
+ spinner14.stop("Build still failing");
2809
2877
  p5.outro(chalk6.red("Deploy cancelled."));
2810
2878
  return;
2811
2879
  }
@@ -2818,10 +2886,10 @@ async function deployCommand(options = {}) {
2818
2886
  return;
2819
2887
  }
2820
2888
  }
2821
- spinner13.start("Checking for uncommitted changes...");
2889
+ spinner14.start("Checking for uncommitted changes...");
2822
2890
  const { stdout: gitStatus } = await execa4("git", ["status", "--porcelain"], { cwd: process.cwd() });
2823
2891
  if (gitStatus.trim()) {
2824
- spinner13.stop("");
2892
+ spinner14.stop("");
2825
2893
  const commit = await p5.confirm({
2826
2894
  message: "You have uncommitted changes. Commit before deploying?",
2827
2895
  initialValue: true
@@ -2835,20 +2903,20 @@ async function deployCommand(options = {}) {
2835
2903
  if (!p5.isCancel(message)) {
2836
2904
  await execa4("git", ["add", "."], { cwd: process.cwd() });
2837
2905
  await execa4("git", ["commit", "-m", message], { cwd: process.cwd() });
2838
- spinner13.start("Pushing to GitHub...");
2906
+ spinner14.start("Pushing to GitHub...");
2839
2907
  await execa4("git", ["push"], { cwd: process.cwd() });
2840
- spinner13.stop("Pushed to GitHub");
2908
+ spinner14.stop("Pushed to GitHub");
2841
2909
  }
2842
2910
  }
2843
2911
  } else {
2844
- spinner13.stop("No uncommitted changes");
2912
+ spinner14.stop("No uncommitted changes");
2845
2913
  }
2846
2914
  const deployType = options.preview ? "preview" : "production";
2847
- spinner13.start(`Deploying to ${deployType}...`);
2915
+ spinner14.start(`Deploying to ${deployType}...`);
2848
2916
  try {
2849
2917
  const vercel = new VercelService(config);
2850
2918
  const deployment = await vercel.deploy(process.cwd(), !options.preview);
2851
- spinner13.stop("Deployment complete!");
2919
+ spinner14.stop("Deployment complete!");
2852
2920
  console.log(boxedOutput(`
2853
2921
  ${chalk6.green("\u2713")} Deployed successfully!
2854
2922
 
@@ -2860,7 +2928,7 @@ ${chalk6.dim("View in Vercel Dashboard:")}
2860
2928
  ${chalk6.dim(deployment.dashboardUrl || "https://vercel.com/dashboard")}
2861
2929
  `));
2862
2930
  } catch (error) {
2863
- spinner13.stop("");
2931
+ spinner14.stop("");
2864
2932
  const errorMsg = error instanceof Error ? error.message : "Unknown error";
2865
2933
  p5.log.error(`Deployment failed: ${errorMsg}`);
2866
2934
  if (errorMsg.includes("Build failed")) {
@@ -2869,8 +2937,8 @@ ${chalk6.dim(deployment.dashboardUrl || "https://vercel.com/dashboard")}
2869
2937
  initialValue: true
2870
2938
  });
2871
2939
  if (retry && !p5.isCancel(retry)) {
2872
- spinner13.start("Analyzing Vercel build error...");
2873
- spinner13.stop("Fix attempted");
2940
+ spinner14.start("Analyzing Vercel build error...");
2941
+ spinner14.stop("Fix attempted");
2874
2942
  }
2875
2943
  }
2876
2944
  p5.outro(chalk6.red("Deploy failed."));
@@ -3236,10 +3304,10 @@ you'll need a Meta Business account.
3236
3304
  initialValue: true
3237
3305
  });
3238
3306
  if (!proceed || p7.isCancel(proceed)) return;
3239
- const spinner13 = p7.spinner();
3240
- spinner13.start("Generating QR code...");
3307
+ const spinner14 = p7.spinner();
3308
+ spinner14.start("Generating QR code...");
3241
3309
  try {
3242
- spinner13.stop("");
3310
+ spinner14.stop("");
3243
3311
  console.log(chalk8.cyan(`
3244
3312
  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
3245
3313
  \u2551 \u2551
@@ -3271,7 +3339,7 @@ Scan this QR code with WhatsApp:
3271
3339
  p7.log.success("WhatsApp connected!");
3272
3340
  }
3273
3341
  } catch (error) {
3274
- spinner13.stop("Error connecting WhatsApp");
3342
+ spinner14.stop("Error connecting WhatsApp");
3275
3343
  p7.log.error(error instanceof Error ? error.message : "Unknown error");
3276
3344
  }
3277
3345
  }
@@ -3302,15 +3370,15 @@ To create a Telegram bot:
3302
3370
  }
3303
3371
  });
3304
3372
  if (p7.isCancel(token)) return;
3305
- const spinner13 = p7.spinner();
3306
- spinner13.start("Verifying bot token...");
3373
+ const spinner14 = p7.spinner();
3374
+ spinner14.start("Verifying bot token...");
3307
3375
  try {
3308
3376
  const response = await fetch(`https://api.telegram.org/bot${token}/getMe`);
3309
3377
  const data = await response.json();
3310
3378
  if (!data.ok) {
3311
3379
  throw new Error(data.description || "Invalid token");
3312
3380
  }
3313
- spinner13.stop("Bot verified!");
3381
+ spinner14.stop("Bot verified!");
3314
3382
  config.setChannelConfig("telegram", {
3315
3383
  enabled: true,
3316
3384
  botToken: token,
@@ -3318,7 +3386,7 @@ To create a Telegram bot:
3318
3386
  });
3319
3387
  p7.log.success(`Connected to @${data.result.username}`);
3320
3388
  } catch (error) {
3321
- spinner13.stop("Verification failed");
3389
+ spinner14.stop("Verification failed");
3322
3390
  p7.log.error(error instanceof Error ? error.message : "Invalid token");
3323
3391
  }
3324
3392
  }
@@ -3456,10 +3524,10 @@ This requires:
3456
3524
  p7.log.info("iMessage support coming soon.");
3457
3525
  }
3458
3526
  async function startAllChannels(config) {
3459
- const spinner13 = p7.spinner();
3460
- spinner13.start("Starting channel gateway...");
3527
+ const spinner14 = p7.spinner();
3528
+ spinner14.start("Starting channel gateway...");
3461
3529
  await new Promise((resolve) => setTimeout(resolve, 1e3));
3462
- spinner13.stop("Gateway started");
3530
+ spinner14.stop("Gateway started");
3463
3531
  console.log(chalk8.green(`
3464
3532
  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
3465
3533
  \u2551 Gateway is running! \u2551
@@ -3473,10 +3541,10 @@ async function startAllChannels(config) {
3473
3541
  `));
3474
3542
  }
3475
3543
  async function stopAllChannels(config) {
3476
- const spinner13 = p7.spinner();
3477
- spinner13.start("Stopping gateway...");
3544
+ const spinner14 = p7.spinner();
3545
+ spinner14.start("Stopping gateway...");
3478
3546
  await new Promise((resolve) => setTimeout(resolve, 500));
3479
- spinner13.stop("Gateway stopped");
3547
+ spinner14.stop("Gateway stopped");
3480
3548
  }
3481
3549
  async function deployGatewayWizard(config) {
3482
3550
  p7.log.info(chalk8.bold("Deploy Gateway to Cloud"));
@@ -3591,10 +3659,10 @@ import glob2 from "fast-glob";
3591
3659
  import * as path8 from "path";
3592
3660
  async function securityCommand() {
3593
3661
  p9.intro(chalk10.bgCyan.black(" Security Audit "));
3594
- const spinner13 = p9.spinner();
3595
- spinner13.start("Scanning for security issues...");
3662
+ const spinner14 = p9.spinner();
3663
+ spinner14.start("Scanning for security issues...");
3596
3664
  const issues = await runSecurityScan();
3597
- spinner13.stop("Scan complete");
3665
+ spinner14.stop("Scan complete");
3598
3666
  if (issues.length === 0) {
3599
3667
  console.log(chalk10.green("\n\u2713 No security issues found!\n"));
3600
3668
  displaySecurityScore(100);
@@ -3688,10 +3756,10 @@ async function generateCommand(type) {
3688
3756
  validate: (v) => !v ? "Name is required" : void 0
3689
3757
  });
3690
3758
  if (p10.isCancel(name)) return;
3691
- const spinner13 = p10.spinner();
3692
- spinner13.start("Generating...");
3759
+ const spinner14 = p10.spinner();
3760
+ spinner14.start("Generating...");
3693
3761
  await generateFile(generateType, name);
3694
- spinner13.stop(`Generated ${name}`);
3762
+ spinner14.stop(`Generated ${name}`);
3695
3763
  p10.outro("");
3696
3764
  }
3697
3765
  async function generateFile(type, name) {
@@ -3836,13 +3904,13 @@ import * as p11 from "@clack/prompts";
3836
3904
  import chalk12 from "chalk";
3837
3905
  async function fixCommand() {
3838
3906
  p11.intro(chalk12.bgCyan.black(" Auto-Fix "));
3839
- const spinner13 = p11.spinner();
3840
- spinner13.start("Analyzing code...");
3907
+ const spinner14 = p11.spinner();
3908
+ spinner14.start("Analyzing code...");
3841
3909
  const result = await runPatternCheck(true);
3842
3910
  if (result.passed) {
3843
- spinner13.stop("No issues found!");
3911
+ spinner14.stop("No issues found!");
3844
3912
  } else {
3845
- spinner13.stop(`Fixed ${result.violations.length} issues`);
3913
+ spinner14.stop(`Fixed ${result.violations.length} issues`);
3846
3914
  }
3847
3915
  p11.outro(chalk12.green("Done!"));
3848
3916
  }
@@ -4043,8 +4111,8 @@ function generateColorPalette(hex) {
4043
4111
  };
4044
4112
  }
4045
4113
  async function checkDesign() {
4046
- const spinner13 = p12.spinner();
4047
- spinner13.start("Checking design quality...");
4114
+ const spinner14 = p12.spinner();
4115
+ spinner14.start("Checking design quality...");
4048
4116
  const cwd = process.cwd();
4049
4117
  const issues = [];
4050
4118
  const glob3 = (await import("fast-glob")).default;
@@ -4070,7 +4138,7 @@ async function checkDesign() {
4070
4138
  }
4071
4139
  }
4072
4140
  }
4073
- spinner13.stop("Check complete");
4141
+ spinner14.stop("Check complete");
4074
4142
  if (issues.length === 0) {
4075
4143
  console.log(chalk13.green("\n\u2713 No design issues found!\n"));
4076
4144
  } else {
@@ -4126,8 +4194,8 @@ async function prdCommand(filePath) {
4126
4194
  if (p13.isCancel(file)) return;
4127
4195
  prdPath = file;
4128
4196
  }
4129
- const spinner13 = p13.spinner();
4130
- spinner13.start("Reading PRD...");
4197
+ const spinner14 = p13.spinner();
4198
+ spinner14.start("Reading PRD...");
4131
4199
  let prdContent;
4132
4200
  try {
4133
4201
  if (prdPath.startsWith("http")) {
@@ -4137,21 +4205,21 @@ async function prdCommand(filePath) {
4137
4205
  prdContent = await fs11.readFile(prdPath, "utf-8");
4138
4206
  }
4139
4207
  } catch (error) {
4140
- spinner13.stop("Error");
4208
+ spinner14.stop("Error");
4141
4209
  p13.log.error(`Could not read PRD: ${error instanceof Error ? error.message : "Unknown error"}`);
4142
4210
  return;
4143
4211
  }
4144
- spinner13.stop("PRD loaded");
4145
- spinner13.start("Analyzing PRD...");
4212
+ spinner14.stop("PRD loaded");
4213
+ spinner14.start("Analyzing PRD...");
4146
4214
  const anthropicCreds = config.getCredentials("anthropic");
4147
4215
  if (!anthropicCreds?.apiKey) {
4148
- spinner13.stop("Error");
4216
+ spinner14.stop("Error");
4149
4217
  p13.log.error("Anthropic API key not configured.");
4150
4218
  return;
4151
4219
  }
4152
4220
  const anthropic = new Anthropic3({ apiKey: anthropicCreds.apiKey });
4153
4221
  const parsed = await parsePRD(anthropic, prdContent);
4154
- spinner13.stop("PRD analyzed");
4222
+ spinner14.stop("PRD analyzed");
4155
4223
  console.log(chalk14.bold("\n\u{1F4CB} Extracted from PRD:\n"));
4156
4224
  console.log(` ${chalk14.cyan("Name:")} ${parsed.name}`);
4157
4225
  console.log(` ${chalk14.cyan("Description:")} ${parsed.description}`);
@@ -4230,35 +4298,35 @@ For database, list tables/entities needed.
4230
4298
  For integrations, list third-party services mentioned.`
4231
4299
  }]
4232
4300
  });
4233
- const text10 = response.content[0].type === "text" ? response.content[0].text : "";
4234
- const jsonMatch = text10.match(/\{[\s\S]*\}/);
4301
+ const text11 = response.content[0].type === "text" ? response.content[0].text : "";
4302
+ const jsonMatch = text11.match(/\{[\s\S]*\}/);
4235
4303
  if (!jsonMatch) {
4236
4304
  throw new Error("Could not parse PRD");
4237
4305
  }
4238
4306
  return JSON.parse(jsonMatch[0]);
4239
4307
  }
4240
4308
  async function buildFromPRD(prd, options, anthropic, config) {
4241
- const spinner13 = p13.spinner();
4309
+ const spinner14 = p13.spinner();
4242
4310
  const projectPath = path11.join(process.cwd(), prd.name);
4243
- spinner13.start("Creating project structure...");
4311
+ spinner14.start("Creating project structure...");
4244
4312
  await fs11.ensureDir(projectPath);
4245
4313
  await fs11.ensureDir(path11.join(projectPath, ".codebakers"));
4246
4314
  await fs11.ensureDir(path11.join(projectPath, "src", "app"));
4247
4315
  await fs11.ensureDir(path11.join(projectPath, "src", "components"));
4248
4316
  await fs11.ensureDir(path11.join(projectPath, "src", "lib"));
4249
- spinner13.stop("Project structure created");
4250
- spinner13.start("Saving PRD...");
4317
+ spinner14.stop("Project structure created");
4318
+ spinner14.start("Saving PRD...");
4251
4319
  await fs11.writeFile(path11.join(projectPath, "PRD.md"), await fs11.readFile(process.cwd(), "utf-8").catch(() => JSON.stringify(prd, null, 2)));
4252
4320
  await fs11.writeJson(path11.join(projectPath, ".codebakers", "prd.json"), prd, { spaces: 2 });
4253
4321
  await fs11.writeJson(path11.join(projectPath, ".codebakers", "design.json"), {
4254
4322
  profile: options.designProfile,
4255
4323
  colors: prd.design.brandColor ? { brand: prd.design.brandColor } : void 0
4256
4324
  }, { spaces: 2 });
4257
- spinner13.stop("PRD saved");
4258
- spinner13.start("Generating build plan...");
4325
+ spinner14.stop("PRD saved");
4326
+ spinner14.start("Generating build plan...");
4259
4327
  const buildPlan = await generateBuildPlan(anthropic, prd, options.designProfile);
4260
4328
  await fs11.writeJson(path11.join(projectPath, ".codebakers", "build-plan.json"), buildPlan, { spaces: 2 });
4261
- spinner13.stop("Build plan generated");
4329
+ spinner14.stop("Build plan generated");
4262
4330
  console.log(chalk14.bold("\n\u{1F3D7}\uFE0F Build Plan:\n"));
4263
4331
  buildPlan.phases.forEach((phase, i) => {
4264
4332
  console.log(chalk14.cyan(`Phase ${i + 1}: ${phase.name}`));
@@ -4282,12 +4350,12 @@ async function buildFromPRD(prd, options, anthropic, config) {
4282
4350
  \u{1F4E6} Phase ${i + 1}: ${phase.name}
4283
4351
  `));
4284
4352
  for (const task of phase.tasks) {
4285
- spinner13.start(task);
4353
+ spinner14.start(task);
4286
4354
  try {
4287
4355
  await executeTask(anthropic, projectPath, task, prd, options.designProfile);
4288
- spinner13.stop(`\u2713 ${task}`);
4356
+ spinner14.stop(`\u2713 ${task}`);
4289
4357
  } catch (error) {
4290
- spinner13.stop(`\u2717 ${task}`);
4358
+ spinner14.stop(`\u2717 ${task}`);
4291
4359
  p13.log.error(error instanceof Error ? error.message : "Task failed");
4292
4360
  const continueBuilding = await p13.confirm({
4293
4361
  message: "Continue with next task?",
@@ -4302,14 +4370,14 @@ async function buildFromPRD(prd, options, anthropic, config) {
4302
4370
  }
4303
4371
  if (options.createInfra) {
4304
4372
  console.log(chalk14.bold("\n\u{1F680} Setting up infrastructure...\n"));
4305
- spinner13.start("Creating GitHub repository...");
4306
- spinner13.stop("GitHub repository created");
4307
- spinner13.start("Creating Supabase project...");
4308
- spinner13.stop("Supabase project created");
4309
- spinner13.start("Creating Vercel project...");
4310
- spinner13.stop("Vercel project created");
4311
- spinner13.start("Deploying...");
4312
- spinner13.stop("Deployed!");
4373
+ spinner14.start("Creating GitHub repository...");
4374
+ spinner14.stop("GitHub repository created");
4375
+ spinner14.start("Creating Supabase project...");
4376
+ spinner14.stop("Supabase project created");
4377
+ spinner14.start("Creating Vercel project...");
4378
+ spinner14.stop("Vercel project created");
4379
+ spinner14.start("Deploying...");
4380
+ spinner14.stop("Deployed!");
4313
4381
  }
4314
4382
  p13.outro(chalk14.green(`
4315
4383
  \u2713 Project built from PRD!
@@ -4362,8 +4430,8 @@ Phases should be:
4362
4430
  Keep tasks specific and actionable.`
4363
4431
  }]
4364
4432
  });
4365
- const text10 = response.content[0].type === "text" ? response.content[0].text : "";
4366
- const jsonMatch = text10.match(/\{[\s\S]*\}/);
4433
+ const text11 = response.content[0].type === "text" ? response.content[0].text : "";
4434
+ const jsonMatch = text11.match(/\{[\s\S]*\}/);
4367
4435
  if (!jsonMatch) {
4368
4436
  throw new Error("Could not generate build plan");
4369
4437
  }
@@ -4411,10 +4479,10 @@ Follow these rules:
4411
4479
  Generate ALL files needed for this task.`
4412
4480
  }]
4413
4481
  });
4414
- const text10 = response.content[0].type === "text" ? response.content[0].text : "";
4482
+ const text11 = response.content[0].type === "text" ? response.content[0].text : "";
4415
4483
  const fileRegex = /<<<FILE:\s*(.+?)>>>([\s\S]*?)<<<END_FILE>>>/g;
4416
4484
  let match;
4417
- while ((match = fileRegex.exec(text10)) !== null) {
4485
+ while ((match = fileRegex.exec(text11)) !== null) {
4418
4486
  const filePath = path11.join(projectPath, match[1].trim());
4419
4487
  const content = match[2].trim();
4420
4488
  await fs11.ensureDir(path11.dirname(filePath));
@@ -4517,18 +4585,18 @@ async function advisorsCommand() {
4517
4585
  console.log(chalk15.bold("\n\n\u{1F3AF} The Dream Team is reviewing your project...\n"));
4518
4586
  const advisorFeedback = [];
4519
4587
  for (const advisor of DREAM_TEAM) {
4520
- const spinner14 = p14.spinner();
4521
- spinner14.start(`${advisor.icon} ${advisor.name} is analyzing...`);
4588
+ const spinner15 = p14.spinner();
4589
+ spinner15.start(`${advisor.icon} ${advisor.name} is analyzing...`);
4522
4590
  const feedback = await getAdvisorFeedback(anthropic, advisor, brief);
4523
4591
  advisorFeedback.push(feedback);
4524
- spinner14.stop(`${advisor.icon} ${advisor.name} complete`);
4592
+ spinner15.stop(`${advisor.icon} ${advisor.name} complete`);
4525
4593
  console.log(chalk15.dim(` Score: ${feedback.score}/10 - "${feedback.feedback.slice(0, 80)}..."
4526
4594
  `));
4527
4595
  }
4528
- const spinner13 = p14.spinner();
4529
- spinner13.start("Generating comprehensive report...");
4596
+ const spinner14 = p14.spinner();
4597
+ spinner14.start("Generating comprehensive report...");
4530
4598
  const report = await generateReport(anthropic, brief, advisorFeedback);
4531
- spinner13.stop("Report generated");
4599
+ spinner14.stop("Report generated");
4532
4600
  displayReportSummary(report);
4533
4601
  const savePath = await saveReport(report, brief.name);
4534
4602
  p14.outro(chalk15.green(`
@@ -4673,8 +4741,8 @@ Respond with JSON only:
4673
4741
  Score 1-10 based on your area of expertise. Be honest but constructive.`
4674
4742
  }]
4675
4743
  });
4676
- const text10 = response.content[0].type === "text" ? response.content[0].text : "";
4677
- const jsonMatch = text10.match(/\{[\s\S]*\}/);
4744
+ const text11 = response.content[0].type === "text" ? response.content[0].text : "";
4745
+ const jsonMatch = text11.match(/\{[\s\S]*\}/);
4678
4746
  if (!jsonMatch) {
4679
4747
  return {
4680
4748
  advisor: advisor.name,
@@ -4757,8 +4825,8 @@ Generate a complete JSON report:
4757
4825
  Be specific, actionable, and realistic based on the timeline and budget.`
4758
4826
  }]
4759
4827
  });
4760
- const text10 = response.content[0].type === "text" ? response.content[0].text : "";
4761
- const jsonMatch = text10.match(/\{[\s\S]*\}/);
4828
+ const text11 = response.content[0].type === "text" ? response.content[0].text : "";
4829
+ const jsonMatch = text11.match(/\{[\s\S]*\}/);
4762
4830
  const parsed = jsonMatch ? JSON.parse(jsonMatch[0]) : {};
4763
4831
  return {
4764
4832
  projectName: brief.name,
@@ -4897,9 +4965,9 @@ ${report.technicalPlan.architecture}
4897
4965
  ${report.technicalPlan.stack?.map((s) => `- ${s}`).join("\n") || "TBD"}
4898
4966
 
4899
4967
  ### Development Phases
4900
- ${report.technicalPlan.phases?.map((p16) => `
4901
- #### ${p16.name} (${p16.duration})
4902
- ${p16.deliverables.map((d) => `- ${d}`).join("\n")}
4968
+ ${report.technicalPlan.phases?.map((p17) => `
4969
+ #### ${p17.name} (${p17.duration})
4970
+ ${p17.deliverables.map((d) => `- ${d}`).join("\n")}
4903
4971
  `).join("\n") || "TBD"}
4904
4972
 
4905
4973
  ### MVP Features
@@ -4913,12 +4981,12 @@ ${report.technicalPlan.futureFeatures?.map((f) => `- ${f}`).join("\n") || "TBD"}
4913
4981
  ## UX Plan
4914
4982
 
4915
4983
  ### User Personas
4916
- ${report.uxPlan.userPersonas?.map((p16) => `
4917
- #### ${p16.name}
4918
- ${p16.description}
4984
+ ${report.uxPlan.userPersonas?.map((p17) => `
4985
+ #### ${p17.name}
4986
+ ${p17.description}
4919
4987
 
4920
4988
  **Goals:**
4921
- ${p16.goals.map((g) => `- ${g}`).join("\n")}
4989
+ ${p17.goals.map((g) => `- ${g}`).join("\n")}
4922
4990
  `).join("\n") || "TBD"}
4923
4991
 
4924
4992
  ### User Journeys
@@ -4928,7 +4996,7 @@ ${report.uxPlan.userJourneys?.map((j) => `- ${j}`).join("\n") || "TBD"}
4928
4996
  ${report.uxPlan.keyScreens?.map((s) => `- ${s}`).join("\n") || "TBD"}
4929
4997
 
4930
4998
  ### Design Principles
4931
- ${report.uxPlan.designPrinciples?.map((p16) => `- ${p16}`).join("\n") || "TBD"}
4999
+ ${report.uxPlan.designPrinciples?.map((p17) => `- ${p17}`).join("\n") || "TBD"}
4932
5000
 
4933
5001
  ---
4934
5002
 
@@ -4943,7 +5011,7 @@ ${report.businessPlan.pricing}
4943
5011
  ### Projections
4944
5012
  | Month | Users | Revenue |
4945
5013
  |-------|-------|---------|
4946
- ${report.businessPlan.projections?.map((p16) => `| ${p16.month} | ${p16.users} | $${p16.revenue} |`).join("\n") || "| TBD | TBD | TBD |"}
5014
+ ${report.businessPlan.projections?.map((p17) => `| ${p17.month} | ${p17.users} | $${p17.revenue} |`).join("\n") || "| TBD | TBD | TBD |"}
4947
5015
 
4948
5016
  ### KPIs
4949
5017
  ${report.businessPlan.kpis?.map((k) => `- ${k}`).join("\n") || "TBD"}
@@ -4980,6 +5048,334 @@ ${report.actionItems.filter((a) => a.priority === "LOW").map((a) => `- [ ] ${a.t
4980
5048
  `;
4981
5049
  }
4982
5050
 
5051
+ // src/commands/migrate.ts
5052
+ import * as p15 from "@clack/prompts";
5053
+ import chalk16 from "chalk";
5054
+ import { execa as execa5 } from "execa";
5055
+ import * as fs13 from "fs-extra";
5056
+ import * as path13 from "path";
5057
+ async function migrateCommand(options = {}) {
5058
+ const config = new Config();
5059
+ if (!config.isInProject()) {
5060
+ p15.log.error("Not in a CodeBakers project.");
5061
+ return;
5062
+ }
5063
+ p15.intro(chalk16.bgCyan.black(" Database Migrations "));
5064
+ const migrationTool = await detectMigrationTool();
5065
+ if (!migrationTool) {
5066
+ p15.log.error("No migration tool detected. Supported: Drizzle, Prisma, Supabase CLI");
5067
+ return;
5068
+ }
5069
+ p15.log.info(`Detected: ${migrationTool}`);
5070
+ const action = options.push ? "push" : options.generate ? "generate" : options.status ? "status" : await p15.select({
5071
+ message: "What do you want to do?",
5072
+ options: [
5073
+ { value: "status", label: "\u{1F4CA} Check migration status" },
5074
+ { value: "generate", label: "\u{1F4DD} Generate migration" },
5075
+ { value: "push", label: "\u{1F680} Push to database" },
5076
+ { value: "pull", label: "\u2B07\uFE0F Pull from database" }
5077
+ ]
5078
+ });
5079
+ if (p15.isCancel(action)) return;
5080
+ switch (action) {
5081
+ case "status":
5082
+ await checkMigrationStatus(migrationTool);
5083
+ break;
5084
+ case "generate":
5085
+ await generateMigration(migrationTool);
5086
+ break;
5087
+ case "push":
5088
+ await pushMigration(migrationTool);
5089
+ break;
5090
+ case "pull":
5091
+ await pullSchema(migrationTool);
5092
+ break;
5093
+ }
5094
+ }
5095
+ async function detectMigrationTool() {
5096
+ const cwd = process.cwd();
5097
+ if (fs13.existsSync(path13.join(cwd, "drizzle.config.ts")) || fs13.existsSync(path13.join(cwd, "drizzle.config.js"))) {
5098
+ return "drizzle";
5099
+ }
5100
+ if (fs13.existsSync(path13.join(cwd, "prisma", "schema.prisma"))) {
5101
+ return "prisma";
5102
+ }
5103
+ if (fs13.existsSync(path13.join(cwd, "supabase", "migrations"))) {
5104
+ return "supabase";
5105
+ }
5106
+ const pkgPath = path13.join(cwd, "package.json");
5107
+ if (fs13.existsSync(pkgPath)) {
5108
+ const pkg = await fs13.readJson(pkgPath);
5109
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
5110
+ if (deps["drizzle-orm"] || deps["drizzle-kit"]) return "drizzle";
5111
+ if (deps["prisma"] || deps["@prisma/client"]) return "prisma";
5112
+ }
5113
+ return null;
5114
+ }
5115
+ async function checkMigrationStatus(tool) {
5116
+ const spinner14 = p15.spinner();
5117
+ spinner14.start("Checking migration status...");
5118
+ try {
5119
+ let result;
5120
+ switch (tool) {
5121
+ case "drizzle":
5122
+ result = await execa5("npx", ["drizzle-kit", "check"], { cwd: process.cwd(), reject: false });
5123
+ break;
5124
+ case "prisma":
5125
+ result = await execa5("npx", ["prisma", "migrate", "status"], { cwd: process.cwd(), reject: false });
5126
+ break;
5127
+ case "supabase":
5128
+ result = await execa5("npx", ["supabase", "migration", "list"], { cwd: process.cwd(), reject: false });
5129
+ break;
5130
+ }
5131
+ spinner14.stop("Status check complete");
5132
+ if (result?.stdout) {
5133
+ console.log(chalk16.dim(result.stdout));
5134
+ }
5135
+ if (result?.stderr) {
5136
+ console.log(chalk16.yellow(result.stderr));
5137
+ }
5138
+ } catch (error) {
5139
+ spinner14.stop("Error checking status");
5140
+ p15.log.error(error instanceof Error ? error.message : "Unknown error");
5141
+ }
5142
+ }
5143
+ async function generateMigration(tool) {
5144
+ const name = await p15.text({
5145
+ message: "Migration name:",
5146
+ placeholder: "add_users_table",
5147
+ validate: (v) => !v ? "Name required" : void 0
5148
+ });
5149
+ if (p15.isCancel(name)) return;
5150
+ const spinner14 = p15.spinner();
5151
+ spinner14.start("Generating migration...");
5152
+ try {
5153
+ let result;
5154
+ switch (tool) {
5155
+ case "drizzle":
5156
+ result = await execa5("npx", ["drizzle-kit", "generate", "--name", name], { cwd: process.cwd(), reject: false });
5157
+ break;
5158
+ case "prisma":
5159
+ result = await execa5("npx", ["prisma", "migrate", "dev", "--name", name, "--create-only"], { cwd: process.cwd(), reject: false });
5160
+ break;
5161
+ case "supabase":
5162
+ result = await execa5("npx", ["supabase", "migration", "new", name], { cwd: process.cwd(), reject: false });
5163
+ break;
5164
+ }
5165
+ spinner14.stop("Migration generated");
5166
+ if (result?.stdout) {
5167
+ console.log(chalk16.dim(result.stdout));
5168
+ }
5169
+ } catch (error) {
5170
+ spinner14.stop("Error generating migration");
5171
+ p15.log.error(error instanceof Error ? error.message : "Unknown error");
5172
+ }
5173
+ }
5174
+ async function pushMigration(tool) {
5175
+ const spinner14 = p15.spinner();
5176
+ spinner14.start("Pushing migration to database...");
5177
+ try {
5178
+ let result;
5179
+ let migrationSql = "";
5180
+ switch (tool) {
5181
+ case "drizzle":
5182
+ result = await execa5("npx", ["drizzle-kit", "push"], {
5183
+ cwd: process.cwd(),
5184
+ reject: false,
5185
+ env: { ...process.env }
5186
+ });
5187
+ break;
5188
+ case "prisma":
5189
+ result = await execa5("npx", ["prisma", "db", "push"], {
5190
+ cwd: process.cwd(),
5191
+ reject: false
5192
+ });
5193
+ break;
5194
+ case "supabase":
5195
+ result = await execa5("npx", ["supabase", "db", "push"], {
5196
+ cwd: process.cwd(),
5197
+ reject: false
5198
+ });
5199
+ break;
5200
+ }
5201
+ if (result?.exitCode !== 0) {
5202
+ spinner14.stop("Migration push failed");
5203
+ const errorOutput = result?.stderr || result?.stdout || "";
5204
+ console.log(chalk16.red("\nError:\n"));
5205
+ console.log(chalk16.dim(errorOutput));
5206
+ migrationSql = await extractMigrationSQL(tool, errorOutput);
5207
+ if (migrationSql) {
5208
+ const copied = await copyToClipboard(migrationSql);
5209
+ if (copied) {
5210
+ console.log(chalk16.green(`
5211
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
5212
+ \u2551 \u{1F4CB} MIGRATION SQL COPIED TO CLIPBOARD! \u2551
5213
+ \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563
5214
+ \u2551 \u2551
5215
+ \u2551 The migration could not be pushed automatically. \u2551
5216
+ \u2551 The SQL has been copied to your clipboard. \u2551
5217
+ \u2551 \u2551
5218
+ \u2551 Next steps: \u2551
5219
+ \u2551 1. Go to your Supabase Dashboard \u2192 SQL Editor \u2551
5220
+ \u2551 2. Paste the SQL (Ctrl+V / Cmd+V) \u2551
5221
+ \u2551 3. Review and run it \u2551
5222
+ \u2551 \u2551
5223
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
5224
+ `));
5225
+ const showSql = await p15.confirm({
5226
+ message: "Show the SQL here too?",
5227
+ initialValue: true
5228
+ });
5229
+ if (showSql && !p15.isCancel(showSql)) {
5230
+ console.log(chalk16.cyan("\n--- SQL Migration ---\n"));
5231
+ console.log(migrationSql);
5232
+ console.log(chalk16.cyan("\n--- End SQL ---\n"));
5233
+ }
5234
+ } else {
5235
+ console.log(chalk16.yellow(`
5236
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
5237
+ \u2551 \u26A0\uFE0F Could not copy to clipboard \u2551
5238
+ \u2551 \u2551
5239
+ \u2551 Here's the SQL to run manually: \u2551
5240
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
5241
+ `));
5242
+ console.log(chalk16.cyan(migrationSql));
5243
+ }
5244
+ const sqlPath = path13.join(process.cwd(), ".codebakers", "failed-migration.sql");
5245
+ await fs13.ensureDir(path13.dirname(sqlPath));
5246
+ await fs13.writeFile(sqlPath, migrationSql);
5247
+ console.log(chalk16.dim(`
5248
+ Also saved to: ${sqlPath}
5249
+ `));
5250
+ } else {
5251
+ p15.log.error("Could not extract migration SQL. Check the error above.");
5252
+ }
5253
+ return;
5254
+ }
5255
+ spinner14.stop("Migration pushed successfully!");
5256
+ if (result?.stdout) {
5257
+ console.log(chalk16.dim(result.stdout));
5258
+ }
5259
+ p15.log.success("Database updated!");
5260
+ } catch (error) {
5261
+ spinner14.stop("Error");
5262
+ const errorMsg = error instanceof Error ? error.message : "Unknown error";
5263
+ p15.log.error(errorMsg);
5264
+ const migrationSql = await extractMigrationSQL(tool, errorMsg);
5265
+ if (migrationSql) {
5266
+ await copyToClipboard(migrationSql);
5267
+ console.log(chalk16.green("\n\u{1F4CB} Migration SQL copied to clipboard!\n"));
5268
+ console.log(chalk16.cyan(migrationSql));
5269
+ }
5270
+ }
5271
+ }
5272
+ async function pullSchema(tool) {
5273
+ const spinner14 = p15.spinner();
5274
+ spinner14.start("Pulling schema from database...");
5275
+ try {
5276
+ let result;
5277
+ switch (tool) {
5278
+ case "drizzle":
5279
+ result = await execa5("npx", ["drizzle-kit", "introspect"], { cwd: process.cwd(), reject: false });
5280
+ break;
5281
+ case "prisma":
5282
+ result = await execa5("npx", ["prisma", "db", "pull"], { cwd: process.cwd(), reject: false });
5283
+ break;
5284
+ case "supabase":
5285
+ result = await execa5("npx", ["supabase", "db", "pull"], { cwd: process.cwd(), reject: false });
5286
+ break;
5287
+ }
5288
+ spinner14.stop("Schema pulled");
5289
+ if (result?.stdout) {
5290
+ console.log(chalk16.dim(result.stdout));
5291
+ }
5292
+ } catch (error) {
5293
+ spinner14.stop("Error pulling schema");
5294
+ p15.log.error(error instanceof Error ? error.message : "Unknown error");
5295
+ }
5296
+ }
5297
+ async function extractMigrationSQL(tool, errorOutput) {
5298
+ const cwd = process.cwd();
5299
+ try {
5300
+ switch (tool) {
5301
+ case "drizzle": {
5302
+ const drizzleDir = path13.join(cwd, "drizzle");
5303
+ if (fs13.existsSync(drizzleDir)) {
5304
+ const files = await fs13.readdir(drizzleDir);
5305
+ const sqlFiles = files.filter((f) => f.endsWith(".sql")).sort().reverse();
5306
+ if (sqlFiles.length > 0) {
5307
+ const latestMigration = await fs13.readFile(path13.join(drizzleDir, sqlFiles[0]), "utf-8");
5308
+ return latestMigration;
5309
+ }
5310
+ }
5311
+ const result = await execa5("npx", ["drizzle-kit", "generate", "--sql"], {
5312
+ cwd,
5313
+ reject: false
5314
+ });
5315
+ if (result?.stdout) {
5316
+ const sqlMatch2 = result.stdout.match(/```sql([\s\S]*?)```/);
5317
+ if (sqlMatch2) return sqlMatch2[1].trim();
5318
+ return result.stdout;
5319
+ }
5320
+ break;
5321
+ }
5322
+ case "prisma": {
5323
+ const migrationsDir = path13.join(cwd, "prisma", "migrations");
5324
+ if (fs13.existsSync(migrationsDir)) {
5325
+ const migrations = await fs13.readdir(migrationsDir);
5326
+ const sorted = migrations.filter((m) => m !== "migration_lock.toml").sort().reverse();
5327
+ if (sorted.length > 0) {
5328
+ const migrationPath = path13.join(migrationsDir, sorted[0], "migration.sql");
5329
+ if (fs13.existsSync(migrationPath)) {
5330
+ return await fs13.readFile(migrationPath, "utf-8");
5331
+ }
5332
+ }
5333
+ }
5334
+ break;
5335
+ }
5336
+ case "supabase": {
5337
+ const migrationsDir = path13.join(cwd, "supabase", "migrations");
5338
+ if (fs13.existsSync(migrationsDir)) {
5339
+ const files = await fs13.readdir(migrationsDir);
5340
+ const sqlFiles = files.filter((f) => f.endsWith(".sql")).sort().reverse();
5341
+ if (sqlFiles.length > 0) {
5342
+ return await fs13.readFile(path13.join(migrationsDir, sqlFiles[0]), "utf-8");
5343
+ }
5344
+ }
5345
+ break;
5346
+ }
5347
+ }
5348
+ const sqlMatch = errorOutput.match(/(CREATE|ALTER|DROP|INSERT|UPDATE|DELETE)[\s\S]+?;/gi);
5349
+ if (sqlMatch) {
5350
+ return sqlMatch.join("\n\n");
5351
+ }
5352
+ } catch {
5353
+ }
5354
+ return null;
5355
+ }
5356
+ async function copyToClipboard(text11) {
5357
+ try {
5358
+ const platform = process.platform;
5359
+ if (platform === "win32") {
5360
+ const proc = await execa5("clip", { input: text11, reject: false });
5361
+ return proc.exitCode === 0;
5362
+ } else if (platform === "darwin") {
5363
+ const proc = await execa5("pbcopy", { input: text11, reject: false });
5364
+ return proc.exitCode === 0;
5365
+ } else {
5366
+ try {
5367
+ const proc = await execa5("xclip", ["-selection", "clipboard"], { input: text11, reject: false });
5368
+ return proc.exitCode === 0;
5369
+ } catch {
5370
+ const proc = await execa5("xsel", ["--clipboard", "--input"], { input: text11, reject: false });
5371
+ return proc.exitCode === 0;
5372
+ }
5373
+ }
5374
+ } catch {
5375
+ return false;
5376
+ }
5377
+ }
5378
+
4983
5379
  // src/index.ts
4984
5380
  var VERSION2 = "1.0.0";
4985
5381
  var logo = `
@@ -4994,23 +5390,24 @@ async function showMainMenu() {
4994
5390
  const config = new Config();
4995
5391
  const isSetup = config.isConfigured();
4996
5392
  console.log(gradient.pastel.multiline(logo));
4997
- console.log(chalk16.dim(` v${VERSION2} \u2014 AI dev team that follows the rules
5393
+ console.log(chalk17.dim(` v${VERSION2} \u2014 AI dev team that follows the rules
4998
5394
  `));
4999
5395
  if (!isSetup) {
5000
5396
  console.log(boxen(
5001
- chalk16.yellow("Welcome to CodeBakers! Let's get you set up."),
5397
+ chalk17.yellow("Welcome to CodeBakers! Let's get you set up."),
5002
5398
  { padding: 1, borderColor: "yellow", borderStyle: "round" }
5003
5399
  ));
5004
5400
  await setupCommand();
5005
5401
  return;
5006
5402
  }
5007
5403
  const inProject = config.isInProject();
5008
- const action = await p15.select({
5404
+ const action = await p16.select({
5009
5405
  message: "What do you want to do?",
5010
5406
  options: inProject ? [
5011
5407
  { value: "code", label: "\u{1F4AC} Code with AI", hint: "build features, fix bugs" },
5012
5408
  { value: "check", label: "\u{1F50D} Check code quality", hint: "run pattern enforcement" },
5013
5409
  { value: "deploy", label: "\u{1F680} Deploy", hint: "deploy to Vercel" },
5410
+ { value: "migrate", label: "\u{1F5C4}\uFE0F Database migrations", hint: "push, generate, status" },
5014
5411
  { value: "fix", label: "\u{1F527} Fix errors", hint: "auto-fix build/deploy errors" },
5015
5412
  { value: "generate", label: "\u26A1 Generate", hint: "scaffold components, pages" },
5016
5413
  { value: "status", label: "\u{1F4CA} Project status", hint: "view project health" },
@@ -5040,8 +5437,8 @@ async function showMainMenu() {
5040
5437
  { value: "help", label: "\u2753 Help" }
5041
5438
  ]
5042
5439
  });
5043
- if (p15.isCancel(action)) {
5044
- p15.cancel("Goodbye!");
5440
+ if (p16.isCancel(action)) {
5441
+ p16.cancel("Goodbye!");
5045
5442
  process.exit(0);
5046
5443
  }
5047
5444
  switch (action) {
@@ -5054,6 +5451,9 @@ async function showMainMenu() {
5054
5451
  case "deploy":
5055
5452
  await deployCommand();
5056
5453
  break;
5454
+ case "migrate":
5455
+ await migrateCommand();
5456
+ break;
5057
5457
  case "fix":
5058
5458
  await fixCommand();
5059
5459
  break;
@@ -5099,27 +5499,27 @@ async function showMainMenu() {
5099
5499
  }
5100
5500
  function showHelp2() {
5101
5501
  console.log(boxen(`
5102
- ${chalk16.bold("CodeBakers CLI")} \u2014 AI dev team that follows the rules
5103
-
5104
- ${chalk16.bold("Commands:")}
5105
- ${chalk16.cyan("codebakers")} Interactive menu (or just run with no args)
5106
- ${chalk16.cyan("codebakers init")} Create a new project
5107
- ${chalk16.cyan("codebakers code")} Start AI coding session
5108
- ${chalk16.cyan("codebakers check")} Run pattern enforcement
5109
- ${chalk16.cyan("codebakers deploy")} Deploy to production
5110
- ${chalk16.cyan("codebakers fix")} Auto-fix errors
5111
- ${chalk16.cyan("codebakers generate")} Generate components/pages
5112
- ${chalk16.cyan("codebakers connect")} Connect external services
5113
- ${chalk16.cyan("codebakers gateway")} Manage messaging channels
5114
- ${chalk16.cyan("codebakers status")} View project status
5115
- ${chalk16.cyan("codebakers security")} Run security audit
5116
- ${chalk16.cyan("codebakers learn")} View/manage learning
5117
-
5118
- ${chalk16.bold("Help at any time:")}
5119
- Press ${chalk16.yellow("?")} during any command to get contextual help
5120
-
5121
- ${chalk16.bold("Documentation:")}
5122
- ${chalk16.dim("https://codebakers.dev/docs")}
5502
+ ${chalk17.bold("CodeBakers CLI")} \u2014 AI dev team that follows the rules
5503
+
5504
+ ${chalk17.bold("Commands:")}
5505
+ ${chalk17.cyan("codebakers")} Interactive menu (or just run with no args)
5506
+ ${chalk17.cyan("codebakers init")} Create a new project
5507
+ ${chalk17.cyan("codebakers code")} Start AI coding session
5508
+ ${chalk17.cyan("codebakers check")} Run pattern enforcement
5509
+ ${chalk17.cyan("codebakers deploy")} Deploy to production
5510
+ ${chalk17.cyan("codebakers fix")} Auto-fix errors
5511
+ ${chalk17.cyan("codebakers generate")} Generate components/pages
5512
+ ${chalk17.cyan("codebakers connect")} Connect external services
5513
+ ${chalk17.cyan("codebakers gateway")} Manage messaging channels
5514
+ ${chalk17.cyan("codebakers status")} View project status
5515
+ ${chalk17.cyan("codebakers security")} Run security audit
5516
+ ${chalk17.cyan("codebakers learn")} View/manage learning
5517
+
5518
+ ${chalk17.bold("Help at any time:")}
5519
+ Press ${chalk17.yellow("?")} during any command to get contextual help
5520
+
5521
+ ${chalk17.bold("Documentation:")}
5522
+ ${chalk17.dim("https://codebakers.dev/docs")}
5123
5523
  `, { padding: 1, borderColor: "cyan", borderStyle: "round" }));
5124
5524
  }
5125
5525
  var program = new Command();
@@ -5139,6 +5539,7 @@ program.command("learn").description("View and manage learning settings").option
5139
5539
  program.command("design [action]").description("Manage design system (profile, palette, check)").action(designCommand);
5140
5540
  program.command("prd [file]").description("Build entire project from a PRD document").action(prdCommand);
5141
5541
  program.command("advisors").alias("dream-team").description("Consult with the CodeBakers Dream Team advisory board").action(advisorsCommand);
5542
+ program.command("migrate").alias("db").description("Database migrations (push, generate, status)").option("--push", "Push migrations to database").option("--generate", "Generate new migration").option("--status", "Check migration status").action(migrateCommand);
5142
5543
  var args = process.argv.slice(2);
5143
5544
  if (args.length === 0) {
5144
5545
  checkForUpdates().catch(() => {