codebakers 2.0.3 → 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 +513 -180
- package/package.json +1 -1
- package/src/commands/migrate.ts +419 -0
- package/src/index.ts +14 -0
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
|
|
6
|
-
import
|
|
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
|
|
|
@@ -372,10 +372,10 @@ async function setupCommand() {
|
|
|
372
372
|
return;
|
|
373
373
|
}
|
|
374
374
|
if (action === "reset") {
|
|
375
|
-
const
|
|
375
|
+
const confirm9 = await p.confirm({
|
|
376
376
|
message: "Are you sure? This will remove all credentials and settings."
|
|
377
377
|
});
|
|
378
|
-
if (
|
|
378
|
+
if (confirm9) {
|
|
379
379
|
p.outro(chalk2.yellow("Configuration reset. Run `codebakers setup` again."));
|
|
380
380
|
}
|
|
381
381
|
return;
|
|
@@ -439,7 +439,7 @@ ${chalk2.dim("and are never sent to our servers.")}`,
|
|
|
439
439
|
p.outro(chalk2.green("\u2713 Setup complete! Run `codebakers init` to create your first project."));
|
|
440
440
|
}
|
|
441
441
|
async function connectService(config, serviceKey, serviceName, required) {
|
|
442
|
-
const
|
|
442
|
+
const spinner14 = p.spinner();
|
|
443
443
|
switch (serviceKey) {
|
|
444
444
|
case "github": {
|
|
445
445
|
p.log.info(`${chalk2.bold("GitHub")} - Opens browser for OAuth authorization`);
|
|
@@ -913,10 +913,10 @@ var SupabaseService = class {
|
|
|
913
913
|
throw new Error("Failed to list projects");
|
|
914
914
|
}
|
|
915
915
|
const projects = await response.json();
|
|
916
|
-
return projects.map((
|
|
917
|
-
id:
|
|
918
|
-
name:
|
|
919
|
-
region:
|
|
916
|
+
return projects.map((p17) => ({
|
|
917
|
+
id: p17.id,
|
|
918
|
+
name: p17.name,
|
|
919
|
+
region: p17.region
|
|
920
920
|
}));
|
|
921
921
|
}
|
|
922
922
|
};
|
|
@@ -1336,20 +1336,20 @@ Domain: ${domain || "Vercel default"}`,
|
|
|
1336
1336
|
p2.cancel("Project creation cancelled.");
|
|
1337
1337
|
return;
|
|
1338
1338
|
}
|
|
1339
|
-
const
|
|
1339
|
+
const spinner14 = p2.spinner();
|
|
1340
1340
|
const projectPath = path2.join(process.cwd(), projectName);
|
|
1341
1341
|
try {
|
|
1342
|
-
|
|
1342
|
+
spinner14.start("Creating local project...");
|
|
1343
1343
|
await createLocalProject(projectPath, projectConfig);
|
|
1344
|
-
|
|
1345
|
-
|
|
1344
|
+
spinner14.stop("Local project created");
|
|
1345
|
+
spinner14.start("Installing dependencies...");
|
|
1346
1346
|
await execa2("pnpm", ["install"], { cwd: projectPath });
|
|
1347
|
-
|
|
1347
|
+
spinner14.stop("Dependencies installed");
|
|
1348
1348
|
if (services.includes("github")) {
|
|
1349
|
-
|
|
1349
|
+
spinner14.start("Creating GitHub repository...");
|
|
1350
1350
|
const github = new GitHubService(config);
|
|
1351
1351
|
const repo = await github.createRepo(projectName, { private: true });
|
|
1352
|
-
|
|
1352
|
+
spinner14.stop(`GitHub repo created: ${repo.html_url}`);
|
|
1353
1353
|
await execa2("git", ["init"], { cwd: projectPath });
|
|
1354
1354
|
await execa2("git", ["add", "."], { cwd: projectPath });
|
|
1355
1355
|
await execa2("git", ["commit", "-m", "Initial commit by CodeBakers"], { cwd: projectPath });
|
|
@@ -1357,10 +1357,10 @@ Domain: ${domain || "Vercel default"}`,
|
|
|
1357
1357
|
await execa2("git", ["push", "-u", "origin", "main"], { cwd: projectPath });
|
|
1358
1358
|
}
|
|
1359
1359
|
if (services.includes("supabase")) {
|
|
1360
|
-
|
|
1360
|
+
spinner14.start("Creating Supabase project...");
|
|
1361
1361
|
const supabase = new SupabaseService(config);
|
|
1362
1362
|
const project = await supabase.createProject(projectName);
|
|
1363
|
-
|
|
1363
|
+
spinner14.stop(`Supabase project created: ${project.name}`);
|
|
1364
1364
|
await fs2.writeJson(
|
|
1365
1365
|
path2.join(projectPath, ".codebakers", "supabase.json"),
|
|
1366
1366
|
{ projectId: project.id, projectUrl: project.api_url },
|
|
@@ -1368,26 +1368,26 @@ Domain: ${domain || "Vercel default"}`,
|
|
|
1368
1368
|
);
|
|
1369
1369
|
}
|
|
1370
1370
|
if (services.includes("vercel")) {
|
|
1371
|
-
|
|
1371
|
+
spinner14.start("Creating Vercel project...");
|
|
1372
1372
|
const vercel = new VercelService(config);
|
|
1373
1373
|
const project = await vercel.createProject(projectName);
|
|
1374
|
-
|
|
1374
|
+
spinner14.stop(`Vercel project created`);
|
|
1375
1375
|
if (domain) {
|
|
1376
|
-
|
|
1376
|
+
spinner14.start(`Configuring domain: ${domain}...`);
|
|
1377
1377
|
await vercel.addDomain(projectName, domain);
|
|
1378
|
-
|
|
1378
|
+
spinner14.stop("Domain configured");
|
|
1379
1379
|
}
|
|
1380
|
-
|
|
1380
|
+
spinner14.start("Deploying to Vercel...");
|
|
1381
1381
|
const deployment = await vercel.deploy(projectPath);
|
|
1382
|
-
|
|
1382
|
+
spinner14.stop(`Deployed: ${deployment.url}`);
|
|
1383
1383
|
}
|
|
1384
|
-
|
|
1384
|
+
spinner14.start("Generating CLAUDE.md...");
|
|
1385
1385
|
const claudeMd = generateClaudeMd(projectConfig);
|
|
1386
1386
|
await fs2.writeFile(path2.join(projectPath, "CLAUDE.md"), claudeMd);
|
|
1387
|
-
|
|
1388
|
-
|
|
1387
|
+
spinner14.stop("CLAUDE.md generated");
|
|
1388
|
+
spinner14.start("Setting up CodeBakers enforcement...");
|
|
1389
1389
|
await setupGitHooks(projectPath);
|
|
1390
|
-
|
|
1390
|
+
spinner14.stop("CodeBakers enforcement configured");
|
|
1391
1391
|
config.addProject({
|
|
1392
1392
|
name: projectName,
|
|
1393
1393
|
path: projectPath,
|
|
@@ -1407,7 +1407,7 @@ ${chalk3.dim("Shortcuts:")}
|
|
|
1407
1407
|
${chalk3.cyan("codebakers deploy")} \u2014 Deploy to production
|
|
1408
1408
|
`));
|
|
1409
1409
|
} catch (error) {
|
|
1410
|
-
|
|
1410
|
+
spinner14.stop("Error occurred");
|
|
1411
1411
|
p2.log.error(`Failed to create project: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1412
1412
|
const cleanup = await p2.confirm({
|
|
1413
1413
|
message: "Clean up partially created project?"
|
|
@@ -2133,17 +2133,17 @@ async function checkCommand(options = {}) {
|
|
|
2133
2133
|
return;
|
|
2134
2134
|
}
|
|
2135
2135
|
p3.intro(chalk4.bgCyan.black(" CodeBakers Pattern Check "));
|
|
2136
|
-
const
|
|
2137
|
-
|
|
2136
|
+
const spinner14 = p3.spinner();
|
|
2137
|
+
spinner14.start("Analyzing code...");
|
|
2138
2138
|
const result = await runPatternCheck(options.fix || false);
|
|
2139
|
-
|
|
2139
|
+
spinner14.stop("Analysis complete");
|
|
2140
2140
|
displayResults(result);
|
|
2141
2141
|
if (result.violations.length > 0 && options.fix) {
|
|
2142
2142
|
const fixable = result.violations.filter((v) => v.autoFixable);
|
|
2143
2143
|
if (fixable.length > 0) {
|
|
2144
|
-
|
|
2144
|
+
spinner14.start(`Auto-fixing ${fixable.length} violations...`);
|
|
2145
2145
|
await autoFix(fixable);
|
|
2146
|
-
|
|
2146
|
+
spinner14.stop("Auto-fix complete");
|
|
2147
2147
|
}
|
|
2148
2148
|
}
|
|
2149
2149
|
const errors = result.violations.filter((v) => v.severity === "error");
|
|
@@ -2335,14 +2335,14 @@ async function codeCommand(prompt, options = {}) {
|
|
|
2335
2335
|
}
|
|
2336
2336
|
}
|
|
2337
2337
|
async function processUserInput(userInput, messages, anthropic, systemPrompt, projectContext, config) {
|
|
2338
|
-
const
|
|
2338
|
+
const spinner14 = p4.spinner();
|
|
2339
2339
|
messages.push({ role: "user", content: userInput });
|
|
2340
2340
|
const wizardResult = await checkForWizard(userInput);
|
|
2341
2341
|
if (wizardResult) {
|
|
2342
2342
|
messages[messages.length - 1].content = wizardResult;
|
|
2343
2343
|
}
|
|
2344
2344
|
try {
|
|
2345
|
-
|
|
2345
|
+
spinner14.start("Thinking...");
|
|
2346
2346
|
const response = await anthropic.messages.create({
|
|
2347
2347
|
model: "claude-sonnet-4-20250514",
|
|
2348
2348
|
max_tokens: 8192,
|
|
@@ -2352,7 +2352,7 @@ async function processUserInput(userInput, messages, anthropic, systemPrompt, pr
|
|
|
2352
2352
|
content: m.content
|
|
2353
2353
|
}))
|
|
2354
2354
|
});
|
|
2355
|
-
|
|
2355
|
+
spinner14.stop("");
|
|
2356
2356
|
const assistantMessage = response.content[0].type === "text" ? response.content[0].text : "";
|
|
2357
2357
|
messages.push({ role: "assistant", content: assistantMessage });
|
|
2358
2358
|
const actions = parseActions(assistantMessage);
|
|
@@ -2367,11 +2367,11 @@ async function processUserInput(userInput, messages, anthropic, systemPrompt, pr
|
|
|
2367
2367
|
initialValue: true
|
|
2368
2368
|
});
|
|
2369
2369
|
if (proceed && !p4.isCancel(proceed)) {
|
|
2370
|
-
|
|
2370
|
+
spinner14.start("Building...");
|
|
2371
2371
|
for (const action of actions) {
|
|
2372
|
-
await executeAction(action,
|
|
2372
|
+
await executeAction(action, spinner14);
|
|
2373
2373
|
}
|
|
2374
|
-
|
|
2374
|
+
spinner14.stop("Build complete");
|
|
2375
2375
|
console.log(chalk5.dim("\n\u{1F50D} Running CodeBakers check..."));
|
|
2376
2376
|
const checkResult = await runPatternCheck(false);
|
|
2377
2377
|
if (checkResult.violations.length > 0) {
|
|
@@ -2382,9 +2382,9 @@ async function processUserInput(userInput, messages, anthropic, systemPrompt, pr
|
|
|
2382
2382
|
initialValue: true
|
|
2383
2383
|
});
|
|
2384
2384
|
if (autoFix2 && !p4.isCancel(autoFix2)) {
|
|
2385
|
-
|
|
2385
|
+
spinner14.start("Auto-fixing...");
|
|
2386
2386
|
await autoFixViolations(checkResult.violations, anthropic, systemPrompt);
|
|
2387
|
-
|
|
2387
|
+
spinner14.stop("Violations fixed");
|
|
2388
2388
|
}
|
|
2389
2389
|
} else {
|
|
2390
2390
|
console.log(chalk5.green("\u2713 All patterns satisfied"));
|
|
@@ -2395,7 +2395,7 @@ async function processUserInput(userInput, messages, anthropic, systemPrompt, pr
|
|
|
2395
2395
|
console.log("\n" + assistantMessage + "\n");
|
|
2396
2396
|
}
|
|
2397
2397
|
} catch (error) {
|
|
2398
|
-
|
|
2398
|
+
spinner14.stop("Error");
|
|
2399
2399
|
console.log(chalk5.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2400
2400
|
}
|
|
2401
2401
|
}
|
|
@@ -2507,14 +2507,14 @@ function parseActions(response) {
|
|
|
2507
2507
|
}
|
|
2508
2508
|
return actions;
|
|
2509
2509
|
}
|
|
2510
|
-
async function executeAction(action,
|
|
2510
|
+
async function executeAction(action, spinner14) {
|
|
2511
2511
|
const cwd = process.cwd();
|
|
2512
2512
|
switch (action.type) {
|
|
2513
2513
|
case "CREATE_FILE": {
|
|
2514
2514
|
const filePath = path5.join(cwd, action.path);
|
|
2515
2515
|
await fs5.ensureDir(path5.dirname(filePath));
|
|
2516
2516
|
await fs5.writeFile(filePath, action.content);
|
|
2517
|
-
|
|
2517
|
+
spinner14.message(`Created ${action.path}`);
|
|
2518
2518
|
break;
|
|
2519
2519
|
}
|
|
2520
2520
|
case "EDIT_FILE": {
|
|
@@ -2524,13 +2524,13 @@ async function executeAction(action, spinner13) {
|
|
|
2524
2524
|
if (action.find && content.includes(action.find)) {
|
|
2525
2525
|
content = content.replace(action.find, action.replace || "");
|
|
2526
2526
|
await fs5.writeFile(filePath, content);
|
|
2527
|
-
|
|
2527
|
+
spinner14.message(`Edited ${action.path}`);
|
|
2528
2528
|
}
|
|
2529
2529
|
}
|
|
2530
2530
|
break;
|
|
2531
2531
|
}
|
|
2532
2532
|
case "RUN_COMMAND": {
|
|
2533
|
-
|
|
2533
|
+
spinner14.message(`Running: ${action.command}`);
|
|
2534
2534
|
const [cmd, ...args2] = action.command.split(" ");
|
|
2535
2535
|
await execa3(cmd, args2, { cwd, stdio: "pipe" });
|
|
2536
2536
|
break;
|
|
@@ -2539,7 +2539,7 @@ async function executeAction(action, spinner13) {
|
|
|
2539
2539
|
const filePath = path5.join(cwd, action.path);
|
|
2540
2540
|
if (await fs5.pathExists(filePath)) {
|
|
2541
2541
|
await fs5.remove(filePath);
|
|
2542
|
-
|
|
2542
|
+
spinner14.message(`Deleted ${action.path}`);
|
|
2543
2543
|
}
|
|
2544
2544
|
break;
|
|
2545
2545
|
}
|
|
@@ -2787,12 +2787,12 @@ async function deployCommand(options = {}) {
|
|
|
2787
2787
|
return;
|
|
2788
2788
|
}
|
|
2789
2789
|
p5.intro(chalk6.bgCyan.black(" Deploy to Production "));
|
|
2790
|
-
const
|
|
2790
|
+
const spinner14 = p5.spinner();
|
|
2791
2791
|
if (options.check !== false) {
|
|
2792
|
-
|
|
2792
|
+
spinner14.start("Running CodeBakers check...");
|
|
2793
2793
|
const checkResult = await runPatternCheck(false);
|
|
2794
2794
|
if (!checkResult.passed) {
|
|
2795
|
-
|
|
2795
|
+
spinner14.stop("");
|
|
2796
2796
|
const errors = checkResult.violations.filter((v) => v.severity === "error");
|
|
2797
2797
|
if (errors.length > 0) {
|
|
2798
2798
|
p5.log.error(`${errors.length} pattern violations found. Fix before deploying.`);
|
|
@@ -2813,9 +2813,9 @@ async function deployCommand(options = {}) {
|
|
|
2813
2813
|
p5.outro(chalk6.red("Deploy cancelled."));
|
|
2814
2814
|
return;
|
|
2815
2815
|
}
|
|
2816
|
-
|
|
2816
|
+
spinner14.start("Auto-fixing with AI...");
|
|
2817
2817
|
await autoFixWithAI(config, errors);
|
|
2818
|
-
|
|
2818
|
+
spinner14.stop("Auto-fix complete");
|
|
2819
2819
|
const recheck = await runPatternCheck(false);
|
|
2820
2820
|
if (!recheck.passed) {
|
|
2821
2821
|
p5.log.error("Some violations remain. Manual fix required.");
|
|
@@ -2824,23 +2824,23 @@ async function deployCommand(options = {}) {
|
|
|
2824
2824
|
}
|
|
2825
2825
|
}
|
|
2826
2826
|
}
|
|
2827
|
-
|
|
2827
|
+
spinner14.stop("Pattern check passed");
|
|
2828
2828
|
}
|
|
2829
|
-
|
|
2829
|
+
spinner14.start("Running TypeScript check...");
|
|
2830
2830
|
try {
|
|
2831
2831
|
await execa4("npx", ["tsc", "--noEmit"], { cwd: process.cwd() });
|
|
2832
|
-
|
|
2832
|
+
spinner14.stop("TypeScript check passed");
|
|
2833
2833
|
} catch (error) {
|
|
2834
|
-
|
|
2834
|
+
spinner14.stop("");
|
|
2835
2835
|
p5.log.error("TypeScript errors found.");
|
|
2836
2836
|
const fix = await p5.confirm({
|
|
2837
2837
|
message: "Attempt to fix TypeScript errors?",
|
|
2838
2838
|
initialValue: true
|
|
2839
2839
|
});
|
|
2840
2840
|
if (fix && !p5.isCancel(fix)) {
|
|
2841
|
-
|
|
2841
|
+
spinner14.start("Fixing TypeScript errors...");
|
|
2842
2842
|
const fixed = await fixTypeScriptErrors(config);
|
|
2843
|
-
|
|
2843
|
+
spinner14.stop(fixed ? "TypeScript errors fixed" : "Could not auto-fix all errors");
|
|
2844
2844
|
if (!fixed) {
|
|
2845
2845
|
p5.outro(chalk6.red("Deploy cancelled."));
|
|
2846
2846
|
return;
|
|
@@ -2850,12 +2850,12 @@ async function deployCommand(options = {}) {
|
|
|
2850
2850
|
return;
|
|
2851
2851
|
}
|
|
2852
2852
|
}
|
|
2853
|
-
|
|
2853
|
+
spinner14.start("Building project...");
|
|
2854
2854
|
try {
|
|
2855
2855
|
await execa4("pnpm", ["build"], { cwd: process.cwd() });
|
|
2856
|
-
|
|
2856
|
+
spinner14.stop("Build successful");
|
|
2857
2857
|
} catch (error) {
|
|
2858
|
-
|
|
2858
|
+
spinner14.stop("");
|
|
2859
2859
|
p5.log.error("Build failed.");
|
|
2860
2860
|
const errorOutput = error instanceof Error ? error.message : "Unknown error";
|
|
2861
2861
|
console.log(chalk6.dim(errorOutput));
|
|
@@ -2864,16 +2864,16 @@ async function deployCommand(options = {}) {
|
|
|
2864
2864
|
initialValue: true
|
|
2865
2865
|
});
|
|
2866
2866
|
if (fix && !p5.isCancel(fix)) {
|
|
2867
|
-
|
|
2867
|
+
spinner14.start("Fixing build errors...");
|
|
2868
2868
|
const fixed = await fixBuildErrors(config, errorOutput);
|
|
2869
|
-
|
|
2869
|
+
spinner14.stop(fixed ? "Build errors fixed" : "Could not auto-fix");
|
|
2870
2870
|
if (fixed) {
|
|
2871
|
-
|
|
2871
|
+
spinner14.start("Retrying build...");
|
|
2872
2872
|
try {
|
|
2873
2873
|
await execa4("pnpm", ["build"], { cwd: process.cwd() });
|
|
2874
|
-
|
|
2874
|
+
spinner14.stop("Build successful");
|
|
2875
2875
|
} catch {
|
|
2876
|
-
|
|
2876
|
+
spinner14.stop("Build still failing");
|
|
2877
2877
|
p5.outro(chalk6.red("Deploy cancelled."));
|
|
2878
2878
|
return;
|
|
2879
2879
|
}
|
|
@@ -2886,10 +2886,10 @@ async function deployCommand(options = {}) {
|
|
|
2886
2886
|
return;
|
|
2887
2887
|
}
|
|
2888
2888
|
}
|
|
2889
|
-
|
|
2889
|
+
spinner14.start("Checking for uncommitted changes...");
|
|
2890
2890
|
const { stdout: gitStatus } = await execa4("git", ["status", "--porcelain"], { cwd: process.cwd() });
|
|
2891
2891
|
if (gitStatus.trim()) {
|
|
2892
|
-
|
|
2892
|
+
spinner14.stop("");
|
|
2893
2893
|
const commit = await p5.confirm({
|
|
2894
2894
|
message: "You have uncommitted changes. Commit before deploying?",
|
|
2895
2895
|
initialValue: true
|
|
@@ -2903,20 +2903,20 @@ async function deployCommand(options = {}) {
|
|
|
2903
2903
|
if (!p5.isCancel(message)) {
|
|
2904
2904
|
await execa4("git", ["add", "."], { cwd: process.cwd() });
|
|
2905
2905
|
await execa4("git", ["commit", "-m", message], { cwd: process.cwd() });
|
|
2906
|
-
|
|
2906
|
+
spinner14.start("Pushing to GitHub...");
|
|
2907
2907
|
await execa4("git", ["push"], { cwd: process.cwd() });
|
|
2908
|
-
|
|
2908
|
+
spinner14.stop("Pushed to GitHub");
|
|
2909
2909
|
}
|
|
2910
2910
|
}
|
|
2911
2911
|
} else {
|
|
2912
|
-
|
|
2912
|
+
spinner14.stop("No uncommitted changes");
|
|
2913
2913
|
}
|
|
2914
2914
|
const deployType = options.preview ? "preview" : "production";
|
|
2915
|
-
|
|
2915
|
+
spinner14.start(`Deploying to ${deployType}...`);
|
|
2916
2916
|
try {
|
|
2917
2917
|
const vercel = new VercelService(config);
|
|
2918
2918
|
const deployment = await vercel.deploy(process.cwd(), !options.preview);
|
|
2919
|
-
|
|
2919
|
+
spinner14.stop("Deployment complete!");
|
|
2920
2920
|
console.log(boxedOutput(`
|
|
2921
2921
|
${chalk6.green("\u2713")} Deployed successfully!
|
|
2922
2922
|
|
|
@@ -2928,7 +2928,7 @@ ${chalk6.dim("View in Vercel Dashboard:")}
|
|
|
2928
2928
|
${chalk6.dim(deployment.dashboardUrl || "https://vercel.com/dashboard")}
|
|
2929
2929
|
`));
|
|
2930
2930
|
} catch (error) {
|
|
2931
|
-
|
|
2931
|
+
spinner14.stop("");
|
|
2932
2932
|
const errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
2933
2933
|
p5.log.error(`Deployment failed: ${errorMsg}`);
|
|
2934
2934
|
if (errorMsg.includes("Build failed")) {
|
|
@@ -2937,8 +2937,8 @@ ${chalk6.dim(deployment.dashboardUrl || "https://vercel.com/dashboard")}
|
|
|
2937
2937
|
initialValue: true
|
|
2938
2938
|
});
|
|
2939
2939
|
if (retry && !p5.isCancel(retry)) {
|
|
2940
|
-
|
|
2941
|
-
|
|
2940
|
+
spinner14.start("Analyzing Vercel build error...");
|
|
2941
|
+
spinner14.stop("Fix attempted");
|
|
2942
2942
|
}
|
|
2943
2943
|
}
|
|
2944
2944
|
p5.outro(chalk6.red("Deploy failed."));
|
|
@@ -3304,10 +3304,10 @@ you'll need a Meta Business account.
|
|
|
3304
3304
|
initialValue: true
|
|
3305
3305
|
});
|
|
3306
3306
|
if (!proceed || p7.isCancel(proceed)) return;
|
|
3307
|
-
const
|
|
3308
|
-
|
|
3307
|
+
const spinner14 = p7.spinner();
|
|
3308
|
+
spinner14.start("Generating QR code...");
|
|
3309
3309
|
try {
|
|
3310
|
-
|
|
3310
|
+
spinner14.stop("");
|
|
3311
3311
|
console.log(chalk8.cyan(`
|
|
3312
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
|
|
3313
3313
|
\u2551 \u2551
|
|
@@ -3339,7 +3339,7 @@ Scan this QR code with WhatsApp:
|
|
|
3339
3339
|
p7.log.success("WhatsApp connected!");
|
|
3340
3340
|
}
|
|
3341
3341
|
} catch (error) {
|
|
3342
|
-
|
|
3342
|
+
spinner14.stop("Error connecting WhatsApp");
|
|
3343
3343
|
p7.log.error(error instanceof Error ? error.message : "Unknown error");
|
|
3344
3344
|
}
|
|
3345
3345
|
}
|
|
@@ -3370,15 +3370,15 @@ To create a Telegram bot:
|
|
|
3370
3370
|
}
|
|
3371
3371
|
});
|
|
3372
3372
|
if (p7.isCancel(token)) return;
|
|
3373
|
-
const
|
|
3374
|
-
|
|
3373
|
+
const spinner14 = p7.spinner();
|
|
3374
|
+
spinner14.start("Verifying bot token...");
|
|
3375
3375
|
try {
|
|
3376
3376
|
const response = await fetch(`https://api.telegram.org/bot${token}/getMe`);
|
|
3377
3377
|
const data = await response.json();
|
|
3378
3378
|
if (!data.ok) {
|
|
3379
3379
|
throw new Error(data.description || "Invalid token");
|
|
3380
3380
|
}
|
|
3381
|
-
|
|
3381
|
+
spinner14.stop("Bot verified!");
|
|
3382
3382
|
config.setChannelConfig("telegram", {
|
|
3383
3383
|
enabled: true,
|
|
3384
3384
|
botToken: token,
|
|
@@ -3386,7 +3386,7 @@ To create a Telegram bot:
|
|
|
3386
3386
|
});
|
|
3387
3387
|
p7.log.success(`Connected to @${data.result.username}`);
|
|
3388
3388
|
} catch (error) {
|
|
3389
|
-
|
|
3389
|
+
spinner14.stop("Verification failed");
|
|
3390
3390
|
p7.log.error(error instanceof Error ? error.message : "Invalid token");
|
|
3391
3391
|
}
|
|
3392
3392
|
}
|
|
@@ -3524,10 +3524,10 @@ This requires:
|
|
|
3524
3524
|
p7.log.info("iMessage support coming soon.");
|
|
3525
3525
|
}
|
|
3526
3526
|
async function startAllChannels(config) {
|
|
3527
|
-
const
|
|
3528
|
-
|
|
3527
|
+
const spinner14 = p7.spinner();
|
|
3528
|
+
spinner14.start("Starting channel gateway...");
|
|
3529
3529
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3530
|
-
|
|
3530
|
+
spinner14.stop("Gateway started");
|
|
3531
3531
|
console.log(chalk8.green(`
|
|
3532
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
|
|
3533
3533
|
\u2551 Gateway is running! \u2551
|
|
@@ -3541,10 +3541,10 @@ async function startAllChannels(config) {
|
|
|
3541
3541
|
`));
|
|
3542
3542
|
}
|
|
3543
3543
|
async function stopAllChannels(config) {
|
|
3544
|
-
const
|
|
3545
|
-
|
|
3544
|
+
const spinner14 = p7.spinner();
|
|
3545
|
+
spinner14.start("Stopping gateway...");
|
|
3546
3546
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
3547
|
-
|
|
3547
|
+
spinner14.stop("Gateway stopped");
|
|
3548
3548
|
}
|
|
3549
3549
|
async function deployGatewayWizard(config) {
|
|
3550
3550
|
p7.log.info(chalk8.bold("Deploy Gateway to Cloud"));
|
|
@@ -3659,10 +3659,10 @@ import glob2 from "fast-glob";
|
|
|
3659
3659
|
import * as path8 from "path";
|
|
3660
3660
|
async function securityCommand() {
|
|
3661
3661
|
p9.intro(chalk10.bgCyan.black(" Security Audit "));
|
|
3662
|
-
const
|
|
3663
|
-
|
|
3662
|
+
const spinner14 = p9.spinner();
|
|
3663
|
+
spinner14.start("Scanning for security issues...");
|
|
3664
3664
|
const issues = await runSecurityScan();
|
|
3665
|
-
|
|
3665
|
+
spinner14.stop("Scan complete");
|
|
3666
3666
|
if (issues.length === 0) {
|
|
3667
3667
|
console.log(chalk10.green("\n\u2713 No security issues found!\n"));
|
|
3668
3668
|
displaySecurityScore(100);
|
|
@@ -3756,10 +3756,10 @@ async function generateCommand(type) {
|
|
|
3756
3756
|
validate: (v) => !v ? "Name is required" : void 0
|
|
3757
3757
|
});
|
|
3758
3758
|
if (p10.isCancel(name)) return;
|
|
3759
|
-
const
|
|
3760
|
-
|
|
3759
|
+
const spinner14 = p10.spinner();
|
|
3760
|
+
spinner14.start("Generating...");
|
|
3761
3761
|
await generateFile(generateType, name);
|
|
3762
|
-
|
|
3762
|
+
spinner14.stop(`Generated ${name}`);
|
|
3763
3763
|
p10.outro("");
|
|
3764
3764
|
}
|
|
3765
3765
|
async function generateFile(type, name) {
|
|
@@ -3904,13 +3904,13 @@ import * as p11 from "@clack/prompts";
|
|
|
3904
3904
|
import chalk12 from "chalk";
|
|
3905
3905
|
async function fixCommand() {
|
|
3906
3906
|
p11.intro(chalk12.bgCyan.black(" Auto-Fix "));
|
|
3907
|
-
const
|
|
3908
|
-
|
|
3907
|
+
const spinner14 = p11.spinner();
|
|
3908
|
+
spinner14.start("Analyzing code...");
|
|
3909
3909
|
const result = await runPatternCheck(true);
|
|
3910
3910
|
if (result.passed) {
|
|
3911
|
-
|
|
3911
|
+
spinner14.stop("No issues found!");
|
|
3912
3912
|
} else {
|
|
3913
|
-
|
|
3913
|
+
spinner14.stop(`Fixed ${result.violations.length} issues`);
|
|
3914
3914
|
}
|
|
3915
3915
|
p11.outro(chalk12.green("Done!"));
|
|
3916
3916
|
}
|
|
@@ -4111,8 +4111,8 @@ function generateColorPalette(hex) {
|
|
|
4111
4111
|
};
|
|
4112
4112
|
}
|
|
4113
4113
|
async function checkDesign() {
|
|
4114
|
-
const
|
|
4115
|
-
|
|
4114
|
+
const spinner14 = p12.spinner();
|
|
4115
|
+
spinner14.start("Checking design quality...");
|
|
4116
4116
|
const cwd = process.cwd();
|
|
4117
4117
|
const issues = [];
|
|
4118
4118
|
const glob3 = (await import("fast-glob")).default;
|
|
@@ -4138,7 +4138,7 @@ async function checkDesign() {
|
|
|
4138
4138
|
}
|
|
4139
4139
|
}
|
|
4140
4140
|
}
|
|
4141
|
-
|
|
4141
|
+
spinner14.stop("Check complete");
|
|
4142
4142
|
if (issues.length === 0) {
|
|
4143
4143
|
console.log(chalk13.green("\n\u2713 No design issues found!\n"));
|
|
4144
4144
|
} else {
|
|
@@ -4194,8 +4194,8 @@ async function prdCommand(filePath) {
|
|
|
4194
4194
|
if (p13.isCancel(file)) return;
|
|
4195
4195
|
prdPath = file;
|
|
4196
4196
|
}
|
|
4197
|
-
const
|
|
4198
|
-
|
|
4197
|
+
const spinner14 = p13.spinner();
|
|
4198
|
+
spinner14.start("Reading PRD...");
|
|
4199
4199
|
let prdContent;
|
|
4200
4200
|
try {
|
|
4201
4201
|
if (prdPath.startsWith("http")) {
|
|
@@ -4205,21 +4205,21 @@ async function prdCommand(filePath) {
|
|
|
4205
4205
|
prdContent = await fs11.readFile(prdPath, "utf-8");
|
|
4206
4206
|
}
|
|
4207
4207
|
} catch (error) {
|
|
4208
|
-
|
|
4208
|
+
spinner14.stop("Error");
|
|
4209
4209
|
p13.log.error(`Could not read PRD: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4210
4210
|
return;
|
|
4211
4211
|
}
|
|
4212
|
-
|
|
4213
|
-
|
|
4212
|
+
spinner14.stop("PRD loaded");
|
|
4213
|
+
spinner14.start("Analyzing PRD...");
|
|
4214
4214
|
const anthropicCreds = config.getCredentials("anthropic");
|
|
4215
4215
|
if (!anthropicCreds?.apiKey) {
|
|
4216
|
-
|
|
4216
|
+
spinner14.stop("Error");
|
|
4217
4217
|
p13.log.error("Anthropic API key not configured.");
|
|
4218
4218
|
return;
|
|
4219
4219
|
}
|
|
4220
4220
|
const anthropic = new Anthropic3({ apiKey: anthropicCreds.apiKey });
|
|
4221
4221
|
const parsed = await parsePRD(anthropic, prdContent);
|
|
4222
|
-
|
|
4222
|
+
spinner14.stop("PRD analyzed");
|
|
4223
4223
|
console.log(chalk14.bold("\n\u{1F4CB} Extracted from PRD:\n"));
|
|
4224
4224
|
console.log(` ${chalk14.cyan("Name:")} ${parsed.name}`);
|
|
4225
4225
|
console.log(` ${chalk14.cyan("Description:")} ${parsed.description}`);
|
|
@@ -4298,35 +4298,35 @@ For database, list tables/entities needed.
|
|
|
4298
4298
|
For integrations, list third-party services mentioned.`
|
|
4299
4299
|
}]
|
|
4300
4300
|
});
|
|
4301
|
-
const
|
|
4302
|
-
const jsonMatch =
|
|
4301
|
+
const text11 = response.content[0].type === "text" ? response.content[0].text : "";
|
|
4302
|
+
const jsonMatch = text11.match(/\{[\s\S]*\}/);
|
|
4303
4303
|
if (!jsonMatch) {
|
|
4304
4304
|
throw new Error("Could not parse PRD");
|
|
4305
4305
|
}
|
|
4306
4306
|
return JSON.parse(jsonMatch[0]);
|
|
4307
4307
|
}
|
|
4308
4308
|
async function buildFromPRD(prd, options, anthropic, config) {
|
|
4309
|
-
const
|
|
4309
|
+
const spinner14 = p13.spinner();
|
|
4310
4310
|
const projectPath = path11.join(process.cwd(), prd.name);
|
|
4311
|
-
|
|
4311
|
+
spinner14.start("Creating project structure...");
|
|
4312
4312
|
await fs11.ensureDir(projectPath);
|
|
4313
4313
|
await fs11.ensureDir(path11.join(projectPath, ".codebakers"));
|
|
4314
4314
|
await fs11.ensureDir(path11.join(projectPath, "src", "app"));
|
|
4315
4315
|
await fs11.ensureDir(path11.join(projectPath, "src", "components"));
|
|
4316
4316
|
await fs11.ensureDir(path11.join(projectPath, "src", "lib"));
|
|
4317
|
-
|
|
4318
|
-
|
|
4317
|
+
spinner14.stop("Project structure created");
|
|
4318
|
+
spinner14.start("Saving PRD...");
|
|
4319
4319
|
await fs11.writeFile(path11.join(projectPath, "PRD.md"), await fs11.readFile(process.cwd(), "utf-8").catch(() => JSON.stringify(prd, null, 2)));
|
|
4320
4320
|
await fs11.writeJson(path11.join(projectPath, ".codebakers", "prd.json"), prd, { spaces: 2 });
|
|
4321
4321
|
await fs11.writeJson(path11.join(projectPath, ".codebakers", "design.json"), {
|
|
4322
4322
|
profile: options.designProfile,
|
|
4323
4323
|
colors: prd.design.brandColor ? { brand: prd.design.brandColor } : void 0
|
|
4324
4324
|
}, { spaces: 2 });
|
|
4325
|
-
|
|
4326
|
-
|
|
4325
|
+
spinner14.stop("PRD saved");
|
|
4326
|
+
spinner14.start("Generating build plan...");
|
|
4327
4327
|
const buildPlan = await generateBuildPlan(anthropic, prd, options.designProfile);
|
|
4328
4328
|
await fs11.writeJson(path11.join(projectPath, ".codebakers", "build-plan.json"), buildPlan, { spaces: 2 });
|
|
4329
|
-
|
|
4329
|
+
spinner14.stop("Build plan generated");
|
|
4330
4330
|
console.log(chalk14.bold("\n\u{1F3D7}\uFE0F Build Plan:\n"));
|
|
4331
4331
|
buildPlan.phases.forEach((phase, i) => {
|
|
4332
4332
|
console.log(chalk14.cyan(`Phase ${i + 1}: ${phase.name}`));
|
|
@@ -4350,12 +4350,12 @@ async function buildFromPRD(prd, options, anthropic, config) {
|
|
|
4350
4350
|
\u{1F4E6} Phase ${i + 1}: ${phase.name}
|
|
4351
4351
|
`));
|
|
4352
4352
|
for (const task of phase.tasks) {
|
|
4353
|
-
|
|
4353
|
+
spinner14.start(task);
|
|
4354
4354
|
try {
|
|
4355
4355
|
await executeTask(anthropic, projectPath, task, prd, options.designProfile);
|
|
4356
|
-
|
|
4356
|
+
spinner14.stop(`\u2713 ${task}`);
|
|
4357
4357
|
} catch (error) {
|
|
4358
|
-
|
|
4358
|
+
spinner14.stop(`\u2717 ${task}`);
|
|
4359
4359
|
p13.log.error(error instanceof Error ? error.message : "Task failed");
|
|
4360
4360
|
const continueBuilding = await p13.confirm({
|
|
4361
4361
|
message: "Continue with next task?",
|
|
@@ -4370,14 +4370,14 @@ async function buildFromPRD(prd, options, anthropic, config) {
|
|
|
4370
4370
|
}
|
|
4371
4371
|
if (options.createInfra) {
|
|
4372
4372
|
console.log(chalk14.bold("\n\u{1F680} Setting up infrastructure...\n"));
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
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!");
|
|
4381
4381
|
}
|
|
4382
4382
|
p13.outro(chalk14.green(`
|
|
4383
4383
|
\u2713 Project built from PRD!
|
|
@@ -4430,8 +4430,8 @@ Phases should be:
|
|
|
4430
4430
|
Keep tasks specific and actionable.`
|
|
4431
4431
|
}]
|
|
4432
4432
|
});
|
|
4433
|
-
const
|
|
4434
|
-
const jsonMatch =
|
|
4433
|
+
const text11 = response.content[0].type === "text" ? response.content[0].text : "";
|
|
4434
|
+
const jsonMatch = text11.match(/\{[\s\S]*\}/);
|
|
4435
4435
|
if (!jsonMatch) {
|
|
4436
4436
|
throw new Error("Could not generate build plan");
|
|
4437
4437
|
}
|
|
@@ -4479,10 +4479,10 @@ Follow these rules:
|
|
|
4479
4479
|
Generate ALL files needed for this task.`
|
|
4480
4480
|
}]
|
|
4481
4481
|
});
|
|
4482
|
-
const
|
|
4482
|
+
const text11 = response.content[0].type === "text" ? response.content[0].text : "";
|
|
4483
4483
|
const fileRegex = /<<<FILE:\s*(.+?)>>>([\s\S]*?)<<<END_FILE>>>/g;
|
|
4484
4484
|
let match;
|
|
4485
|
-
while ((match = fileRegex.exec(
|
|
4485
|
+
while ((match = fileRegex.exec(text11)) !== null) {
|
|
4486
4486
|
const filePath = path11.join(projectPath, match[1].trim());
|
|
4487
4487
|
const content = match[2].trim();
|
|
4488
4488
|
await fs11.ensureDir(path11.dirname(filePath));
|
|
@@ -4585,18 +4585,18 @@ async function advisorsCommand() {
|
|
|
4585
4585
|
console.log(chalk15.bold("\n\n\u{1F3AF} The Dream Team is reviewing your project...\n"));
|
|
4586
4586
|
const advisorFeedback = [];
|
|
4587
4587
|
for (const advisor of DREAM_TEAM) {
|
|
4588
|
-
const
|
|
4589
|
-
|
|
4588
|
+
const spinner15 = p14.spinner();
|
|
4589
|
+
spinner15.start(`${advisor.icon} ${advisor.name} is analyzing...`);
|
|
4590
4590
|
const feedback = await getAdvisorFeedback(anthropic, advisor, brief);
|
|
4591
4591
|
advisorFeedback.push(feedback);
|
|
4592
|
-
|
|
4592
|
+
spinner15.stop(`${advisor.icon} ${advisor.name} complete`);
|
|
4593
4593
|
console.log(chalk15.dim(` Score: ${feedback.score}/10 - "${feedback.feedback.slice(0, 80)}..."
|
|
4594
4594
|
`));
|
|
4595
4595
|
}
|
|
4596
|
-
const
|
|
4597
|
-
|
|
4596
|
+
const spinner14 = p14.spinner();
|
|
4597
|
+
spinner14.start("Generating comprehensive report...");
|
|
4598
4598
|
const report = await generateReport(anthropic, brief, advisorFeedback);
|
|
4599
|
-
|
|
4599
|
+
spinner14.stop("Report generated");
|
|
4600
4600
|
displayReportSummary(report);
|
|
4601
4601
|
const savePath = await saveReport(report, brief.name);
|
|
4602
4602
|
p14.outro(chalk15.green(`
|
|
@@ -4741,8 +4741,8 @@ Respond with JSON only:
|
|
|
4741
4741
|
Score 1-10 based on your area of expertise. Be honest but constructive.`
|
|
4742
4742
|
}]
|
|
4743
4743
|
});
|
|
4744
|
-
const
|
|
4745
|
-
const jsonMatch =
|
|
4744
|
+
const text11 = response.content[0].type === "text" ? response.content[0].text : "";
|
|
4745
|
+
const jsonMatch = text11.match(/\{[\s\S]*\}/);
|
|
4746
4746
|
if (!jsonMatch) {
|
|
4747
4747
|
return {
|
|
4748
4748
|
advisor: advisor.name,
|
|
@@ -4825,8 +4825,8 @@ Generate a complete JSON report:
|
|
|
4825
4825
|
Be specific, actionable, and realistic based on the timeline and budget.`
|
|
4826
4826
|
}]
|
|
4827
4827
|
});
|
|
4828
|
-
const
|
|
4829
|
-
const jsonMatch =
|
|
4828
|
+
const text11 = response.content[0].type === "text" ? response.content[0].text : "";
|
|
4829
|
+
const jsonMatch = text11.match(/\{[\s\S]*\}/);
|
|
4830
4830
|
const parsed = jsonMatch ? JSON.parse(jsonMatch[0]) : {};
|
|
4831
4831
|
return {
|
|
4832
4832
|
projectName: brief.name,
|
|
@@ -4965,9 +4965,9 @@ ${report.technicalPlan.architecture}
|
|
|
4965
4965
|
${report.technicalPlan.stack?.map((s) => `- ${s}`).join("\n") || "TBD"}
|
|
4966
4966
|
|
|
4967
4967
|
### Development Phases
|
|
4968
|
-
${report.technicalPlan.phases?.map((
|
|
4969
|
-
#### ${
|
|
4970
|
-
${
|
|
4968
|
+
${report.technicalPlan.phases?.map((p17) => `
|
|
4969
|
+
#### ${p17.name} (${p17.duration})
|
|
4970
|
+
${p17.deliverables.map((d) => `- ${d}`).join("\n")}
|
|
4971
4971
|
`).join("\n") || "TBD"}
|
|
4972
4972
|
|
|
4973
4973
|
### MVP Features
|
|
@@ -4981,12 +4981,12 @@ ${report.technicalPlan.futureFeatures?.map((f) => `- ${f}`).join("\n") || "TBD"}
|
|
|
4981
4981
|
## UX Plan
|
|
4982
4982
|
|
|
4983
4983
|
### User Personas
|
|
4984
|
-
${report.uxPlan.userPersonas?.map((
|
|
4985
|
-
#### ${
|
|
4986
|
-
${
|
|
4984
|
+
${report.uxPlan.userPersonas?.map((p17) => `
|
|
4985
|
+
#### ${p17.name}
|
|
4986
|
+
${p17.description}
|
|
4987
4987
|
|
|
4988
4988
|
**Goals:**
|
|
4989
|
-
${
|
|
4989
|
+
${p17.goals.map((g) => `- ${g}`).join("\n")}
|
|
4990
4990
|
`).join("\n") || "TBD"}
|
|
4991
4991
|
|
|
4992
4992
|
### User Journeys
|
|
@@ -4996,7 +4996,7 @@ ${report.uxPlan.userJourneys?.map((j) => `- ${j}`).join("\n") || "TBD"}
|
|
|
4996
4996
|
${report.uxPlan.keyScreens?.map((s) => `- ${s}`).join("\n") || "TBD"}
|
|
4997
4997
|
|
|
4998
4998
|
### Design Principles
|
|
4999
|
-
${report.uxPlan.designPrinciples?.map((
|
|
4999
|
+
${report.uxPlan.designPrinciples?.map((p17) => `- ${p17}`).join("\n") || "TBD"}
|
|
5000
5000
|
|
|
5001
5001
|
---
|
|
5002
5002
|
|
|
@@ -5011,7 +5011,7 @@ ${report.businessPlan.pricing}
|
|
|
5011
5011
|
### Projections
|
|
5012
5012
|
| Month | Users | Revenue |
|
|
5013
5013
|
|-------|-------|---------|
|
|
5014
|
-
${report.businessPlan.projections?.map((
|
|
5014
|
+
${report.businessPlan.projections?.map((p17) => `| ${p17.month} | ${p17.users} | $${p17.revenue} |`).join("\n") || "| TBD | TBD | TBD |"}
|
|
5015
5015
|
|
|
5016
5016
|
### KPIs
|
|
5017
5017
|
${report.businessPlan.kpis?.map((k) => `- ${k}`).join("\n") || "TBD"}
|
|
@@ -5048,6 +5048,334 @@ ${report.actionItems.filter((a) => a.priority === "LOW").map((a) => `- [ ] ${a.t
|
|
|
5048
5048
|
`;
|
|
5049
5049
|
}
|
|
5050
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
|
+
|
|
5051
5379
|
// src/index.ts
|
|
5052
5380
|
var VERSION2 = "1.0.0";
|
|
5053
5381
|
var logo = `
|
|
@@ -5062,23 +5390,24 @@ async function showMainMenu() {
|
|
|
5062
5390
|
const config = new Config();
|
|
5063
5391
|
const isSetup = config.isConfigured();
|
|
5064
5392
|
console.log(gradient.pastel.multiline(logo));
|
|
5065
|
-
console.log(
|
|
5393
|
+
console.log(chalk17.dim(` v${VERSION2} \u2014 AI dev team that follows the rules
|
|
5066
5394
|
`));
|
|
5067
5395
|
if (!isSetup) {
|
|
5068
5396
|
console.log(boxen(
|
|
5069
|
-
|
|
5397
|
+
chalk17.yellow("Welcome to CodeBakers! Let's get you set up."),
|
|
5070
5398
|
{ padding: 1, borderColor: "yellow", borderStyle: "round" }
|
|
5071
5399
|
));
|
|
5072
5400
|
await setupCommand();
|
|
5073
5401
|
return;
|
|
5074
5402
|
}
|
|
5075
5403
|
const inProject = config.isInProject();
|
|
5076
|
-
const action = await
|
|
5404
|
+
const action = await p16.select({
|
|
5077
5405
|
message: "What do you want to do?",
|
|
5078
5406
|
options: inProject ? [
|
|
5079
5407
|
{ value: "code", label: "\u{1F4AC} Code with AI", hint: "build features, fix bugs" },
|
|
5080
5408
|
{ value: "check", label: "\u{1F50D} Check code quality", hint: "run pattern enforcement" },
|
|
5081
5409
|
{ value: "deploy", label: "\u{1F680} Deploy", hint: "deploy to Vercel" },
|
|
5410
|
+
{ value: "migrate", label: "\u{1F5C4}\uFE0F Database migrations", hint: "push, generate, status" },
|
|
5082
5411
|
{ value: "fix", label: "\u{1F527} Fix errors", hint: "auto-fix build/deploy errors" },
|
|
5083
5412
|
{ value: "generate", label: "\u26A1 Generate", hint: "scaffold components, pages" },
|
|
5084
5413
|
{ value: "status", label: "\u{1F4CA} Project status", hint: "view project health" },
|
|
@@ -5108,8 +5437,8 @@ async function showMainMenu() {
|
|
|
5108
5437
|
{ value: "help", label: "\u2753 Help" }
|
|
5109
5438
|
]
|
|
5110
5439
|
});
|
|
5111
|
-
if (
|
|
5112
|
-
|
|
5440
|
+
if (p16.isCancel(action)) {
|
|
5441
|
+
p16.cancel("Goodbye!");
|
|
5113
5442
|
process.exit(0);
|
|
5114
5443
|
}
|
|
5115
5444
|
switch (action) {
|
|
@@ -5122,6 +5451,9 @@ async function showMainMenu() {
|
|
|
5122
5451
|
case "deploy":
|
|
5123
5452
|
await deployCommand();
|
|
5124
5453
|
break;
|
|
5454
|
+
case "migrate":
|
|
5455
|
+
await migrateCommand();
|
|
5456
|
+
break;
|
|
5125
5457
|
case "fix":
|
|
5126
5458
|
await fixCommand();
|
|
5127
5459
|
break;
|
|
@@ -5167,27 +5499,27 @@ async function showMainMenu() {
|
|
|
5167
5499
|
}
|
|
5168
5500
|
function showHelp2() {
|
|
5169
5501
|
console.log(boxen(`
|
|
5170
|
-
${
|
|
5171
|
-
|
|
5172
|
-
${
|
|
5173
|
-
${
|
|
5174
|
-
${
|
|
5175
|
-
${
|
|
5176
|
-
${
|
|
5177
|
-
${
|
|
5178
|
-
${
|
|
5179
|
-
${
|
|
5180
|
-
${
|
|
5181
|
-
${
|
|
5182
|
-
${
|
|
5183
|
-
${
|
|
5184
|
-
${
|
|
5185
|
-
|
|
5186
|
-
${
|
|
5187
|
-
Press ${
|
|
5188
|
-
|
|
5189
|
-
${
|
|
5190
|
-
${
|
|
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")}
|
|
5191
5523
|
`, { padding: 1, borderColor: "cyan", borderStyle: "round" }));
|
|
5192
5524
|
}
|
|
5193
5525
|
var program = new Command();
|
|
@@ -5207,6 +5539,7 @@ program.command("learn").description("View and manage learning settings").option
|
|
|
5207
5539
|
program.command("design [action]").description("Manage design system (profile, palette, check)").action(designCommand);
|
|
5208
5540
|
program.command("prd [file]").description("Build entire project from a PRD document").action(prdCommand);
|
|
5209
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);
|
|
5210
5543
|
var args = process.argv.slice(2);
|
|
5211
5544
|
if (args.length === 0) {
|
|
5212
5545
|
checkForUpdates().catch(() => {
|