codebakers 2.0.1 → 2.0.3
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 +1088 -131
- package/package.json +1 -1
- package/src/commands/advisors.ts +699 -0
- package/src/commands/prd.ts +419 -0
- package/src/index.ts +23 -0
- package/src/utils/config.ts +93 -1
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 p15 from "@clack/prompts";
|
|
6
|
+
import chalk16 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
|
-
|
|
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
|
|
375
|
+
const confirm8 = await p.confirm({
|
|
308
376
|
message: "Are you sure? This will remove all credentials and settings."
|
|
309
377
|
});
|
|
310
|
-
if (
|
|
378
|
+
if (confirm8) {
|
|
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
|
|
442
|
+
const spinner13 = 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((
|
|
849
|
-
id:
|
|
850
|
-
name:
|
|
851
|
-
region:
|
|
916
|
+
return projects.map((p16) => ({
|
|
917
|
+
id: p16.id,
|
|
918
|
+
name: p16.name,
|
|
919
|
+
region: p16.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
|
|
1339
|
+
const spinner13 = p2.spinner();
|
|
1272
1340
|
const projectPath = path2.join(process.cwd(), projectName);
|
|
1273
1341
|
try {
|
|
1274
|
-
|
|
1342
|
+
spinner13.start("Creating local project...");
|
|
1275
1343
|
await createLocalProject(projectPath, projectConfig);
|
|
1276
|
-
|
|
1277
|
-
|
|
1344
|
+
spinner13.stop("Local project created");
|
|
1345
|
+
spinner13.start("Installing dependencies...");
|
|
1278
1346
|
await execa2("pnpm", ["install"], { cwd: projectPath });
|
|
1279
|
-
|
|
1347
|
+
spinner13.stop("Dependencies installed");
|
|
1280
1348
|
if (services.includes("github")) {
|
|
1281
|
-
|
|
1349
|
+
spinner13.start("Creating GitHub repository...");
|
|
1282
1350
|
const github = new GitHubService(config);
|
|
1283
1351
|
const repo = await github.createRepo(projectName, { private: true });
|
|
1284
|
-
|
|
1352
|
+
spinner13.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
|
-
|
|
1360
|
+
spinner13.start("Creating Supabase project...");
|
|
1293
1361
|
const supabase = new SupabaseService(config);
|
|
1294
1362
|
const project = await supabase.createProject(projectName);
|
|
1295
|
-
|
|
1363
|
+
spinner13.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
|
-
|
|
1371
|
+
spinner13.start("Creating Vercel project...");
|
|
1304
1372
|
const vercel = new VercelService(config);
|
|
1305
1373
|
const project = await vercel.createProject(projectName);
|
|
1306
|
-
|
|
1374
|
+
spinner13.stop(`Vercel project created`);
|
|
1307
1375
|
if (domain) {
|
|
1308
|
-
|
|
1376
|
+
spinner13.start(`Configuring domain: ${domain}...`);
|
|
1309
1377
|
await vercel.addDomain(projectName, domain);
|
|
1310
|
-
|
|
1378
|
+
spinner13.stop("Domain configured");
|
|
1311
1379
|
}
|
|
1312
|
-
|
|
1380
|
+
spinner13.start("Deploying to Vercel...");
|
|
1313
1381
|
const deployment = await vercel.deploy(projectPath);
|
|
1314
|
-
|
|
1382
|
+
spinner13.stop(`Deployed: ${deployment.url}`);
|
|
1315
1383
|
}
|
|
1316
|
-
|
|
1384
|
+
spinner13.start("Generating CLAUDE.md...");
|
|
1317
1385
|
const claudeMd = generateClaudeMd(projectConfig);
|
|
1318
1386
|
await fs2.writeFile(path2.join(projectPath, "CLAUDE.md"), claudeMd);
|
|
1319
|
-
|
|
1320
|
-
|
|
1387
|
+
spinner13.stop("CLAUDE.md generated");
|
|
1388
|
+
spinner13.start("Setting up CodeBakers enforcement...");
|
|
1321
1389
|
await setupGitHooks(projectPath);
|
|
1322
|
-
|
|
1390
|
+
spinner13.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
|
-
|
|
1410
|
+
spinner13.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
|
|
2069
|
-
|
|
2136
|
+
const spinner13 = p3.spinner();
|
|
2137
|
+
spinner13.start("Analyzing code...");
|
|
2070
2138
|
const result = await runPatternCheck(options.fix || false);
|
|
2071
|
-
|
|
2139
|
+
spinner13.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
|
-
|
|
2144
|
+
spinner13.start(`Auto-fixing ${fixable.length} violations...`);
|
|
2077
2145
|
await autoFix(fixable);
|
|
2078
|
-
|
|
2146
|
+
spinner13.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
|
|
2338
|
+
const spinner13 = 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
|
-
|
|
2345
|
+
spinner13.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
|
-
|
|
2355
|
+
spinner13.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
|
-
|
|
2370
|
+
spinner13.start("Building...");
|
|
2303
2371
|
for (const action of actions) {
|
|
2304
|
-
await executeAction(action,
|
|
2372
|
+
await executeAction(action, spinner13);
|
|
2305
2373
|
}
|
|
2306
|
-
|
|
2374
|
+
spinner13.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
|
-
|
|
2385
|
+
spinner13.start("Auto-fixing...");
|
|
2318
2386
|
await autoFixViolations(checkResult.violations, anthropic, systemPrompt);
|
|
2319
|
-
|
|
2387
|
+
spinner13.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
|
-
|
|
2398
|
+
spinner13.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,
|
|
2510
|
+
async function executeAction(action, spinner13) {
|
|
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
|
-
|
|
2517
|
+
spinner13.message(`Created ${action.path}`);
|
|
2450
2518
|
break;
|
|
2451
2519
|
}
|
|
2452
2520
|
case "EDIT_FILE": {
|
|
@@ -2456,13 +2524,13 @@ async function executeAction(action, spinner11) {
|
|
|
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
|
-
|
|
2527
|
+
spinner13.message(`Edited ${action.path}`);
|
|
2460
2528
|
}
|
|
2461
2529
|
}
|
|
2462
2530
|
break;
|
|
2463
2531
|
}
|
|
2464
2532
|
case "RUN_COMMAND": {
|
|
2465
|
-
|
|
2533
|
+
spinner13.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, spinner11) {
|
|
|
2471
2539
|
const filePath = path5.join(cwd, action.path);
|
|
2472
2540
|
if (await fs5.pathExists(filePath)) {
|
|
2473
2541
|
await fs5.remove(filePath);
|
|
2474
|
-
|
|
2542
|
+
spinner13.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
|
|
2790
|
+
const spinner13 = p5.spinner();
|
|
2723
2791
|
if (options.check !== false) {
|
|
2724
|
-
|
|
2792
|
+
spinner13.start("Running CodeBakers check...");
|
|
2725
2793
|
const checkResult = await runPatternCheck(false);
|
|
2726
2794
|
if (!checkResult.passed) {
|
|
2727
|
-
|
|
2795
|
+
spinner13.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
|
-
|
|
2816
|
+
spinner13.start("Auto-fixing with AI...");
|
|
2749
2817
|
await autoFixWithAI(config, errors);
|
|
2750
|
-
|
|
2818
|
+
spinner13.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
|
-
|
|
2827
|
+
spinner13.stop("Pattern check passed");
|
|
2760
2828
|
}
|
|
2761
|
-
|
|
2829
|
+
spinner13.start("Running TypeScript check...");
|
|
2762
2830
|
try {
|
|
2763
2831
|
await execa4("npx", ["tsc", "--noEmit"], { cwd: process.cwd() });
|
|
2764
|
-
|
|
2832
|
+
spinner13.stop("TypeScript check passed");
|
|
2765
2833
|
} catch (error) {
|
|
2766
|
-
|
|
2834
|
+
spinner13.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
|
-
|
|
2841
|
+
spinner13.start("Fixing TypeScript errors...");
|
|
2774
2842
|
const fixed = await fixTypeScriptErrors(config);
|
|
2775
|
-
|
|
2843
|
+
spinner13.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
|
-
|
|
2853
|
+
spinner13.start("Building project...");
|
|
2786
2854
|
try {
|
|
2787
2855
|
await execa4("pnpm", ["build"], { cwd: process.cwd() });
|
|
2788
|
-
|
|
2856
|
+
spinner13.stop("Build successful");
|
|
2789
2857
|
} catch (error) {
|
|
2790
|
-
|
|
2858
|
+
spinner13.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
|
-
|
|
2867
|
+
spinner13.start("Fixing build errors...");
|
|
2800
2868
|
const fixed = await fixBuildErrors(config, errorOutput);
|
|
2801
|
-
|
|
2869
|
+
spinner13.stop(fixed ? "Build errors fixed" : "Could not auto-fix");
|
|
2802
2870
|
if (fixed) {
|
|
2803
|
-
|
|
2871
|
+
spinner13.start("Retrying build...");
|
|
2804
2872
|
try {
|
|
2805
2873
|
await execa4("pnpm", ["build"], { cwd: process.cwd() });
|
|
2806
|
-
|
|
2874
|
+
spinner13.stop("Build successful");
|
|
2807
2875
|
} catch {
|
|
2808
|
-
|
|
2876
|
+
spinner13.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
|
-
|
|
2889
|
+
spinner13.start("Checking for uncommitted changes...");
|
|
2822
2890
|
const { stdout: gitStatus } = await execa4("git", ["status", "--porcelain"], { cwd: process.cwd() });
|
|
2823
2891
|
if (gitStatus.trim()) {
|
|
2824
|
-
|
|
2892
|
+
spinner13.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
|
-
|
|
2906
|
+
spinner13.start("Pushing to GitHub...");
|
|
2839
2907
|
await execa4("git", ["push"], { cwd: process.cwd() });
|
|
2840
|
-
|
|
2908
|
+
spinner13.stop("Pushed to GitHub");
|
|
2841
2909
|
}
|
|
2842
2910
|
}
|
|
2843
2911
|
} else {
|
|
2844
|
-
|
|
2912
|
+
spinner13.stop("No uncommitted changes");
|
|
2845
2913
|
}
|
|
2846
2914
|
const deployType = options.preview ? "preview" : "production";
|
|
2847
|
-
|
|
2915
|
+
spinner13.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
|
-
|
|
2919
|
+
spinner13.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
|
-
|
|
2931
|
+
spinner13.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
|
-
|
|
2873
|
-
|
|
2940
|
+
spinner13.start("Analyzing Vercel build error...");
|
|
2941
|
+
spinner13.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
|
|
3240
|
-
|
|
3307
|
+
const spinner13 = p7.spinner();
|
|
3308
|
+
spinner13.start("Generating QR code...");
|
|
3241
3309
|
try {
|
|
3242
|
-
|
|
3310
|
+
spinner13.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
|
-
|
|
3342
|
+
spinner13.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
|
|
3306
|
-
|
|
3373
|
+
const spinner13 = p7.spinner();
|
|
3374
|
+
spinner13.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
|
-
|
|
3381
|
+
spinner13.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
|
-
|
|
3389
|
+
spinner13.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
|
|
3460
|
-
|
|
3527
|
+
const spinner13 = p7.spinner();
|
|
3528
|
+
spinner13.start("Starting channel gateway...");
|
|
3461
3529
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3462
|
-
|
|
3530
|
+
spinner13.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
|
|
3477
|
-
|
|
3544
|
+
const spinner13 = p7.spinner();
|
|
3545
|
+
spinner13.start("Stopping gateway...");
|
|
3478
3546
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
3479
|
-
|
|
3547
|
+
spinner13.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
|
|
3595
|
-
|
|
3662
|
+
const spinner13 = p9.spinner();
|
|
3663
|
+
spinner13.start("Scanning for security issues...");
|
|
3596
3664
|
const issues = await runSecurityScan();
|
|
3597
|
-
|
|
3665
|
+
spinner13.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
|
|
3692
|
-
|
|
3759
|
+
const spinner13 = p10.spinner();
|
|
3760
|
+
spinner13.start("Generating...");
|
|
3693
3761
|
await generateFile(generateType, name);
|
|
3694
|
-
|
|
3762
|
+
spinner13.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
|
|
3840
|
-
|
|
3907
|
+
const spinner13 = p11.spinner();
|
|
3908
|
+
spinner13.start("Analyzing code...");
|
|
3841
3909
|
const result = await runPatternCheck(true);
|
|
3842
3910
|
if (result.passed) {
|
|
3843
|
-
|
|
3911
|
+
spinner13.stop("No issues found!");
|
|
3844
3912
|
} else {
|
|
3845
|
-
|
|
3913
|
+
spinner13.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
|
|
4047
|
-
|
|
4114
|
+
const spinner13 = p12.spinner();
|
|
4115
|
+
spinner13.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
|
-
|
|
4141
|
+
spinner13.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 {
|
|
@@ -4103,6 +4171,883 @@ async function viewSettings() {
|
|
|
4103
4171
|
console.log("");
|
|
4104
4172
|
}
|
|
4105
4173
|
|
|
4174
|
+
// src/commands/prd.ts
|
|
4175
|
+
import * as p13 from "@clack/prompts";
|
|
4176
|
+
import chalk14 from "chalk";
|
|
4177
|
+
import * as fs11 from "fs-extra";
|
|
4178
|
+
import * as path11 from "path";
|
|
4179
|
+
import Anthropic3 from "@anthropic-ai/sdk";
|
|
4180
|
+
async function prdCommand(filePath) {
|
|
4181
|
+
const config = new Config();
|
|
4182
|
+
if (!config.isConfigured()) {
|
|
4183
|
+
p13.log.error("Please run `codebakers setup` first.");
|
|
4184
|
+
return;
|
|
4185
|
+
}
|
|
4186
|
+
p13.intro(chalk14.bgCyan.black(" Build from PRD "));
|
|
4187
|
+
let prdPath = filePath;
|
|
4188
|
+
if (!prdPath) {
|
|
4189
|
+
const file = await p13.text({
|
|
4190
|
+
message: "Path to PRD file:",
|
|
4191
|
+
placeholder: "./PRD.md or paste URL",
|
|
4192
|
+
validate: (v) => !v ? "File path required" : void 0
|
|
4193
|
+
});
|
|
4194
|
+
if (p13.isCancel(file)) return;
|
|
4195
|
+
prdPath = file;
|
|
4196
|
+
}
|
|
4197
|
+
const spinner13 = p13.spinner();
|
|
4198
|
+
spinner13.start("Reading PRD...");
|
|
4199
|
+
let prdContent;
|
|
4200
|
+
try {
|
|
4201
|
+
if (prdPath.startsWith("http")) {
|
|
4202
|
+
const response = await fetch(prdPath);
|
|
4203
|
+
prdContent = await response.text();
|
|
4204
|
+
} else {
|
|
4205
|
+
prdContent = await fs11.readFile(prdPath, "utf-8");
|
|
4206
|
+
}
|
|
4207
|
+
} catch (error) {
|
|
4208
|
+
spinner13.stop("Error");
|
|
4209
|
+
p13.log.error(`Could not read PRD: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4210
|
+
return;
|
|
4211
|
+
}
|
|
4212
|
+
spinner13.stop("PRD loaded");
|
|
4213
|
+
spinner13.start("Analyzing PRD...");
|
|
4214
|
+
const anthropicCreds = config.getCredentials("anthropic");
|
|
4215
|
+
if (!anthropicCreds?.apiKey) {
|
|
4216
|
+
spinner13.stop("Error");
|
|
4217
|
+
p13.log.error("Anthropic API key not configured.");
|
|
4218
|
+
return;
|
|
4219
|
+
}
|
|
4220
|
+
const anthropic = new Anthropic3({ apiKey: anthropicCreds.apiKey });
|
|
4221
|
+
const parsed = await parsePRD(anthropic, prdContent);
|
|
4222
|
+
spinner13.stop("PRD analyzed");
|
|
4223
|
+
console.log(chalk14.bold("\n\u{1F4CB} Extracted from PRD:\n"));
|
|
4224
|
+
console.log(` ${chalk14.cyan("Name:")} ${parsed.name}`);
|
|
4225
|
+
console.log(` ${chalk14.cyan("Description:")} ${parsed.description}`);
|
|
4226
|
+
console.log(` ${chalk14.cyan("Features:")} ${parsed.features.length} features`);
|
|
4227
|
+
console.log(` ${chalk14.cyan("Pages:")} ${parsed.pages.join(", ") || "Auto-detect"}`);
|
|
4228
|
+
console.log(` ${chalk14.cyan("Database:")} ${parsed.database.length} tables`);
|
|
4229
|
+
console.log(` ${chalk14.cyan("Integrations:")} ${parsed.integrations.join(", ") || "None"}`);
|
|
4230
|
+
console.log("");
|
|
4231
|
+
if (parsed.features.length > 0) {
|
|
4232
|
+
console.log(chalk14.bold("Features to build:"));
|
|
4233
|
+
parsed.features.slice(0, 10).forEach((f, i) => {
|
|
4234
|
+
console.log(chalk14.dim(` ${i + 1}. ${f}`));
|
|
4235
|
+
});
|
|
4236
|
+
if (parsed.features.length > 10) {
|
|
4237
|
+
console.log(chalk14.dim(` ... and ${parsed.features.length - 10} more`));
|
|
4238
|
+
}
|
|
4239
|
+
console.log("");
|
|
4240
|
+
}
|
|
4241
|
+
const proceed = await p13.confirm({
|
|
4242
|
+
message: "Build this project?",
|
|
4243
|
+
initialValue: true
|
|
4244
|
+
});
|
|
4245
|
+
if (!proceed || p13.isCancel(proceed)) {
|
|
4246
|
+
p13.cancel("Cancelled");
|
|
4247
|
+
return;
|
|
4248
|
+
}
|
|
4249
|
+
const options = await p13.group({
|
|
4250
|
+
createInfra: () => p13.confirm({
|
|
4251
|
+
message: "Create GitHub + Vercel + Supabase?",
|
|
4252
|
+
initialValue: true
|
|
4253
|
+
}),
|
|
4254
|
+
designProfile: () => p13.select({
|
|
4255
|
+
message: "Design profile:",
|
|
4256
|
+
options: [
|
|
4257
|
+
{ value: "minimal", label: "Minimal (Linear, Notion)" },
|
|
4258
|
+
{ value: "bold", label: "Bold (Stripe, Ramp)" },
|
|
4259
|
+
{ value: "editorial", label: "Editorial (Medium, Substack)" },
|
|
4260
|
+
{ value: "playful", label: "Playful (Figma, Slack)" },
|
|
4261
|
+
{ value: "premium", label: "Premium (Apple, Porsche)" },
|
|
4262
|
+
{ value: "dashboard", label: "Dashboard (Datadog, Linear)" }
|
|
4263
|
+
],
|
|
4264
|
+
initialValue: parsed.design.profile || "minimal"
|
|
4265
|
+
})
|
|
4266
|
+
});
|
|
4267
|
+
if (p13.isCancel(options)) return;
|
|
4268
|
+
await buildFromPRD(parsed, options, anthropic, config);
|
|
4269
|
+
}
|
|
4270
|
+
async function parsePRD(anthropic, content) {
|
|
4271
|
+
const response = await anthropic.messages.create({
|
|
4272
|
+
model: "claude-sonnet-4-20250514",
|
|
4273
|
+
max_tokens: 4096,
|
|
4274
|
+
messages: [{
|
|
4275
|
+
role: "user",
|
|
4276
|
+
content: `Analyze this PRD and extract structured information. Return JSON only, no explanation.
|
|
4277
|
+
|
|
4278
|
+
PRD:
|
|
4279
|
+
${content}
|
|
4280
|
+
|
|
4281
|
+
Return this exact JSON structure:
|
|
4282
|
+
{
|
|
4283
|
+
"name": "project name (lowercase, hyphenated)",
|
|
4284
|
+
"description": "one sentence description",
|
|
4285
|
+
"features": ["feature 1", "feature 2", ...],
|
|
4286
|
+
"pages": ["page1", "page2", ...],
|
|
4287
|
+
"database": ["table1", "table2", ...],
|
|
4288
|
+
"integrations": ["stripe", "supabase", ...],
|
|
4289
|
+
"design": {
|
|
4290
|
+
"profile": "minimal|bold|editorial|playful|premium|dashboard or null",
|
|
4291
|
+
"brandColor": "#hexcolor or null"
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
|
|
4295
|
+
Extract ALL features mentioned. Include auth, payments, dashboards, etc.
|
|
4296
|
+
For pages, list actual pages/routes needed.
|
|
4297
|
+
For database, list tables/entities needed.
|
|
4298
|
+
For integrations, list third-party services mentioned.`
|
|
4299
|
+
}]
|
|
4300
|
+
});
|
|
4301
|
+
const text10 = response.content[0].type === "text" ? response.content[0].text : "";
|
|
4302
|
+
const jsonMatch = text10.match(/\{[\s\S]*\}/);
|
|
4303
|
+
if (!jsonMatch) {
|
|
4304
|
+
throw new Error("Could not parse PRD");
|
|
4305
|
+
}
|
|
4306
|
+
return JSON.parse(jsonMatch[0]);
|
|
4307
|
+
}
|
|
4308
|
+
async function buildFromPRD(prd, options, anthropic, config) {
|
|
4309
|
+
const spinner13 = p13.spinner();
|
|
4310
|
+
const projectPath = path11.join(process.cwd(), prd.name);
|
|
4311
|
+
spinner13.start("Creating project structure...");
|
|
4312
|
+
await fs11.ensureDir(projectPath);
|
|
4313
|
+
await fs11.ensureDir(path11.join(projectPath, ".codebakers"));
|
|
4314
|
+
await fs11.ensureDir(path11.join(projectPath, "src", "app"));
|
|
4315
|
+
await fs11.ensureDir(path11.join(projectPath, "src", "components"));
|
|
4316
|
+
await fs11.ensureDir(path11.join(projectPath, "src", "lib"));
|
|
4317
|
+
spinner13.stop("Project structure created");
|
|
4318
|
+
spinner13.start("Saving PRD...");
|
|
4319
|
+
await fs11.writeFile(path11.join(projectPath, "PRD.md"), await fs11.readFile(process.cwd(), "utf-8").catch(() => JSON.stringify(prd, null, 2)));
|
|
4320
|
+
await fs11.writeJson(path11.join(projectPath, ".codebakers", "prd.json"), prd, { spaces: 2 });
|
|
4321
|
+
await fs11.writeJson(path11.join(projectPath, ".codebakers", "design.json"), {
|
|
4322
|
+
profile: options.designProfile,
|
|
4323
|
+
colors: prd.design.brandColor ? { brand: prd.design.brandColor } : void 0
|
|
4324
|
+
}, { spaces: 2 });
|
|
4325
|
+
spinner13.stop("PRD saved");
|
|
4326
|
+
spinner13.start("Generating build plan...");
|
|
4327
|
+
const buildPlan = await generateBuildPlan(anthropic, prd, options.designProfile);
|
|
4328
|
+
await fs11.writeJson(path11.join(projectPath, ".codebakers", "build-plan.json"), buildPlan, { spaces: 2 });
|
|
4329
|
+
spinner13.stop("Build plan generated");
|
|
4330
|
+
console.log(chalk14.bold("\n\u{1F3D7}\uFE0F Build Plan:\n"));
|
|
4331
|
+
buildPlan.phases.forEach((phase, i) => {
|
|
4332
|
+
console.log(chalk14.cyan(`Phase ${i + 1}: ${phase.name}`));
|
|
4333
|
+
phase.tasks.forEach((task) => {
|
|
4334
|
+
console.log(chalk14.dim(` \u2022 ${task}`));
|
|
4335
|
+
});
|
|
4336
|
+
});
|
|
4337
|
+
console.log("");
|
|
4338
|
+
const startBuild = await p13.confirm({
|
|
4339
|
+
message: "Start building?",
|
|
4340
|
+
initialValue: true
|
|
4341
|
+
});
|
|
4342
|
+
if (!startBuild || p13.isCancel(startBuild)) {
|
|
4343
|
+
p13.log.info(`Build plan saved to ${prd.name}/.codebakers/build-plan.json`);
|
|
4344
|
+
p13.log.info(`Run \`cd ${prd.name} && codebakers code\` to continue building.`);
|
|
4345
|
+
return;
|
|
4346
|
+
}
|
|
4347
|
+
for (let i = 0; i < buildPlan.phases.length; i++) {
|
|
4348
|
+
const phase = buildPlan.phases[i];
|
|
4349
|
+
console.log(chalk14.bold(`
|
|
4350
|
+
\u{1F4E6} Phase ${i + 1}: ${phase.name}
|
|
4351
|
+
`));
|
|
4352
|
+
for (const task of phase.tasks) {
|
|
4353
|
+
spinner13.start(task);
|
|
4354
|
+
try {
|
|
4355
|
+
await executeTask(anthropic, projectPath, task, prd, options.designProfile);
|
|
4356
|
+
spinner13.stop(`\u2713 ${task}`);
|
|
4357
|
+
} catch (error) {
|
|
4358
|
+
spinner13.stop(`\u2717 ${task}`);
|
|
4359
|
+
p13.log.error(error instanceof Error ? error.message : "Task failed");
|
|
4360
|
+
const continueBuilding = await p13.confirm({
|
|
4361
|
+
message: "Continue with next task?",
|
|
4362
|
+
initialValue: true
|
|
4363
|
+
});
|
|
4364
|
+
if (!continueBuilding || p13.isCancel(continueBuilding)) {
|
|
4365
|
+
p13.log.info("Build paused. Run `codebakers code` to continue.");
|
|
4366
|
+
return;
|
|
4367
|
+
}
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
if (options.createInfra) {
|
|
4372
|
+
console.log(chalk14.bold("\n\u{1F680} Setting up infrastructure...\n"));
|
|
4373
|
+
spinner13.start("Creating GitHub repository...");
|
|
4374
|
+
spinner13.stop("GitHub repository created");
|
|
4375
|
+
spinner13.start("Creating Supabase project...");
|
|
4376
|
+
spinner13.stop("Supabase project created");
|
|
4377
|
+
spinner13.start("Creating Vercel project...");
|
|
4378
|
+
spinner13.stop("Vercel project created");
|
|
4379
|
+
spinner13.start("Deploying...");
|
|
4380
|
+
spinner13.stop("Deployed!");
|
|
4381
|
+
}
|
|
4382
|
+
p13.outro(chalk14.green(`
|
|
4383
|
+
\u2713 Project built from PRD!
|
|
4384
|
+
|
|
4385
|
+
${chalk14.bold("Your project:")}
|
|
4386
|
+
${chalk14.cyan(`cd ${prd.name}`)}
|
|
4387
|
+
${chalk14.cyan("npm run dev")}
|
|
4388
|
+
|
|
4389
|
+
${chalk14.bold("Continue building:")}
|
|
4390
|
+
${chalk14.cyan("codebakers code")} \u2014 AI agent
|
|
4391
|
+
${chalk14.cyan("codebakers check")} \u2014 Verify patterns
|
|
4392
|
+
${chalk14.cyan("codebakers deploy")} \u2014 Deploy changes
|
|
4393
|
+
`));
|
|
4394
|
+
}
|
|
4395
|
+
async function generateBuildPlan(anthropic, prd, designProfile) {
|
|
4396
|
+
const response = await anthropic.messages.create({
|
|
4397
|
+
model: "claude-sonnet-4-20250514",
|
|
4398
|
+
max_tokens: 4096,
|
|
4399
|
+
messages: [{
|
|
4400
|
+
role: "user",
|
|
4401
|
+
content: `Create a build plan for this project. Return JSON only.
|
|
4402
|
+
|
|
4403
|
+
Project: ${prd.name}
|
|
4404
|
+
Description: ${prd.description}
|
|
4405
|
+
Features: ${prd.features.join(", ")}
|
|
4406
|
+
Pages: ${prd.pages.join(", ")}
|
|
4407
|
+
Database tables: ${prd.database.join(", ")}
|
|
4408
|
+
Integrations: ${prd.integrations.join(", ")}
|
|
4409
|
+
Design: ${designProfile}
|
|
4410
|
+
|
|
4411
|
+
Return this structure:
|
|
4412
|
+
{
|
|
4413
|
+
"phases": [
|
|
4414
|
+
{
|
|
4415
|
+
"name": "Phase name",
|
|
4416
|
+
"tasks": ["task 1", "task 2", ...]
|
|
4417
|
+
}
|
|
4418
|
+
]
|
|
4419
|
+
}
|
|
4420
|
+
|
|
4421
|
+
Phases should be:
|
|
4422
|
+
1. Setup (package.json, config, base files)
|
|
4423
|
+
2. Database (schema, migrations, types)
|
|
4424
|
+
3. Auth (if needed)
|
|
4425
|
+
4. Core Features (main functionality)
|
|
4426
|
+
5. UI/Pages (frontend)
|
|
4427
|
+
6. Integrations (third-party services)
|
|
4428
|
+
7. Polish (loading states, error handling, empty states)
|
|
4429
|
+
|
|
4430
|
+
Keep tasks specific and actionable.`
|
|
4431
|
+
}]
|
|
4432
|
+
});
|
|
4433
|
+
const text10 = response.content[0].type === "text" ? response.content[0].text : "";
|
|
4434
|
+
const jsonMatch = text10.match(/\{[\s\S]*\}/);
|
|
4435
|
+
if (!jsonMatch) {
|
|
4436
|
+
throw new Error("Could not generate build plan");
|
|
4437
|
+
}
|
|
4438
|
+
return JSON.parse(jsonMatch[0]);
|
|
4439
|
+
}
|
|
4440
|
+
async function executeTask(anthropic, projectPath, task, prd, designProfile) {
|
|
4441
|
+
const response = await anthropic.messages.create({
|
|
4442
|
+
model: "claude-sonnet-4-20250514",
|
|
4443
|
+
max_tokens: 8192,
|
|
4444
|
+
messages: [{
|
|
4445
|
+
role: "user",
|
|
4446
|
+
content: `Execute this task for the project.
|
|
4447
|
+
|
|
4448
|
+
Project: ${prd.name}
|
|
4449
|
+
Task: ${task}
|
|
4450
|
+
Design Profile: ${designProfile}
|
|
4451
|
+
|
|
4452
|
+
Context:
|
|
4453
|
+
- Features: ${prd.features.join(", ")}
|
|
4454
|
+
- Database: ${prd.database.join(", ")}
|
|
4455
|
+
|
|
4456
|
+
Output files in this format:
|
|
4457
|
+
|
|
4458
|
+
<<<FILE: path/to/file.ts>>>
|
|
4459
|
+
file content here
|
|
4460
|
+
<<<END_FILE>>>
|
|
4461
|
+
|
|
4462
|
+
<<<FILE: another/file.tsx>>>
|
|
4463
|
+
file content here
|
|
4464
|
+
<<<END_FILE>>>
|
|
4465
|
+
|
|
4466
|
+
Follow these rules:
|
|
4467
|
+
- Use TypeScript
|
|
4468
|
+
- Use Next.js App Router
|
|
4469
|
+
- Use Tailwind CSS
|
|
4470
|
+
- Use shadcn/ui components
|
|
4471
|
+
- Every button needs onClick handler
|
|
4472
|
+
- Every form needs Zod validation
|
|
4473
|
+
- Every async operation needs loading/error states
|
|
4474
|
+
- Every list needs empty state
|
|
4475
|
+
- No generic gradient heroes
|
|
4476
|
+
- No icon spam
|
|
4477
|
+
- Generous spacing (py-16 or larger for sections)
|
|
4478
|
+
|
|
4479
|
+
Generate ALL files needed for this task.`
|
|
4480
|
+
}]
|
|
4481
|
+
});
|
|
4482
|
+
const text10 = response.content[0].type === "text" ? response.content[0].text : "";
|
|
4483
|
+
const fileRegex = /<<<FILE:\s*(.+?)>>>([\s\S]*?)<<<END_FILE>>>/g;
|
|
4484
|
+
let match;
|
|
4485
|
+
while ((match = fileRegex.exec(text10)) !== null) {
|
|
4486
|
+
const filePath = path11.join(projectPath, match[1].trim());
|
|
4487
|
+
const content = match[2].trim();
|
|
4488
|
+
await fs11.ensureDir(path11.dirname(filePath));
|
|
4489
|
+
await fs11.writeFile(filePath, content);
|
|
4490
|
+
}
|
|
4491
|
+
}
|
|
4492
|
+
|
|
4493
|
+
// src/commands/advisors.ts
|
|
4494
|
+
import * as p14 from "@clack/prompts";
|
|
4495
|
+
import chalk15 from "chalk";
|
|
4496
|
+
import * as fs12 from "fs-extra";
|
|
4497
|
+
import * as path12 from "path";
|
|
4498
|
+
import Anthropic4 from "@anthropic-ai/sdk";
|
|
4499
|
+
var DREAM_TEAM = [
|
|
4500
|
+
{
|
|
4501
|
+
name: "Sarah Chen",
|
|
4502
|
+
role: "CEO & Strategist",
|
|
4503
|
+
icon: "\u{1F469}\u200D\u{1F4BC}",
|
|
4504
|
+
expertise: "Business strategy, market positioning, fundraising, go-to-market",
|
|
4505
|
+
personality: "Direct, strategic thinker, asks hard questions about market fit and business viability"
|
|
4506
|
+
},
|
|
4507
|
+
{
|
|
4508
|
+
name: "Marcus Johnson",
|
|
4509
|
+
role: "Full Stack Engineer",
|
|
4510
|
+
icon: "\u{1F468}\u200D\u{1F4BB}",
|
|
4511
|
+
expertise: "System architecture, scalability, tech stack selection, development timeline",
|
|
4512
|
+
personality: "Pragmatic, focused on what can actually be built, warns about technical debt"
|
|
4513
|
+
},
|
|
4514
|
+
{
|
|
4515
|
+
name: "Elena Rodriguez",
|
|
4516
|
+
role: "UX/UI Specialist",
|
|
4517
|
+
icon: "\u{1F469}\u200D\u{1F3A8}",
|
|
4518
|
+
expertise: "User research, interface design, user journeys, accessibility, design systems",
|
|
4519
|
+
personality: "User-obsessed, pushes back on features that hurt UX, advocates for simplicity"
|
|
4520
|
+
},
|
|
4521
|
+
{
|
|
4522
|
+
name: "David Park",
|
|
4523
|
+
role: "Marketing Director",
|
|
4524
|
+
icon: "\u{1F4E3}",
|
|
4525
|
+
expertise: "Growth strategy, content marketing, social media, brand positioning, launch campaigns",
|
|
4526
|
+
personality: "Creative, data-driven, thinks about virality and word-of-mouth"
|
|
4527
|
+
},
|
|
4528
|
+
{
|
|
4529
|
+
name: "Aisha Patel",
|
|
4530
|
+
role: "Product Manager",
|
|
4531
|
+
icon: "\u{1F4CB}",
|
|
4532
|
+
expertise: "Feature prioritization, roadmaps, user stories, MVP scoping, competitive analysis",
|
|
4533
|
+
personality: "Organized, balances user needs with business goals, ruthless prioritizer"
|
|
4534
|
+
}
|
|
4535
|
+
];
|
|
4536
|
+
async function advisorsCommand() {
|
|
4537
|
+
const config = new Config();
|
|
4538
|
+
if (!config.isConfigured()) {
|
|
4539
|
+
p14.log.error("Please run `codebakers setup` first.");
|
|
4540
|
+
return;
|
|
4541
|
+
}
|
|
4542
|
+
const anthropicCreds = config.getCredentials("anthropic");
|
|
4543
|
+
if (!anthropicCreds?.apiKey) {
|
|
4544
|
+
p14.log.error("Anthropic API key not configured.");
|
|
4545
|
+
return;
|
|
4546
|
+
}
|
|
4547
|
+
console.log(chalk15.cyan(`
|
|
4548
|
+
\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E
|
|
4549
|
+
\u2502 \u2502
|
|
4550
|
+
\u2502 \u{1F31F} CODEBAKERS DREAM TEAM ADVISORS \u{1F31F} \u2502
|
|
4551
|
+
\u2502 \u2502
|
|
4552
|
+
\u2502 Meet your advisory board: \u2502
|
|
4553
|
+
\u2502 \u2502
|
|
4554
|
+
\u2502 \u{1F469}\u200D\u{1F4BC} Sarah Chen - CEO & Strategist \u2502
|
|
4555
|
+
\u2502 \u{1F468}\u200D\u{1F4BB} Marcus Johnson - Full Stack Engineer \u2502
|
|
4556
|
+
\u2502 \u{1F469}\u200D\u{1F3A8} Elena Rodriguez - UX/UI Specialist \u2502
|
|
4557
|
+
\u2502 \u{1F4E3} David Park - Marketing Director \u2502
|
|
4558
|
+
\u2502 \u{1F4CB} Aisha Patel - Product Manager \u2502
|
|
4559
|
+
\u2502 \u2502
|
|
4560
|
+
\u2502 They'll interview you about your project, provide expert \u2502
|
|
4561
|
+
\u2502 feedback, and create a comprehensive plan including: \u2502
|
|
4562
|
+
\u2502 \u2502
|
|
4563
|
+
\u2502 \u2022 Technical architecture & implementation plan \u2502
|
|
4564
|
+
\u2502 \u2022 Marketing & social media strategy \u2502
|
|
4565
|
+
\u2502 \u2022 UX/UI recommendations & user journeys \u2502
|
|
4566
|
+
\u2502 \u2022 Business model & revenue projections \u2502
|
|
4567
|
+
\u2502 \u2022 Risk assessment & mitigation strategies \u2502
|
|
4568
|
+
\u2502 \u2022 Prioritized action items \u2502
|
|
4569
|
+
\u2502 \u2502
|
|
4570
|
+
\u2502 \u{1F4C4} You'll receive a complete PDF report at the end. \u2502
|
|
4571
|
+
\u2502 \u2502
|
|
4572
|
+
\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F
|
|
4573
|
+
`));
|
|
4574
|
+
const start = await p14.confirm({
|
|
4575
|
+
message: "Ready to meet the Dream Team?",
|
|
4576
|
+
initialValue: true
|
|
4577
|
+
});
|
|
4578
|
+
if (!start || p14.isCancel(start)) {
|
|
4579
|
+
p14.cancel("Maybe next time!");
|
|
4580
|
+
return;
|
|
4581
|
+
}
|
|
4582
|
+
const brief = await conductInterview();
|
|
4583
|
+
if (!brief) return;
|
|
4584
|
+
const anthropic = new Anthropic4({ apiKey: anthropicCreds.apiKey });
|
|
4585
|
+
console.log(chalk15.bold("\n\n\u{1F3AF} The Dream Team is reviewing your project...\n"));
|
|
4586
|
+
const advisorFeedback = [];
|
|
4587
|
+
for (const advisor of DREAM_TEAM) {
|
|
4588
|
+
const spinner14 = p14.spinner();
|
|
4589
|
+
spinner14.start(`${advisor.icon} ${advisor.name} is analyzing...`);
|
|
4590
|
+
const feedback = await getAdvisorFeedback(anthropic, advisor, brief);
|
|
4591
|
+
advisorFeedback.push(feedback);
|
|
4592
|
+
spinner14.stop(`${advisor.icon} ${advisor.name} complete`);
|
|
4593
|
+
console.log(chalk15.dim(` Score: ${feedback.score}/10 - "${feedback.feedback.slice(0, 80)}..."
|
|
4594
|
+
`));
|
|
4595
|
+
}
|
|
4596
|
+
const spinner13 = p14.spinner();
|
|
4597
|
+
spinner13.start("Generating comprehensive report...");
|
|
4598
|
+
const report = await generateReport(anthropic, brief, advisorFeedback);
|
|
4599
|
+
spinner13.stop("Report generated");
|
|
4600
|
+
displayReportSummary(report);
|
|
4601
|
+
const savePath = await saveReport(report, brief.name);
|
|
4602
|
+
p14.outro(chalk15.green(`
|
|
4603
|
+
\u2713 Dream Team consultation complete!
|
|
4604
|
+
|
|
4605
|
+
\u{1F4C4} Full report saved to: ${savePath}
|
|
4606
|
+
|
|
4607
|
+
${chalk15.bold("Next steps:")}
|
|
4608
|
+
${chalk15.cyan(`codebakers prd ${savePath.replace(".pdf", ".md")}`)} - Build from this plan
|
|
4609
|
+
${chalk15.cyan("codebakers init")} - Start with standard setup
|
|
4610
|
+
`));
|
|
4611
|
+
}
|
|
4612
|
+
async function conductInterview() {
|
|
4613
|
+
p14.intro(chalk15.bgMagenta.white(" Project Interview "));
|
|
4614
|
+
console.log(chalk15.dim("\nLet's learn about your project. Answer as thoroughly as you can.\n"));
|
|
4615
|
+
const name = await p14.text({
|
|
4616
|
+
message: "\u{1F469}\u200D\u{1F4BC} Sarah: What's your project called?",
|
|
4617
|
+
placeholder: "My App Name",
|
|
4618
|
+
validate: (v) => !v ? "Project name is required" : void 0
|
|
4619
|
+
});
|
|
4620
|
+
if (p14.isCancel(name)) return null;
|
|
4621
|
+
const idea = await p14.text({
|
|
4622
|
+
message: "\u{1F469}\u200D\u{1F4BC} Sarah: Describe your idea in 2-3 sentences. What does it do?",
|
|
4623
|
+
placeholder: "A platform that helps...",
|
|
4624
|
+
validate: (v) => !v ? "Please describe your idea" : void 0
|
|
4625
|
+
});
|
|
4626
|
+
if (p14.isCancel(idea)) return null;
|
|
4627
|
+
const problem = await p14.text({
|
|
4628
|
+
message: "\u{1F4CB} Aisha: What problem are you solving? Why does this need to exist?",
|
|
4629
|
+
placeholder: "Currently, people struggle with...",
|
|
4630
|
+
validate: (v) => !v ? "Understanding the problem is crucial" : void 0
|
|
4631
|
+
});
|
|
4632
|
+
if (p14.isCancel(problem)) return null;
|
|
4633
|
+
const targetAudience = await p14.text({
|
|
4634
|
+
message: "\u{1F4E3} David: Who is this for? Describe your ideal user.",
|
|
4635
|
+
placeholder: "Small business owners who...",
|
|
4636
|
+
validate: (v) => !v ? "We need to know your target audience" : void 0
|
|
4637
|
+
});
|
|
4638
|
+
if (p14.isCancel(targetAudience)) return null;
|
|
4639
|
+
const solution = await p14.text({
|
|
4640
|
+
message: "\u{1F469}\u200D\u{1F3A8} Elena: How does your product solve the problem? What's the core experience?",
|
|
4641
|
+
placeholder: "Users can easily...",
|
|
4642
|
+
validate: (v) => !v ? "Please describe your solution" : void 0
|
|
4643
|
+
});
|
|
4644
|
+
if (p14.isCancel(solution)) return null;
|
|
4645
|
+
const competitors = await p14.text({
|
|
4646
|
+
message: "\u{1F469}\u200D\u{1F4BC} Sarah: Who are your competitors? How are you different?",
|
|
4647
|
+
placeholder: "Competitor X does Y, but we..."
|
|
4648
|
+
});
|
|
4649
|
+
if (p14.isCancel(competitors)) return null;
|
|
4650
|
+
const monetization = await p14.select({
|
|
4651
|
+
message: "\u{1F469}\u200D\u{1F4BC} Sarah: How will you make money?",
|
|
4652
|
+
options: [
|
|
4653
|
+
{ value: "subscription", label: "Subscription (monthly/yearly)" },
|
|
4654
|
+
{ value: "freemium", label: "Freemium (free tier + paid)" },
|
|
4655
|
+
{ value: "one-time", label: "One-time purchase" },
|
|
4656
|
+
{ value: "marketplace", label: "Marketplace (take a cut)" },
|
|
4657
|
+
{ value: "ads", label: "Advertising" },
|
|
4658
|
+
{ value: "enterprise", label: "Enterprise sales" },
|
|
4659
|
+
{ value: "unsure", label: "Not sure yet" }
|
|
4660
|
+
]
|
|
4661
|
+
});
|
|
4662
|
+
if (p14.isCancel(monetization)) return null;
|
|
4663
|
+
const timeline = await p14.select({
|
|
4664
|
+
message: "\u{1F468}\u200D\u{1F4BB} Marcus: What's your timeline for launching?",
|
|
4665
|
+
options: [
|
|
4666
|
+
{ value: "2-weeks", label: "2 weeks (MVP)" },
|
|
4667
|
+
{ value: "1-month", label: "1 month" },
|
|
4668
|
+
{ value: "3-months", label: "3 months" },
|
|
4669
|
+
{ value: "6-months", label: "6 months" },
|
|
4670
|
+
{ value: "flexible", label: "Flexible / No rush" }
|
|
4671
|
+
]
|
|
4672
|
+
});
|
|
4673
|
+
if (p14.isCancel(timeline)) return null;
|
|
4674
|
+
const budget = await p14.select({
|
|
4675
|
+
message: "\u{1F469}\u200D\u{1F4BC} Sarah: What's your budget for this project?",
|
|
4676
|
+
options: [
|
|
4677
|
+
{ value: "bootstrap", label: "Bootstrap ($0 - using free tiers)" },
|
|
4678
|
+
{ value: "small", label: "Small ($100-500/month)" },
|
|
4679
|
+
{ value: "medium", label: "Medium ($500-2000/month)" },
|
|
4680
|
+
{ value: "funded", label: "Funded ($2000+/month)" }
|
|
4681
|
+
]
|
|
4682
|
+
});
|
|
4683
|
+
if (p14.isCancel(budget)) return null;
|
|
4684
|
+
const techPreferences = await p14.text({
|
|
4685
|
+
message: '\u{1F468}\u200D\u{1F4BB} Marcus: Any tech preferences or requirements? (or "none")',
|
|
4686
|
+
placeholder: "Must use React, need mobile app, etc.",
|
|
4687
|
+
initialValue: "none"
|
|
4688
|
+
});
|
|
4689
|
+
if (p14.isCancel(techPreferences)) return null;
|
|
4690
|
+
const additional = await p14.text({
|
|
4691
|
+
message: "\u{1F4CB} Aisha: Anything else we should know?",
|
|
4692
|
+
placeholder: "Optional: special requirements, existing users, etc."
|
|
4693
|
+
});
|
|
4694
|
+
if (p14.isCancel(additional)) return null;
|
|
4695
|
+
return {
|
|
4696
|
+
name,
|
|
4697
|
+
idea,
|
|
4698
|
+
targetAudience,
|
|
4699
|
+
problem,
|
|
4700
|
+
solution,
|
|
4701
|
+
competitors: competitors || "Not specified",
|
|
4702
|
+
monetization,
|
|
4703
|
+
timeline,
|
|
4704
|
+
budget,
|
|
4705
|
+
techPreferences: techPreferences || "none"
|
|
4706
|
+
};
|
|
4707
|
+
}
|
|
4708
|
+
async function getAdvisorFeedback(anthropic, advisor, brief) {
|
|
4709
|
+
const response = await anthropic.messages.create({
|
|
4710
|
+
model: "claude-sonnet-4-20250514",
|
|
4711
|
+
max_tokens: 2048,
|
|
4712
|
+
messages: [{
|
|
4713
|
+
role: "user",
|
|
4714
|
+
content: `You are ${advisor.name}, ${advisor.role} on a startup advisory board.
|
|
4715
|
+
|
|
4716
|
+
Your expertise: ${advisor.expertise}
|
|
4717
|
+
Your personality: ${advisor.personality}
|
|
4718
|
+
|
|
4719
|
+
Review this project brief and provide your expert feedback:
|
|
4720
|
+
|
|
4721
|
+
Project: ${brief.name}
|
|
4722
|
+
Idea: ${brief.idea}
|
|
4723
|
+
Problem: ${brief.problem}
|
|
4724
|
+
Target Audience: ${brief.targetAudience}
|
|
4725
|
+
Solution: ${brief.solution}
|
|
4726
|
+
Competitors: ${brief.competitors}
|
|
4727
|
+
Monetization: ${brief.monetization}
|
|
4728
|
+
Timeline: ${brief.timeline}
|
|
4729
|
+
Budget: ${brief.budget}
|
|
4730
|
+
Tech Preferences: ${brief.techPreferences}
|
|
4731
|
+
|
|
4732
|
+
Respond with JSON only:
|
|
4733
|
+
{
|
|
4734
|
+
"feedback": "2-3 sentence overall assessment in your voice/personality",
|
|
4735
|
+
"recommendations": ["specific recommendation 1", "recommendation 2", "recommendation 3"],
|
|
4736
|
+
"questions": ["question you'd want answered", "another question"],
|
|
4737
|
+
"risks": ["risk 1", "risk 2"],
|
|
4738
|
+
"score": 7
|
|
4739
|
+
}
|
|
4740
|
+
|
|
4741
|
+
Score 1-10 based on your area of expertise. Be honest but constructive.`
|
|
4742
|
+
}]
|
|
4743
|
+
});
|
|
4744
|
+
const text10 = response.content[0].type === "text" ? response.content[0].text : "";
|
|
4745
|
+
const jsonMatch = text10.match(/\{[\s\S]*\}/);
|
|
4746
|
+
if (!jsonMatch) {
|
|
4747
|
+
return {
|
|
4748
|
+
advisor: advisor.name,
|
|
4749
|
+
role: advisor.role,
|
|
4750
|
+
icon: advisor.icon,
|
|
4751
|
+
feedback: "Unable to generate feedback",
|
|
4752
|
+
recommendations: [],
|
|
4753
|
+
questions: [],
|
|
4754
|
+
risks: [],
|
|
4755
|
+
score: 5
|
|
4756
|
+
};
|
|
4757
|
+
}
|
|
4758
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
4759
|
+
return {
|
|
4760
|
+
advisor: advisor.name,
|
|
4761
|
+
role: advisor.role,
|
|
4762
|
+
icon: advisor.icon,
|
|
4763
|
+
...parsed
|
|
4764
|
+
};
|
|
4765
|
+
}
|
|
4766
|
+
async function generateReport(anthropic, brief, advisorFeedback) {
|
|
4767
|
+
const avgScore = advisorFeedback.reduce((sum, f) => sum + f.score, 0) / advisorFeedback.length;
|
|
4768
|
+
const response = await anthropic.messages.create({
|
|
4769
|
+
model: "claude-sonnet-4-20250514",
|
|
4770
|
+
max_tokens: 8192,
|
|
4771
|
+
messages: [{
|
|
4772
|
+
role: "user",
|
|
4773
|
+
content: `Generate a comprehensive startup plan based on this project brief and advisor feedback.
|
|
4774
|
+
|
|
4775
|
+
PROJECT BRIEF:
|
|
4776
|
+
${JSON.stringify(brief, null, 2)}
|
|
4777
|
+
|
|
4778
|
+
ADVISOR FEEDBACK:
|
|
4779
|
+
${JSON.stringify(advisorFeedback, null, 2)}
|
|
4780
|
+
|
|
4781
|
+
Generate a complete JSON report:
|
|
4782
|
+
{
|
|
4783
|
+
"executiveSummary": "3-4 paragraph executive summary",
|
|
4784
|
+
"goNoGo": "GO" or "CAUTION" or "PIVOT",
|
|
4785
|
+
"marketingPlan": {
|
|
4786
|
+
"positioning": "positioning statement",
|
|
4787
|
+
"targetSegments": ["segment 1", "segment 2"],
|
|
4788
|
+
"channels": ["channel 1", "channel 2"],
|
|
4789
|
+
"launchStrategy": "detailed launch strategy",
|
|
4790
|
+
"contentPlan": ["content idea 1", "content idea 2"],
|
|
4791
|
+
"socialMediaPlan": {
|
|
4792
|
+
"platforms": ["platform 1", "platform 2"],
|
|
4793
|
+
"postFrequency": "frequency",
|
|
4794
|
+
"contentTypes": ["type 1", "type 2"]
|
|
4795
|
+
},
|
|
4796
|
+
"budget": "recommended budget breakdown"
|
|
4797
|
+
},
|
|
4798
|
+
"technicalPlan": {
|
|
4799
|
+
"architecture": "high-level architecture description",
|
|
4800
|
+
"stack": ["Next.js", "Supabase", "etc"],
|
|
4801
|
+
"phases": [
|
|
4802
|
+
{"name": "Phase 1: MVP", "duration": "2 weeks", "deliverables": ["feature 1", "feature 2"]}
|
|
4803
|
+
],
|
|
4804
|
+
"mvpFeatures": ["feature 1", "feature 2"],
|
|
4805
|
+
"futureFeatures": ["feature 1", "feature 2"]
|
|
4806
|
+
},
|
|
4807
|
+
"uxPlan": {
|
|
4808
|
+
"userPersonas": [{"name": "Persona Name", "description": "desc", "goals": ["goal 1"]}],
|
|
4809
|
+
"userJourneys": ["journey 1", "journey 2"],
|
|
4810
|
+
"keyScreens": ["screen 1", "screen 2"],
|
|
4811
|
+
"designPrinciples": ["principle 1", "principle 2"]
|
|
4812
|
+
},
|
|
4813
|
+
"businessPlan": {
|
|
4814
|
+
"revenueModel": "detailed revenue model",
|
|
4815
|
+
"pricing": "pricing strategy",
|
|
4816
|
+
"projections": [{"month": 3, "users": 100, "revenue": 500}],
|
|
4817
|
+
"kpis": ["kpi 1", "kpi 2"],
|
|
4818
|
+
"risks": [{"risk": "risk description", "mitigation": "how to mitigate"}]
|
|
4819
|
+
},
|
|
4820
|
+
"actionItems": [
|
|
4821
|
+
{"priority": "HIGH", "task": "task description", "owner": "CEO/Engineer/etc"}
|
|
4822
|
+
]
|
|
4823
|
+
}
|
|
4824
|
+
|
|
4825
|
+
Be specific, actionable, and realistic based on the timeline and budget.`
|
|
4826
|
+
}]
|
|
4827
|
+
});
|
|
4828
|
+
const text10 = response.content[0].type === "text" ? response.content[0].text : "";
|
|
4829
|
+
const jsonMatch = text10.match(/\{[\s\S]*\}/);
|
|
4830
|
+
const parsed = jsonMatch ? JSON.parse(jsonMatch[0]) : {};
|
|
4831
|
+
return {
|
|
4832
|
+
projectName: brief.name,
|
|
4833
|
+
brief,
|
|
4834
|
+
advisorFeedback,
|
|
4835
|
+
overallScore: Math.round(avgScore * 10) / 10,
|
|
4836
|
+
goNoGo: parsed.goNoGo || (avgScore >= 7 ? "GO" : avgScore >= 5 ? "CAUTION" : "PIVOT"),
|
|
4837
|
+
executiveSummary: parsed.executiveSummary || "",
|
|
4838
|
+
marketingPlan: parsed.marketingPlan || {},
|
|
4839
|
+
technicalPlan: parsed.technicalPlan || {},
|
|
4840
|
+
uxPlan: parsed.uxPlan || {},
|
|
4841
|
+
businessPlan: parsed.businessPlan || {},
|
|
4842
|
+
actionItems: parsed.actionItems || []
|
|
4843
|
+
};
|
|
4844
|
+
}
|
|
4845
|
+
function displayReportSummary(report) {
|
|
4846
|
+
const goNoGoColor = {
|
|
4847
|
+
"GO": chalk15.green,
|
|
4848
|
+
"CAUTION": chalk15.yellow,
|
|
4849
|
+
"PIVOT": chalk15.red
|
|
4850
|
+
}[report.goNoGo];
|
|
4851
|
+
console.log(chalk15.bold(`
|
|
4852
|
+
${"\u2550".repeat(60)}`));
|
|
4853
|
+
console.log(chalk15.bold.cyan(`
|
|
4854
|
+
\u{1F4CA} DREAM TEAM REPORT: ${report.projectName.toUpperCase()}
|
|
4855
|
+
`));
|
|
4856
|
+
console.log(chalk15.bold(`${"\u2550".repeat(60)}
|
|
4857
|
+
`));
|
|
4858
|
+
console.log(chalk15.bold("Overall Assessment:"));
|
|
4859
|
+
console.log(` Score: ${chalk15.bold(report.overallScore.toString())}/10`);
|
|
4860
|
+
console.log(` Verdict: ${goNoGoColor(report.goNoGo)}
|
|
4861
|
+
`);
|
|
4862
|
+
console.log(chalk15.bold("Advisor Scores:"));
|
|
4863
|
+
for (const feedback of report.advisorFeedback) {
|
|
4864
|
+
const bar = "\u2588".repeat(feedback.score) + "\u2591".repeat(10 - feedback.score);
|
|
4865
|
+
console.log(` ${feedback.icon} ${feedback.advisor.padEnd(18)} ${bar} ${feedback.score}/10`);
|
|
4866
|
+
}
|
|
4867
|
+
console.log("");
|
|
4868
|
+
console.log(chalk15.bold("Executive Summary:"));
|
|
4869
|
+
console.log(chalk15.dim(` ${report.executiveSummary.slice(0, 300)}...`));
|
|
4870
|
+
console.log("");
|
|
4871
|
+
console.log(chalk15.bold("Top Action Items:"));
|
|
4872
|
+
const highPriority = report.actionItems.filter((a) => a.priority === "HIGH").slice(0, 5);
|
|
4873
|
+
highPriority.forEach((item, i) => {
|
|
4874
|
+
console.log(` ${chalk15.red("!")} ${item.task}`);
|
|
4875
|
+
});
|
|
4876
|
+
console.log("");
|
|
4877
|
+
if (report.technicalPlan.stack?.length > 0) {
|
|
4878
|
+
console.log(chalk15.bold("Recommended Stack:"));
|
|
4879
|
+
console.log(` ${report.technicalPlan.stack.join(" \u2022 ")}`);
|
|
4880
|
+
console.log("");
|
|
4881
|
+
}
|
|
4882
|
+
console.log(chalk15.dim("Full report saved to PDF with complete marketing, technical, and business plans.\n"));
|
|
4883
|
+
}
|
|
4884
|
+
async function saveReport(report, projectName) {
|
|
4885
|
+
const sanitizedName = projectName.toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
4886
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
4887
|
+
const filename = `${sanitizedName}-dream-team-report-${timestamp}`;
|
|
4888
|
+
const mdPath = path12.join(process.cwd(), `${filename}.md`);
|
|
4889
|
+
const mdContent = generateMarkdownReport(report);
|
|
4890
|
+
await fs12.writeFile(mdPath, mdContent);
|
|
4891
|
+
const jsonPath = path12.join(process.cwd(), `${filename}.json`);
|
|
4892
|
+
await fs12.writeJson(jsonPath, report, { spaces: 2 });
|
|
4893
|
+
return mdPath;
|
|
4894
|
+
}
|
|
4895
|
+
function generateMarkdownReport(report) {
|
|
4896
|
+
const goNoGoEmoji = { "GO": "\u{1F7E2}", "CAUTION": "\u{1F7E1}", "PIVOT": "\u{1F534}" }[report.goNoGo];
|
|
4897
|
+
return `# ${report.projectName} - Dream Team Report
|
|
4898
|
+
|
|
4899
|
+
**Generated:** ${(/* @__PURE__ */ new Date()).toLocaleDateString()}
|
|
4900
|
+
**Overall Score:** ${report.overallScore}/10
|
|
4901
|
+
**Verdict:** ${goNoGoEmoji} ${report.goNoGo}
|
|
4902
|
+
|
|
4903
|
+
---
|
|
4904
|
+
|
|
4905
|
+
## Executive Summary
|
|
4906
|
+
|
|
4907
|
+
${report.executiveSummary}
|
|
4908
|
+
|
|
4909
|
+
---
|
|
4910
|
+
|
|
4911
|
+
## Advisor Feedback
|
|
4912
|
+
|
|
4913
|
+
${report.advisorFeedback.map((f) => `
|
|
4914
|
+
### ${f.icon} ${f.advisor} - ${f.role}
|
|
4915
|
+
|
|
4916
|
+
**Score:** ${f.score}/10
|
|
4917
|
+
|
|
4918
|
+
${f.feedback}
|
|
4919
|
+
|
|
4920
|
+
**Recommendations:**
|
|
4921
|
+
${f.recommendations.map((r) => `- ${r}`).join("\n")}
|
|
4922
|
+
|
|
4923
|
+
**Questions to Consider:**
|
|
4924
|
+
${f.questions.map((q) => `- ${q}`).join("\n")}
|
|
4925
|
+
|
|
4926
|
+
**Risks Identified:**
|
|
4927
|
+
${f.risks.map((r) => `- ${r}`).join("\n")}
|
|
4928
|
+
`).join("\n")}
|
|
4929
|
+
|
|
4930
|
+
---
|
|
4931
|
+
|
|
4932
|
+
## Marketing Plan
|
|
4933
|
+
|
|
4934
|
+
### Positioning
|
|
4935
|
+
${report.marketingPlan.positioning}
|
|
4936
|
+
|
|
4937
|
+
### Target Segments
|
|
4938
|
+
${report.marketingPlan.targetSegments?.map((s) => `- ${s}`).join("\n") || "TBD"}
|
|
4939
|
+
|
|
4940
|
+
### Marketing Channels
|
|
4941
|
+
${report.marketingPlan.channels?.map((c) => `- ${c}`).join("\n") || "TBD"}
|
|
4942
|
+
|
|
4943
|
+
### Launch Strategy
|
|
4944
|
+
${report.marketingPlan.launchStrategy}
|
|
4945
|
+
|
|
4946
|
+
### Content Plan
|
|
4947
|
+
${report.marketingPlan.contentPlan?.map((c) => `- ${c}`).join("\n") || "TBD"}
|
|
4948
|
+
|
|
4949
|
+
### Social Media Plan
|
|
4950
|
+
- **Platforms:** ${report.marketingPlan.socialMediaPlan?.platforms?.join(", ") || "TBD"}
|
|
4951
|
+
- **Post Frequency:** ${report.marketingPlan.socialMediaPlan?.postFrequency || "TBD"}
|
|
4952
|
+
- **Content Types:** ${report.marketingPlan.socialMediaPlan?.contentTypes?.join(", ") || "TBD"}
|
|
4953
|
+
|
|
4954
|
+
### Budget
|
|
4955
|
+
${report.marketingPlan.budget}
|
|
4956
|
+
|
|
4957
|
+
---
|
|
4958
|
+
|
|
4959
|
+
## Technical Plan
|
|
4960
|
+
|
|
4961
|
+
### Architecture
|
|
4962
|
+
${report.technicalPlan.architecture}
|
|
4963
|
+
|
|
4964
|
+
### Tech Stack
|
|
4965
|
+
${report.technicalPlan.stack?.map((s) => `- ${s}`).join("\n") || "TBD"}
|
|
4966
|
+
|
|
4967
|
+
### Development Phases
|
|
4968
|
+
${report.technicalPlan.phases?.map((p16) => `
|
|
4969
|
+
#### ${p16.name} (${p16.duration})
|
|
4970
|
+
${p16.deliverables.map((d) => `- ${d}`).join("\n")}
|
|
4971
|
+
`).join("\n") || "TBD"}
|
|
4972
|
+
|
|
4973
|
+
### MVP Features
|
|
4974
|
+
${report.technicalPlan.mvpFeatures?.map((f) => `- ${f}`).join("\n") || "TBD"}
|
|
4975
|
+
|
|
4976
|
+
### Future Features
|
|
4977
|
+
${report.technicalPlan.futureFeatures?.map((f) => `- ${f}`).join("\n") || "TBD"}
|
|
4978
|
+
|
|
4979
|
+
---
|
|
4980
|
+
|
|
4981
|
+
## UX Plan
|
|
4982
|
+
|
|
4983
|
+
### User Personas
|
|
4984
|
+
${report.uxPlan.userPersonas?.map((p16) => `
|
|
4985
|
+
#### ${p16.name}
|
|
4986
|
+
${p16.description}
|
|
4987
|
+
|
|
4988
|
+
**Goals:**
|
|
4989
|
+
${p16.goals.map((g) => `- ${g}`).join("\n")}
|
|
4990
|
+
`).join("\n") || "TBD"}
|
|
4991
|
+
|
|
4992
|
+
### User Journeys
|
|
4993
|
+
${report.uxPlan.userJourneys?.map((j) => `- ${j}`).join("\n") || "TBD"}
|
|
4994
|
+
|
|
4995
|
+
### Key Screens
|
|
4996
|
+
${report.uxPlan.keyScreens?.map((s) => `- ${s}`).join("\n") || "TBD"}
|
|
4997
|
+
|
|
4998
|
+
### Design Principles
|
|
4999
|
+
${report.uxPlan.designPrinciples?.map((p16) => `- ${p16}`).join("\n") || "TBD"}
|
|
5000
|
+
|
|
5001
|
+
---
|
|
5002
|
+
|
|
5003
|
+
## Business Plan
|
|
5004
|
+
|
|
5005
|
+
### Revenue Model
|
|
5006
|
+
${report.businessPlan.revenueModel}
|
|
5007
|
+
|
|
5008
|
+
### Pricing Strategy
|
|
5009
|
+
${report.businessPlan.pricing}
|
|
5010
|
+
|
|
5011
|
+
### Projections
|
|
5012
|
+
| Month | Users | Revenue |
|
|
5013
|
+
|-------|-------|---------|
|
|
5014
|
+
${report.businessPlan.projections?.map((p16) => `| ${p16.month} | ${p16.users} | $${p16.revenue} |`).join("\n") || "| TBD | TBD | TBD |"}
|
|
5015
|
+
|
|
5016
|
+
### KPIs
|
|
5017
|
+
${report.businessPlan.kpis?.map((k) => `- ${k}`).join("\n") || "TBD"}
|
|
5018
|
+
|
|
5019
|
+
### Risks & Mitigation
|
|
5020
|
+
| Risk | Mitigation |
|
|
5021
|
+
|------|------------|
|
|
5022
|
+
${report.businessPlan.risks?.map((r) => `| ${r.risk} | ${r.mitigation} |`).join("\n") || "| TBD | TBD |"}
|
|
5023
|
+
|
|
5024
|
+
---
|
|
5025
|
+
|
|
5026
|
+
## Action Items
|
|
5027
|
+
|
|
5028
|
+
### High Priority
|
|
5029
|
+
${report.actionItems.filter((a) => a.priority === "HIGH").map((a) => `- [ ] **${a.task}** (Owner: ${a.owner})`).join("\n") || "None"}
|
|
5030
|
+
|
|
5031
|
+
### Medium Priority
|
|
5032
|
+
${report.actionItems.filter((a) => a.priority === "MEDIUM").map((a) => `- [ ] ${a.task} (Owner: ${a.owner})`).join("\n") || "None"}
|
|
5033
|
+
|
|
5034
|
+
### Low Priority
|
|
5035
|
+
${report.actionItems.filter((a) => a.priority === "LOW").map((a) => `- [ ] ${a.task} (Owner: ${a.owner})`).join("\n") || "None"}
|
|
5036
|
+
|
|
5037
|
+
---
|
|
5038
|
+
|
|
5039
|
+
## Next Steps
|
|
5040
|
+
|
|
5041
|
+
1. Review this report with your team
|
|
5042
|
+
2. Run \`codebakers prd ${report.projectName.toLowerCase().replace(/[^a-z0-9]/g, "-")}-dream-team-report.md\` to start building
|
|
5043
|
+
3. Or run \`codebakers init\` for standard project setup
|
|
5044
|
+
|
|
5045
|
+
---
|
|
5046
|
+
|
|
5047
|
+
*Generated by CodeBakers Dream Team Advisors*
|
|
5048
|
+
`;
|
|
5049
|
+
}
|
|
5050
|
+
|
|
4106
5051
|
// src/index.ts
|
|
4107
5052
|
var VERSION2 = "1.0.0";
|
|
4108
5053
|
var logo = `
|
|
@@ -4117,18 +5062,18 @@ async function showMainMenu() {
|
|
|
4117
5062
|
const config = new Config();
|
|
4118
5063
|
const isSetup = config.isConfigured();
|
|
4119
5064
|
console.log(gradient.pastel.multiline(logo));
|
|
4120
|
-
console.log(
|
|
5065
|
+
console.log(chalk16.dim(` v${VERSION2} \u2014 AI dev team that follows the rules
|
|
4121
5066
|
`));
|
|
4122
5067
|
if (!isSetup) {
|
|
4123
5068
|
console.log(boxen(
|
|
4124
|
-
|
|
5069
|
+
chalk16.yellow("Welcome to CodeBakers! Let's get you set up."),
|
|
4125
5070
|
{ padding: 1, borderColor: "yellow", borderStyle: "round" }
|
|
4126
5071
|
));
|
|
4127
5072
|
await setupCommand();
|
|
4128
5073
|
return;
|
|
4129
5074
|
}
|
|
4130
5075
|
const inProject = config.isInProject();
|
|
4131
|
-
const action = await
|
|
5076
|
+
const action = await p15.select({
|
|
4132
5077
|
message: "What do you want to do?",
|
|
4133
5078
|
options: inProject ? [
|
|
4134
5079
|
{ value: "code", label: "\u{1F4AC} Code with AI", hint: "build features, fix bugs" },
|
|
@@ -4145,10 +5090,14 @@ async function showMainMenu() {
|
|
|
4145
5090
|
{ value: "design", label: "\u{1F3A8} Design system", hint: "set profile, colors" },
|
|
4146
5091
|
{ value: "separator2", label: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" },
|
|
4147
5092
|
{ value: "new", label: "\u{1F195} Create new project" },
|
|
5093
|
+
{ value: "prd", label: "\u{1F4C4} Build from PRD", hint: "upload a PRD document" },
|
|
5094
|
+
{ value: "advisors", label: "\u{1F31F} Dream Team Advisors", hint: "consult with experts" },
|
|
4148
5095
|
{ value: "settings", label: "\u2699\uFE0F Settings" },
|
|
4149
5096
|
{ value: "help", label: "\u2753 Help" }
|
|
4150
5097
|
] : [
|
|
4151
5098
|
{ value: "new", label: "\u{1F195} Create new project" },
|
|
5099
|
+
{ value: "prd", label: "\u{1F4C4} Build from PRD", hint: "upload a PRD document" },
|
|
5100
|
+
{ value: "advisors", label: "\u{1F31F} Dream Team Advisors", hint: "consult with experts" },
|
|
4152
5101
|
{ value: "open", label: "\u{1F4C2} Open existing project" },
|
|
4153
5102
|
{ value: "status", label: "\u{1F4CA} View all projects" },
|
|
4154
5103
|
{ value: "separator1", label: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" },
|
|
@@ -4159,8 +5108,8 @@ async function showMainMenu() {
|
|
|
4159
5108
|
{ value: "help", label: "\u2753 Help" }
|
|
4160
5109
|
]
|
|
4161
5110
|
});
|
|
4162
|
-
if (
|
|
4163
|
-
|
|
5111
|
+
if (p15.isCancel(action)) {
|
|
5112
|
+
p15.cancel("Goodbye!");
|
|
4164
5113
|
process.exit(0);
|
|
4165
5114
|
}
|
|
4166
5115
|
switch (action) {
|
|
@@ -4200,6 +5149,12 @@ async function showMainMenu() {
|
|
|
4200
5149
|
case "new":
|
|
4201
5150
|
await initCommand();
|
|
4202
5151
|
break;
|
|
5152
|
+
case "prd":
|
|
5153
|
+
await prdCommand();
|
|
5154
|
+
break;
|
|
5155
|
+
case "advisors":
|
|
5156
|
+
await advisorsCommand();
|
|
5157
|
+
break;
|
|
4203
5158
|
case "settings":
|
|
4204
5159
|
await setupCommand();
|
|
4205
5160
|
break;
|
|
@@ -4212,27 +5167,27 @@ async function showMainMenu() {
|
|
|
4212
5167
|
}
|
|
4213
5168
|
function showHelp2() {
|
|
4214
5169
|
console.log(boxen(`
|
|
4215
|
-
${
|
|
4216
|
-
|
|
4217
|
-
${
|
|
4218
|
-
${
|
|
4219
|
-
${
|
|
4220
|
-
${
|
|
4221
|
-
${
|
|
4222
|
-
${
|
|
4223
|
-
${
|
|
4224
|
-
${
|
|
4225
|
-
${
|
|
4226
|
-
${
|
|
4227
|
-
${
|
|
4228
|
-
${
|
|
4229
|
-
${
|
|
4230
|
-
|
|
4231
|
-
${
|
|
4232
|
-
Press ${
|
|
4233
|
-
|
|
4234
|
-
${
|
|
4235
|
-
${
|
|
5170
|
+
${chalk16.bold("CodeBakers CLI")} \u2014 AI dev team that follows the rules
|
|
5171
|
+
|
|
5172
|
+
${chalk16.bold("Commands:")}
|
|
5173
|
+
${chalk16.cyan("codebakers")} Interactive menu (or just run with no args)
|
|
5174
|
+
${chalk16.cyan("codebakers init")} Create a new project
|
|
5175
|
+
${chalk16.cyan("codebakers code")} Start AI coding session
|
|
5176
|
+
${chalk16.cyan("codebakers check")} Run pattern enforcement
|
|
5177
|
+
${chalk16.cyan("codebakers deploy")} Deploy to production
|
|
5178
|
+
${chalk16.cyan("codebakers fix")} Auto-fix errors
|
|
5179
|
+
${chalk16.cyan("codebakers generate")} Generate components/pages
|
|
5180
|
+
${chalk16.cyan("codebakers connect")} Connect external services
|
|
5181
|
+
${chalk16.cyan("codebakers gateway")} Manage messaging channels
|
|
5182
|
+
${chalk16.cyan("codebakers status")} View project status
|
|
5183
|
+
${chalk16.cyan("codebakers security")} Run security audit
|
|
5184
|
+
${chalk16.cyan("codebakers learn")} View/manage learning
|
|
5185
|
+
|
|
5186
|
+
${chalk16.bold("Help at any time:")}
|
|
5187
|
+
Press ${chalk16.yellow("?")} during any command to get contextual help
|
|
5188
|
+
|
|
5189
|
+
${chalk16.bold("Documentation:")}
|
|
5190
|
+
${chalk16.dim("https://codebakers.dev/docs")}
|
|
4236
5191
|
`, { padding: 1, borderColor: "cyan", borderStyle: "round" }));
|
|
4237
5192
|
}
|
|
4238
5193
|
var program = new Command();
|
|
@@ -4250,6 +5205,8 @@ program.command("status").description("View project status and health").option("
|
|
|
4250
5205
|
program.command("security").description("Run security audit").option("--fix", "Auto-fix security issues").action(securityCommand);
|
|
4251
5206
|
program.command("learn").description("View and manage learning settings").option("--forget <item>", "Forget a learned preference").option("--reset", "Reset all learning").option("--export", "Export learned patterns").action(learnCommand);
|
|
4252
5207
|
program.command("design [action]").description("Manage design system (profile, palette, check)").action(designCommand);
|
|
5208
|
+
program.command("prd [file]").description("Build entire project from a PRD document").action(prdCommand);
|
|
5209
|
+
program.command("advisors").alias("dream-team").description("Consult with the CodeBakers Dream Team advisory board").action(advisorsCommand);
|
|
4253
5210
|
var args = process.argv.slice(2);
|
|
4254
5211
|
if (args.length === 0) {
|
|
4255
5212
|
checkForUpdates().catch(() => {
|