codebakers 3.0.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +811 -176
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6,9 +6,9 @@ import {
6
6
  } from "./chunk-HOWR3YTF.js";
7
7
 
8
8
  // src/index.ts
9
- import * as p6 from "@clack/prompts";
9
+ import * as p8 from "@clack/prompts";
10
10
  import ora3 from "ora";
11
- import fs17 from "fs-extra";
11
+ import fs18 from "fs-extra";
12
12
 
13
13
  // src/core/config.ts
14
14
  import Conf from "conf";
@@ -1285,7 +1285,7 @@ ${originalRequest}`;
1285
1285
  }
1286
1286
  const pathMatch = request.match(/['"`]([^'"`]+)['"`]/g);
1287
1287
  if (pathMatch) {
1288
- keywords.push(...pathMatch.map((p7) => p7.replace(/['"`]/g, "")));
1288
+ keywords.push(...pathMatch.map((p9) => p9.replace(/['"`]/g, "")));
1289
1289
  }
1290
1290
  return keywords;
1291
1291
  }
@@ -1499,11 +1499,11 @@ Format each as a single line. Be brief.`;
1499
1499
  } else if (line.toLowerCase().includes("suggestion") || line.toLowerCase().includes("improvement")) {
1500
1500
  currentSection = "suggestions";
1501
1501
  } else if (line.startsWith("-") || line.startsWith("\u2022") || /^\d+\./.test(line)) {
1502
- const text3 = line.replace(/^[-•\d.]\s*/, "").trim();
1503
- if (text3 && currentSection === "issues") {
1504
- issues.push(text3);
1505
- } else if (text3 && currentSection === "suggestions") {
1506
- suggestions.push(text3);
1502
+ const text6 = line.replace(/^[-•\d.]\s*/, "").trim();
1503
+ if (text6 && currentSection === "issues") {
1504
+ issues.push(text6);
1505
+ } else if (text6 && currentSection === "suggestions") {
1506
+ suggestions.push(text6);
1507
1507
  }
1508
1508
  }
1509
1509
  }
@@ -1572,8 +1572,8 @@ Format each as a single line. Be brief.`;
1572
1572
  if (this.ai) {
1573
1573
  onProgress?.("Running AI deep analysis...", 60);
1574
1574
  const filesForAI = await Promise.all(
1575
- filePaths.slice(0, 50).map(async (p7) => {
1576
- const f = await this.loadFile(p7);
1575
+ filePaths.slice(0, 50).map(async (p9) => {
1576
+ const f = await this.loadFile(p9);
1577
1577
  return f ? { path: f.path, content: f.content } : null;
1578
1578
  })
1579
1579
  );
@@ -1729,43 +1729,50 @@ import * as p from "@clack/prompts";
1729
1729
  // src/utils/ui.ts
1730
1730
  import chalk from "chalk";
1731
1731
  var colors = {
1732
- primary: chalk.hex("#ff6b6b"),
1733
- secondary: chalk.hex("#4ecdc4"),
1734
- success: chalk.hex("#7ee787"),
1735
- error: chalk.hex("#f85149"),
1736
- warning: chalk.hex("#d29922"),
1737
- muted: chalk.hex("#6e7681"),
1738
- white: chalk.white
1732
+ primary: chalk.hex("#7fff00"),
1733
+ // Lime green (accent)
1734
+ secondary: chalk.hex("#888888"),
1735
+ // Gray text
1736
+ muted: chalk.hex("#555555"),
1737
+ // Dimmed text
1738
+ success: chalk.hex("#27ae60"),
1739
+ // Green
1740
+ warning: chalk.hex("#f39c12"),
1741
+ // Orange
1742
+ error: chalk.hex("#e74c3c"),
1743
+ // Red
1744
+ info: chalk.hex("#3498db"),
1745
+ // Blue
1746
+ white: chalk.hex("#eeeeee"),
1747
+ dim: chalk.hex("#666666")
1748
+ };
1749
+ var sym = {
1750
+ check: chalk.green("\u2713"),
1751
+ cross: chalk.red("\u2717"),
1752
+ box: chalk.dim("\u2610"),
1753
+ bullet: chalk.dim("\u2022"),
1754
+ arrow: chalk.dim("\u2192"),
1755
+ ellipsis: "\u2026",
1756
+ spinner: "\u27F3"
1739
1757
  };
1740
1758
  function showHeader() {
1741
1759
  console.clear();
1742
1760
  console.log("");
1743
- console.log(colors.primary(" \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\u2557"));
1744
- console.log(colors.primary(" \u2551") + colors.white(" \u{1F35E} CODEBAKERS ") + colors.primary("\u2551"));
1745
- console.log(colors.primary(" \u2551") + colors.muted(" AI Dev Team That Follows The Rules ") + colors.primary("\u2551"));
1746
- console.log(colors.primary(" \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\u255D"));
1747
- console.log("");
1748
- }
1749
- function showProjectStatus(name, framework) {
1750
- console.log(colors.muted(" \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"));
1751
- console.log(colors.white(` \u{1F4C1} ${name}`) + colors.muted(` (${framework || "Unknown"})`));
1752
- console.log(colors.muted(" \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"));
1761
+ console.log(colors.muted(" \u250C\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\u2510"));
1762
+ console.log(colors.muted(" \u2502") + colors.white(" \u{1F4E6} C O D E B A K E R S ") + colors.muted("\u2502"));
1763
+ console.log(colors.muted(" \u2502") + colors.dim(" ") + colors.muted("\u2502"));
1764
+ console.log(colors.muted(" \u2502") + colors.secondary(" AI Dev Team That Follows The Rules ") + colors.muted("\u2502"));
1765
+ console.log(colors.muted(" \u2514\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\u2518"));
1753
1766
  console.log("");
1754
1767
  }
1755
1768
  function showSuccess(message) {
1756
- console.log("");
1757
- console.log(colors.success(` \u2705 ${message}`));
1758
- console.log("");
1769
+ console.log(` ${sym.check} ${colors.white(message)}`);
1759
1770
  }
1760
1771
  function showError(message) {
1761
- console.log("");
1762
- console.log(colors.error(` \u274C ${message}`));
1763
- console.log("");
1772
+ console.log(` ${sym.cross} ${colors.error(message)}`);
1764
1773
  }
1765
1774
  function showWarning(message) {
1766
- console.log("");
1767
- console.log(colors.warning(` \u26A0\uFE0F ${message}`));
1768
- console.log("");
1775
+ console.log(` ${colors.warning("\u26A0")} ${colors.warning(message)}`);
1769
1776
  }
1770
1777
  function showInfo(message) {
1771
1778
  console.log(colors.muted(` \u2139\uFE0F ${message}`));
@@ -1774,15 +1781,6 @@ function divider() {
1774
1781
  console.log(colors.muted(" \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"));
1775
1782
  }
1776
1783
  var promptSymbol = colors.primary("\u276F");
1777
- function showWelcome() {
1778
- console.log(colors.muted(" Just tell me what you need:"));
1779
- console.log(colors.muted(' "Add a login page" - Generate code'));
1780
- console.log(colors.muted(' "Review my code" - Analyze codebase'));
1781
- console.log(colors.muted(' "Deploy to production" - Ship it'));
1782
- console.log(colors.muted(' "Undo that" - Rollback'));
1783
- console.log(colors.muted(" /help - All commands"));
1784
- console.log("");
1785
- }
1786
1784
 
1787
1785
  // src/core/nlp.ts
1788
1786
  var INTENT_PATTERNS = [
@@ -2398,7 +2396,11 @@ var NLPInterpreter = class {
2398
2396
  "account": "whoami",
2399
2397
  "me": "whoami",
2400
2398
  "index": "index",
2401
- "rag": "index"
2399
+ "rag": "index",
2400
+ "folder": "folder",
2401
+ "cd": "folder",
2402
+ "chdir": "folder",
2403
+ "browse": "folder"
2402
2404
  };
2403
2405
  const intent = commandMap[lower] || "unclear";
2404
2406
  const params = {};
@@ -2501,12 +2503,12 @@ var NLPInterpreter = class {
2501
2503
  deploy: "This will deploy your code. Continue?"
2502
2504
  };
2503
2505
  console.log("");
2504
- const confirm7 = await p.confirm({
2506
+ const confirm8 = await p.confirm({
2505
2507
  message: colors.warning(messages[intent.type] || "Are you sure?"),
2506
2508
  initialValue: intent.type !== "deploy"
2507
2509
  // Default no for deploy
2508
2510
  });
2509
- return !p.isCancel(confirm7) && confirm7 === true;
2511
+ return !p.isCancel(confirm8) && confirm8 === true;
2510
2512
  }
2511
2513
  };
2512
2514
  var nlp = new NLPInterpreter();
@@ -2734,22 +2736,22 @@ Please provide ONLY the corrected file content with the path. No explanation nee
2734
2736
  // HELPERS
2735
2737
  // ============================================================================
2736
2738
  async findMissingPackages(packages) {
2737
- const fs18 = await import("fs-extra");
2738
- const path17 = await import("path");
2739
- const pkgPath = path17.join(this.scanner["projectPath"], "package.json");
2740
- if (!await fs18.pathExists(pkgPath)) return packages;
2741
- const pkg = await fs18.readJson(pkgPath);
2739
+ const fs19 = await import("fs-extra");
2740
+ const path19 = await import("path");
2741
+ const pkgPath = path19.join(this.scanner["projectPath"], "package.json");
2742
+ if (!await fs19.pathExists(pkgPath)) return packages;
2743
+ const pkg = await fs19.readJson(pkgPath);
2742
2744
  const installed = {
2743
2745
  ...pkg.dependencies,
2744
2746
  ...pkg.devDependencies
2745
2747
  };
2746
- return packages.filter((p7) => !installed[p7]);
2748
+ return packages.filter((p9) => !installed[p9]);
2747
2749
  }
2748
- spin(text3) {
2750
+ spin(text6) {
2749
2751
  if (this.spinner) {
2750
- this.spinner.text = text3 + " (ESC to cancel)";
2752
+ this.spinner.text = text6 + " (ESC to cancel)";
2751
2753
  } else {
2752
- this.spinner = ora(text3 + " (ESC to cancel)").start();
2754
+ this.spinner = ora(text6 + " (ESC to cancel)").start();
2753
2755
  }
2754
2756
  }
2755
2757
  stop() {
@@ -4067,9 +4069,9 @@ Create ALL files listed above.`;
4067
4069
  const count = pathMap.get(file.path) || 0;
4068
4070
  pathMap.set(file.path, count + 1);
4069
4071
  }
4070
- for (const [path17, count] of pathMap) {
4072
+ for (const [path19, count] of pathMap) {
4071
4073
  if (count > 1) {
4072
- conflicts.push(`Multiple agents created: ${path17}`);
4074
+ conflicts.push(`Multiple agents created: ${path19}`);
4073
4075
  }
4074
4076
  }
4075
4077
  for (const file of files) {
@@ -4877,11 +4879,11 @@ var AgentExecutor = class {
4877
4879
  }
4878
4880
  return Array.from(packages);
4879
4881
  }
4880
- spin(text3) {
4882
+ spin(text6) {
4881
4883
  if (this.spinner) {
4882
- this.spinner.text = text3;
4884
+ this.spinner.text = text6;
4883
4885
  } else {
4884
- this.spinner = ora2(text3).start();
4886
+ this.spinner = ora2(text6).start();
4885
4887
  }
4886
4888
  }
4887
4889
  stop() {
@@ -5186,7 +5188,7 @@ ${chunks[i]}`,
5186
5188
  projectName: analysis.projectName,
5187
5189
  totalFeatures: analysis.features.length,
5188
5190
  completedFeatures: analysis.features.filter((f) => f.status === "complete").length,
5189
- currentPhase: analysis.phases.find((p7) => p7.status === "in_progress")?.id || analysis.phases[0]?.id || "",
5191
+ currentPhase: analysis.phases.find((p9) => p9.status === "in_progress")?.id || analysis.phases[0]?.id || "",
5190
5192
  currentFeature: analysis.features.find((f) => f.status === "in_progress")?.id || "",
5191
5193
  features: analysis.features.map((f) => ({ id: f.id, status: f.status })),
5192
5194
  startedAt: Date.now(),
@@ -6682,8 +6684,8 @@ var SmartGitManager = class {
6682
6684
  const pr = await this.createPR(phaseBranch, baseBranch);
6683
6685
  return pr;
6684
6686
  }
6685
- slugify(text3) {
6686
- return text3.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 30);
6687
+ slugify(text6) {
6688
+ return text6.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 30);
6687
6689
  }
6688
6690
  // ============================================================================
6689
6691
  // SMART COMMITS
@@ -6962,7 +6964,7 @@ var ProjectBuilder = class {
6962
6964
  totalDuration: 0
6963
6965
  };
6964
6966
  try {
6965
- const phaseNames = spec.buildPhases.map((p7) => p7.name.replace(/Phase \d+:\s*/i, ""));
6967
+ const phaseNames = spec.buildPhases.map((p9) => p9.name.replace(/Phase \d+:\s*/i, ""));
6966
6968
  const strategy = await this.git.createProjectStrategy(spec.name, phaseNames);
6967
6969
  console.log(this.git.formatStrategy(strategy));
6968
6970
  const proceed = await p4.confirm({
@@ -7669,7 +7671,7 @@ Return ONLY the fixed code, no explanations. Keep all other code exactly the sam
7669
7671
  return this.patterns;
7670
7672
  }
7671
7673
  enablePattern(id) {
7672
- const pattern = this.patterns.find((p7) => p7.id === id);
7674
+ const pattern = this.patterns.find((p9) => p9.id === id);
7673
7675
  if (pattern) {
7674
7676
  pattern.enabled = true;
7675
7677
  return true;
@@ -7677,7 +7679,7 @@ Return ONLY the fixed code, no explanations. Keep all other code exactly the sam
7677
7679
  return false;
7678
7680
  }
7679
7681
  disablePattern(id) {
7680
- const pattern = this.patterns.find((p7) => p7.id === id);
7682
+ const pattern = this.patterns.find((p9) => p9.id === id);
7681
7683
  if (pattern) {
7682
7684
  pattern.enabled = false;
7683
7685
  return true;
@@ -7736,8 +7738,8 @@ Return ONLY the fixed code, no explanations. Keep all other code exactly the sam
7736
7738
  formatPatterns() {
7737
7739
  let output = "\n";
7738
7740
  output += colors.white(" \u{1F4CB} Pattern Rules") + "\n\n";
7739
- const enabled = this.patterns.filter((p7) => p7.enabled);
7740
- const disabled = this.patterns.filter((p7) => !p7.enabled);
7741
+ const enabled = this.patterns.filter((p9) => p9.enabled);
7742
+ const disabled = this.patterns.filter((p9) => !p9.enabled);
7741
7743
  output += colors.success(" ENABLED") + "\n";
7742
7744
  for (const pattern of enabled) {
7743
7745
  const severityIcon = pattern.severity === "critical" ? "\u{1F534}" : pattern.severity === "warning" ? "\u{1F7E1}" : "\u{1F7E2}";
@@ -7762,7 +7764,7 @@ Return ONLY the fixed code, no explanations. Keep all other code exactly the sam
7762
7764
  return grouped;
7763
7765
  }
7764
7766
  getPatternName(id) {
7765
- const pattern = this.patterns.find((p7) => p7.id === id);
7767
+ const pattern = this.patterns.find((p9) => p9.id === id);
7766
7768
  return pattern?.name || id;
7767
7769
  }
7768
7770
  // ============================================================================
@@ -7968,7 +7970,7 @@ var SmartSuggestions = class {
7968
7970
  /platform\s*(that|which|for)/,
7969
7971
  /saas\s*(for|that|which)/
7970
7972
  ];
7971
- return ideaPatterns.some((p7) => p7.test(lower));
7973
+ return ideaPatterns.some((p9) => p9.test(lower));
7972
7974
  }
7973
7975
  looksLikeComplexRequest(input) {
7974
7976
  const lower = input.toLowerCase();
@@ -7998,7 +8000,7 @@ var SmartSuggestions = class {
7998
8000
  /clean\s*up/,
7999
8001
  /improve\s*(the\s*)?(code|quality)/
8000
8002
  ];
8001
- return patterns.some((p7) => p7.test(lower));
8003
+ return patterns.some((p9) => p9.test(lower));
8002
8004
  }
8003
8005
  // ============================================================================
8004
8006
  // DISPLAY
@@ -8028,6 +8030,23 @@ var AUTH_STORE = new Conf2({
8028
8030
  projectName: "codebakers",
8029
8031
  encryptionKey: "cb-secure-storage-key-2026"
8030
8032
  });
8033
+ var ADMIN_CODES = {
8034
+ "ADMIN-DANIEL-2026": { email: "daniel@botmakers.ai", name: "Daniel" },
8035
+ "ADMIN-BOTMAKERS": { email: "admin@botmakers.ai", name: "Admin" }
8036
+ // Add more admin codes here
8037
+ };
8038
+ var BETA_CODES = {
8039
+ "BETA-TESTER-001": { email: "tester1@beta.com", name: "Beta Tester 1", expiresAt: "2026-12-31" },
8040
+ "BETA-TESTER-002": { email: "tester2@beta.com", name: "Beta Tester 2", expiresAt: "2026-12-31" },
8041
+ "BETA-EARLY-ACCESS": { email: "early@beta.com", name: "Early Access", expiresAt: "2026-06-30" }
8042
+ // Add more beta codes here
8043
+ };
8044
+ var WHITELISTED_EMAILS = [
8045
+ "daniel@botmakers.ai",
8046
+ "admin@botmakers.ai",
8047
+ "team@botmakers.ai"
8048
+ // Add more whitelisted emails here
8049
+ ];
8031
8050
  var FEATURES = {
8032
8051
  // Free features
8033
8052
  basic_build: "basic_build",
@@ -8044,6 +8063,7 @@ var FEATURES = {
8044
8063
  whitelabel: "whitelabel",
8045
8064
  priority_support: "priority_support"
8046
8065
  };
8066
+ var ALL_FEATURES = Object.values(FEATURES);
8047
8067
  var Auth = class _Auth {
8048
8068
  static instance;
8049
8069
  constructor() {
@@ -8055,7 +8075,7 @@ var Auth = class _Auth {
8055
8075
  return _Auth.instance;
8056
8076
  }
8057
8077
  // ============================================================================
8058
- // LOGIN FLOW
8078
+ // LOGIN FLOW - Multiple methods
8059
8079
  // ============================================================================
8060
8080
  async login() {
8061
8081
  const existing = this.getAuth();
@@ -8071,6 +8091,163 @@ var Auth = class _Auth {
8071
8091
  console.log("");
8072
8092
  console.log(colors.white(" \u{1F510} CodeBakers Login"));
8073
8093
  console.log("");
8094
+ const method = await p5.select({
8095
+ message: "How would you like to login?",
8096
+ options: [
8097
+ { value: "browser", label: "Login with browser (Google/GitHub)" },
8098
+ { value: "code", label: "Enter admin/beta code" },
8099
+ { value: "apikey", label: "Use API key only (no account)" }
8100
+ ]
8101
+ });
8102
+ if (p5.isCancel(method)) {
8103
+ return false;
8104
+ }
8105
+ switch (method) {
8106
+ case "code":
8107
+ return this.loginWithCode();
8108
+ case "apikey":
8109
+ return this.loginWithApiKey();
8110
+ default:
8111
+ return this.loginWithBrowser();
8112
+ }
8113
+ }
8114
+ // ============================================================================
8115
+ // LOGIN WITH SPECIAL CODE (Admin/Beta)
8116
+ // ============================================================================
8117
+ async loginWithCode() {
8118
+ console.log("");
8119
+ console.log(colors.secondary(" Enter your admin or beta code:"));
8120
+ const code = await p5.text({
8121
+ message: "Code:",
8122
+ placeholder: "ADMIN-XXXX or BETA-XXXX"
8123
+ });
8124
+ if (p5.isCancel(code) || !code) {
8125
+ return false;
8126
+ }
8127
+ const codeUpper = code.toString().toUpperCase().trim();
8128
+ if (ADMIN_CODES[codeUpper]) {
8129
+ const admin = ADMIN_CODES[codeUpper];
8130
+ const auth2 = {
8131
+ accessToken: `admin_${codeUpper}_${Date.now()}`,
8132
+ refreshToken: "",
8133
+ user: {
8134
+ id: `admin_${codeUpper}`,
8135
+ email: admin.email,
8136
+ name: admin.name
8137
+ },
8138
+ license: {
8139
+ tier: "admin",
8140
+ features: ALL_FEATURES,
8141
+ expiresAt: null,
8142
+ // Never expires
8143
+ usage: { current: 0, limit: 999999 }
8144
+ },
8145
+ expiresAt: Date.now() + 365 * 24 * 60 * 60 * 1e3,
8146
+ // 1 year
8147
+ authType: "admin"
8148
+ };
8149
+ this.saveAuth(auth2);
8150
+ console.log("");
8151
+ console.log(colors.success(` \u2713 Logged in as Admin: ${admin.name}`));
8152
+ console.log(colors.muted(" Full access enabled. No expiration."));
8153
+ console.log("");
8154
+ return true;
8155
+ }
8156
+ if (BETA_CODES[codeUpper]) {
8157
+ const beta = BETA_CODES[codeUpper];
8158
+ const expiresAt = new Date(beta.expiresAt);
8159
+ if (expiresAt < /* @__PURE__ */ new Date()) {
8160
+ console.log(colors.error(" \u2717 This beta code has expired."));
8161
+ return false;
8162
+ }
8163
+ const auth2 = {
8164
+ accessToken: `beta_${codeUpper}_${Date.now()}`,
8165
+ refreshToken: "",
8166
+ user: {
8167
+ id: `beta_${codeUpper}`,
8168
+ email: beta.email,
8169
+ name: beta.name
8170
+ },
8171
+ license: {
8172
+ tier: "beta",
8173
+ features: ALL_FEATURES,
8174
+ expiresAt: beta.expiresAt,
8175
+ usage: { current: 0, limit: 999999 }
8176
+ },
8177
+ expiresAt: expiresAt.getTime(),
8178
+ authType: "beta"
8179
+ };
8180
+ this.saveAuth(auth2);
8181
+ console.log("");
8182
+ console.log(colors.success(` \u2713 Logged in as Beta Tester: ${beta.name}`));
8183
+ console.log(colors.muted(` Full access until ${beta.expiresAt}`));
8184
+ console.log("");
8185
+ return true;
8186
+ }
8187
+ console.log(colors.error(" \u2717 Invalid code. Please check and try again."));
8188
+ return false;
8189
+ }
8190
+ // ============================================================================
8191
+ // LOGIN WITH API KEY ONLY (No account needed)
8192
+ // ============================================================================
8193
+ async loginWithApiKey() {
8194
+ console.log("");
8195
+ console.log(colors.secondary(" Using API key only mode."));
8196
+ console.log(colors.muted(" You can use CB without an account."));
8197
+ console.log(colors.muted(" Some features may be limited."));
8198
+ console.log("");
8199
+ const apiKey = process.env.ANTHROPIC_API_KEY;
8200
+ if (!apiKey) {
8201
+ console.log(colors.warning(" \u26A0 No ANTHROPIC_API_KEY found in environment."));
8202
+ console.log(colors.muted(" Set it with: export ANTHROPIC_API_KEY=your_key"));
8203
+ console.log("");
8204
+ const enterKey = await p5.confirm({
8205
+ message: "Would you like to enter your API key now?",
8206
+ initialValue: true
8207
+ });
8208
+ if (enterKey && !p5.isCancel(enterKey)) {
8209
+ const key = await p5.text({
8210
+ message: "Anthropic API Key:",
8211
+ placeholder: "sk-ant-..."
8212
+ });
8213
+ if (p5.isCancel(key) || !key) {
8214
+ return false;
8215
+ }
8216
+ AUTH_STORE.set("anthropicApiKey", key);
8217
+ console.log(colors.success(" \u2713 API key saved."));
8218
+ }
8219
+ }
8220
+ const auth2 = {
8221
+ accessToken: `apikey_${Date.now()}`,
8222
+ refreshToken: "",
8223
+ user: {
8224
+ id: "apikey_user",
8225
+ email: "apikey@local",
8226
+ name: "API Key User"
8227
+ },
8228
+ license: {
8229
+ tier: "free",
8230
+ // Free tier features only
8231
+ features: ["basic_build", "memory", "patterns"],
8232
+ expiresAt: null,
8233
+ usage: { current: 0, limit: 50 }
8234
+ },
8235
+ expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1e3,
8236
+ // 30 days
8237
+ authType: "apikey"
8238
+ };
8239
+ this.saveAuth(auth2);
8240
+ console.log("");
8241
+ console.log(colors.success(" \u2713 Using API key only mode."));
8242
+ console.log(colors.muted(" Free tier features enabled."));
8243
+ console.log(colors.muted(' Run "cb login" anytime to upgrade.'));
8244
+ console.log("");
8245
+ return true;
8246
+ }
8247
+ // ============================================================================
8248
+ // LOGIN WITH BROWSER (Original device flow)
8249
+ // ============================================================================
8250
+ async loginWithBrowser() {
8074
8251
  try {
8075
8252
  const deviceCode = await this.requestDeviceCode();
8076
8253
  if (!deviceCode) {
@@ -8099,6 +8276,15 @@ var Auth = class _Auth {
8099
8276
  console.log(colors.error(" Authentication failed or timed out."));
8100
8277
  return false;
8101
8278
  }
8279
+ if (WHITELISTED_EMAILS.includes(auth2.user.email)) {
8280
+ auth2.license = {
8281
+ tier: "admin",
8282
+ features: ALL_FEATURES,
8283
+ expiresAt: null,
8284
+ usage: { current: 0, limit: 999999 }
8285
+ };
8286
+ auth2.authType = "whitelist";
8287
+ }
8102
8288
  this.saveAuth(auth2);
8103
8289
  console.log("");
8104
8290
  console.log(colors.success(` \u2713 Logged in as ${auth2.user.email}`));
@@ -8121,6 +8307,13 @@ var Auth = class _Auth {
8121
8307
  console.log(colors.success(" \u2713 Logged out successfully"));
8122
8308
  }
8123
8309
  // ============================================================================
8310
+ // IS LOGGED IN - Quick check
8311
+ // ============================================================================
8312
+ isLoggedIn() {
8313
+ const auth2 = this.getAuth();
8314
+ return auth2 !== null && !this.isExpired(auth2);
8315
+ }
8316
+ // ============================================================================
8124
8317
  // WHO AM I
8125
8318
  // ============================================================================
8126
8319
  async whoami() {
@@ -8132,16 +8325,26 @@ var Auth = class _Auth {
8132
8325
  console.log("");
8133
8326
  return;
8134
8327
  }
8135
- const freshLicense = await this.verifyLicense();
8136
- if (freshLicense) {
8137
- auth2.license = freshLicense;
8138
- this.saveAuth(auth2);
8328
+ if (auth2.authType === "device") {
8329
+ const freshLicense = await this.verifyLicense();
8330
+ if (freshLicense) {
8331
+ auth2.license = freshLicense;
8332
+ this.saveAuth(auth2);
8333
+ }
8139
8334
  }
8140
8335
  console.log("");
8141
8336
  console.log(colors.white(" \u{1F464} CodeBakers Account"));
8142
8337
  console.log("");
8143
8338
  console.log(colors.secondary(` Email: ${auth2.user.email}`));
8144
8339
  console.log(colors.secondary(` Name: ${auth2.user.name}`));
8340
+ const authTypeLabels = {
8341
+ admin: "\u{1F511} Admin Access",
8342
+ beta: "\u{1F9EA} Beta Tester",
8343
+ apikey: "\u{1F527} API Key Only",
8344
+ whitelist: "\u2B50 Whitelisted",
8345
+ device: "\u{1F310} Standard"
8346
+ };
8347
+ console.log(colors.secondary(` Type: ${authTypeLabels[auth2.authType || "device"] || "Standard"}`));
8145
8348
  console.log("");
8146
8349
  console.log(colors.white(" \u{1F4C4} License"));
8147
8350
  console.log(colors.secondary(` Tier: ${auth2.license.tier.toUpperCase()}`));
@@ -8157,7 +8360,7 @@ var Auth = class _Auth {
8157
8360
  for (const feature of auth2.license.features) {
8158
8361
  console.log(colors.success(` \u2713 ${this.formatFeatureName(feature)}`));
8159
8362
  }
8160
- if (auth2.license.usage) {
8363
+ if (auth2.license.usage && auth2.authType !== "admin") {
8161
8364
  console.log("");
8162
8365
  console.log(colors.white(" \u{1F4CA} Usage This Month"));
8163
8366
  const pct = Math.round(auth2.license.usage.current / auth2.license.usage.limit * 100);
@@ -8660,7 +8863,7 @@ ${issues.map((i) => ` \u2022 ${i}`).join("\n")}` : "\n\nEverything looks good!"
8660
8863
  /^(ugh|argh|damn|shit|fuck)/i
8661
8864
  // Frustration words
8662
8865
  ];
8663
- return frustrationPatterns.some((p7) => p7.test(input));
8866
+ return frustrationPatterns.some((p9) => p9.test(input));
8664
8867
  }
8665
8868
  // ============================================================================
8666
8869
  // RATE LIMITING (Don't be annoying)
@@ -8922,8 +9125,8 @@ ${chunk.content.slice(0, 2e3)}`
8922
9125
  chunk.embedding = this.simpleEmbed(chunk.content + " " + chunk.summary);
8923
9126
  }
8924
9127
  }
8925
- simpleEmbed(text3) {
8926
- const words = text3.toLowerCase().split(/\W+/).filter((w) => w.length > 2);
9128
+ simpleEmbed(text6) {
9129
+ const words = text6.toLowerCase().split(/\W+/).filter((w) => w.length > 2);
8927
9130
  const embedding = new Array(256).fill(0);
8928
9131
  for (const word of words) {
8929
9132
  const hash = this.hashString(word);
@@ -9268,8 +9471,8 @@ ${content.slice(0, 3e3)}`
9268
9471
  for (const feature of commonFeatures) {
9269
9472
  if (!features.has(feature)) {
9270
9473
  const relatedFiles = [...files.entries()].filter(
9271
- ([path17, summary]) => path17.toLowerCase().includes(feature) || summary.summary.toLowerCase().includes(feature)
9272
- ).map(([path17]) => path17);
9474
+ ([path19, summary]) => path19.toLowerCase().includes(feature) || summary.summary.toLowerCase().includes(feature)
9475
+ ).map(([path19]) => path19);
9273
9476
  if (relatedFiles.length > 0) {
9274
9477
  features.set(feature, {
9275
9478
  name: feature,
@@ -9384,7 +9587,7 @@ ${featureList}`
9384
9587
  "Redux": ["@reduxjs/toolkit", "redux"]
9385
9588
  };
9386
9589
  for (const [name, packages] of Object.entries(categories)) {
9387
- if (packages.some((p7) => deps.has(p7))) {
9590
+ if (packages.some((p9) => deps.has(p9))) {
9388
9591
  stack.push(name);
9389
9592
  }
9390
9593
  }
@@ -9430,8 +9633,8 @@ ${featureList}`
9430
9633
  }
9431
9634
  }
9432
9635
  const relevantFiles = [...this.index.files.entries()].filter(
9433
- ([path17, summary]) => queryLower.split(" ").some(
9434
- (word) => word.length > 2 && (path17.toLowerCase().includes(word) || summary.summary.toLowerCase().includes(word))
9636
+ ([path19, summary]) => queryLower.split(" ").some(
9637
+ (word) => word.length > 2 && (path19.toLowerCase().includes(word) || summary.summary.toLowerCase().includes(word))
9435
9638
  )
9436
9639
  ).slice(0, 10);
9437
9640
  if (relevantFiles.length > 0) {
@@ -9516,10 +9719,411 @@ ${featureList}`
9516
9719
  }
9517
9720
  };
9518
9721
 
9519
- // src/services/git.ts
9520
- import simpleGit from "simple-git";
9722
+ // src/core/onboarding.ts
9723
+ import * as p6 from "@clack/prompts";
9521
9724
  import fs16 from "fs-extra";
9522
9725
  import path16 from "path";
9726
+ function showWelcomeScreen() {
9727
+ console.clear();
9728
+ console.log("");
9729
+ console.log(colors.primary(" \u250C\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\u2510"));
9730
+ console.log(colors.primary(" \u2502 \u2502"));
9731
+ console.log(colors.primary(" \u2502") + colors.white(" Welcome to CodeBakers! ") + colors.primary("\u2502"));
9732
+ console.log(colors.primary(" \u2502") + colors.muted(" AI Dev Team That Follows The Rules ") + colors.primary("\u2502"));
9733
+ console.log(colors.primary(" \u2502 \u2502"));
9734
+ console.log(colors.primary(" \u2514\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\u2518"));
9735
+ console.log("");
9736
+ console.log(colors.white(" Let's get you set up in 2 quick steps:"));
9737
+ console.log("");
9738
+ console.log(colors.muted(" 1. Connect your account (or use API key)"));
9739
+ console.log(colors.muted(" 2. Initialize your project"));
9740
+ console.log("");
9741
+ console.log(colors.dim(" Press ESC at any time to go back"));
9742
+ console.log("");
9743
+ }
9744
+ async function showAuthScreen() {
9745
+ console.clear();
9746
+ console.log("");
9747
+ console.log(colors.white(" \u250C\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\u2510"));
9748
+ console.log(colors.white(" \u2502") + colors.primary(" Step 1 of 2: ") + colors.white("Connect Your Account ") + colors.white("\u2502"));
9749
+ console.log(colors.white(" \u2514\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\u2518"));
9750
+ console.log("");
9751
+ const choice = await p6.select({
9752
+ message: "How would you like to connect?",
9753
+ options: [
9754
+ {
9755
+ value: "browser",
9756
+ label: "\u{1F310} Login with browser",
9757
+ hint: "Google or GitHub - recommended"
9758
+ },
9759
+ {
9760
+ value: "code",
9761
+ label: "\u{1F511} Enter admin/beta code",
9762
+ hint: "If you have a special code"
9763
+ },
9764
+ {
9765
+ value: "apikey",
9766
+ label: "\u{1F527} Use my own API key",
9767
+ hint: "No account needed, limited features"
9768
+ },
9769
+ {
9770
+ value: "skip",
9771
+ label: "\u23ED\uFE0F Skip for now",
9772
+ hint: "You can login later with /login"
9773
+ }
9774
+ ]
9775
+ });
9776
+ if (p6.isCancel(choice)) {
9777
+ return "back";
9778
+ }
9779
+ return choice;
9780
+ }
9781
+ async function showApiKeyScreen(config) {
9782
+ console.clear();
9783
+ console.log("");
9784
+ console.log(colors.white(" \u250C\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\u2510"));
9785
+ console.log(colors.white(" \u2502") + colors.primary(" Step 1 of 2: ") + colors.white("Enter Your API Key ") + colors.white("\u2502"));
9786
+ console.log(colors.white(" \u2514\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\u2518"));
9787
+ console.log("");
9788
+ console.log(colors.muted(" Get your API key from: https://console.anthropic.com/"));
9789
+ console.log("");
9790
+ const apiKey = await p6.text({
9791
+ message: "Anthropic API Key:",
9792
+ placeholder: "sk-ant-api...",
9793
+ validate: (value) => {
9794
+ if (!value) return "API key is required";
9795
+ if (!value.startsWith("sk-ant-")) return "API key should start with sk-ant-";
9796
+ return void 0;
9797
+ }
9798
+ });
9799
+ if (p6.isCancel(apiKey)) {
9800
+ return "back";
9801
+ }
9802
+ config.setAnthropicKey(apiKey);
9803
+ console.log("");
9804
+ console.log(colors.success(" \u2713 API key saved"));
9805
+ await sleep(500);
9806
+ return "done";
9807
+ }
9808
+ async function showProjectScreen(memory) {
9809
+ console.clear();
9810
+ console.log("");
9811
+ console.log(colors.white(" \u250C\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\u2510"));
9812
+ console.log(colors.white(" \u2502") + colors.primary(" Step 2 of 2: ") + colors.white("Initialize Your Project ") + colors.white("\u2502"));
9813
+ console.log(colors.white(" \u2514\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\u2518"));
9814
+ console.log("");
9815
+ const cwd = process.cwd();
9816
+ const dirName = path16.basename(cwd);
9817
+ const hasPackageJson = await fs16.pathExists(path16.join(cwd, "package.json"));
9818
+ if (hasPackageJson) {
9819
+ console.log(colors.muted(` \u{1F4C1} Detected project: ${dirName}`));
9820
+ console.log("");
9821
+ } else {
9822
+ console.log(colors.muted(` \u{1F4C1} Current folder: ${dirName}`));
9823
+ console.log("");
9824
+ }
9825
+ const action = await p6.select({
9826
+ message: "What would you like to do?",
9827
+ options: [
9828
+ {
9829
+ value: "init",
9830
+ label: "\u2728 Initialize this folder as a CB project",
9831
+ hint: "CB will remember context about this project"
9832
+ },
9833
+ {
9834
+ value: "skip",
9835
+ label: "\u23ED\uFE0F Skip for now",
9836
+ hint: "You can initialize later with /init"
9837
+ }
9838
+ ]
9839
+ });
9840
+ if (p6.isCancel(action)) {
9841
+ return "back";
9842
+ }
9843
+ if (action === "skip") {
9844
+ return "skip";
9845
+ }
9846
+ const projectName = await p6.text({
9847
+ message: "Project name:",
9848
+ initialValue: dirName,
9849
+ placeholder: dirName
9850
+ });
9851
+ if (p6.isCancel(projectName)) {
9852
+ return "back";
9853
+ }
9854
+ const description = await p6.text({
9855
+ message: "Brief description (optional):",
9856
+ placeholder: "A web app that..."
9857
+ });
9858
+ if (p6.isCancel(description)) {
9859
+ return "back";
9860
+ }
9861
+ await memory.init();
9862
+ memory.setIdentity(projectName, description || "");
9863
+ console.log("");
9864
+ console.log(colors.success(` \u2713 Project "${projectName}" initialized`));
9865
+ console.log(colors.muted(" CB will now remember context about this project"));
9866
+ await sleep(500);
9867
+ return "done";
9868
+ }
9869
+ function showCompleteScreen() {
9870
+ console.clear();
9871
+ console.log("");
9872
+ console.log(colors.primary(" \u250C\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\u2510"));
9873
+ console.log(colors.primary(" \u2502") + colors.white(" ") + colors.primary("\u2502"));
9874
+ console.log(colors.primary(" \u2502") + colors.success(" \u2713 You're all set! ") + colors.primary("\u2502"));
9875
+ console.log(colors.primary(" \u2502") + colors.white(" ") + colors.primary("\u2502"));
9876
+ console.log(colors.primary(" \u2514\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\u2518"));
9877
+ console.log("");
9878
+ console.log(colors.white(" Quick start:"));
9879
+ console.log("");
9880
+ console.log(colors.muted(" Just type what you want:"));
9881
+ console.log(colors.white(' "Add a login page"'));
9882
+ console.log(colors.white(' "Fix the bug in navbar"'));
9883
+ console.log(colors.white(' "Create an API for users"'));
9884
+ console.log("");
9885
+ console.log(colors.muted(" Or use commands:"));
9886
+ console.log(colors.dim(" /help ") + colors.muted("Show all commands"));
9887
+ console.log(colors.dim(" /audit ") + colors.muted("Check code quality"));
9888
+ console.log(colors.dim(" /spec ") + colors.muted("Generate a product spec"));
9889
+ console.log("");
9890
+ }
9891
+ async function runOnboarding(config, memory) {
9892
+ let currentStep = "welcome";
9893
+ const hasApiKey = config.isConfigured();
9894
+ const hasAuth = auth.isLoggedIn();
9895
+ const hasProject = memory.getIdentity().name !== "";
9896
+ if (hasAuth || hasApiKey) {
9897
+ if (hasProject) {
9898
+ return true;
9899
+ }
9900
+ currentStep = "project";
9901
+ }
9902
+ while (true) {
9903
+ switch (currentStep) {
9904
+ case "welcome": {
9905
+ showWelcomeScreen();
9906
+ const proceed = await p6.confirm({
9907
+ message: "Ready to begin?",
9908
+ initialValue: true
9909
+ });
9910
+ if (p6.isCancel(proceed) || !proceed) {
9911
+ return false;
9912
+ }
9913
+ currentStep = "auth";
9914
+ break;
9915
+ }
9916
+ case "auth": {
9917
+ const authChoice = await showAuthScreen();
9918
+ if (authChoice === "back") {
9919
+ currentStep = "welcome";
9920
+ break;
9921
+ }
9922
+ if (authChoice === "skip") {
9923
+ if (!config.isConfigured()) {
9924
+ console.log("");
9925
+ console.log(colors.warning(" \u26A0 You need either an account or API key to use CB"));
9926
+ console.log("");
9927
+ await sleep(1500);
9928
+ break;
9929
+ }
9930
+ currentStep = "project";
9931
+ break;
9932
+ }
9933
+ if (authChoice === "apikey") {
9934
+ currentStep = "api_key";
9935
+ break;
9936
+ }
9937
+ if (authChoice === "browser" || authChoice === "code") {
9938
+ const success = authChoice === "browser" ? await auth.loginWithBrowser() : await auth.loginWithCode();
9939
+ if (success) {
9940
+ currentStep = "project";
9941
+ }
9942
+ break;
9943
+ }
9944
+ break;
9945
+ }
9946
+ case "api_key": {
9947
+ const result = await showApiKeyScreen(config);
9948
+ if (result === "back") {
9949
+ currentStep = "auth";
9950
+ break;
9951
+ }
9952
+ currentStep = "project";
9953
+ break;
9954
+ }
9955
+ case "project": {
9956
+ const result = await showProjectScreen(memory);
9957
+ if (result === "back") {
9958
+ if (!config.isConfigured() && !auth.isLoggedIn()) {
9959
+ currentStep = "auth";
9960
+ }
9961
+ break;
9962
+ }
9963
+ currentStep = "complete";
9964
+ break;
9965
+ }
9966
+ case "complete": {
9967
+ showCompleteScreen();
9968
+ const ready = await p6.confirm({
9969
+ message: "Start using CodeBakers?",
9970
+ initialValue: true
9971
+ });
9972
+ if (p6.isCancel(ready)) {
9973
+ currentStep = "project";
9974
+ break;
9975
+ }
9976
+ return true;
9977
+ }
9978
+ }
9979
+ }
9980
+ }
9981
+ function needsOnboarding(config, memory) {
9982
+ const hasApiKey = config.isConfigured();
9983
+ const hasAuth = auth.isLoggedIn();
9984
+ return !hasApiKey && !hasAuth;
9985
+ }
9986
+ function sleep(ms) {
9987
+ return new Promise((resolve) => setTimeout(resolve, ms));
9988
+ }
9989
+
9990
+ // src/utils/folder-picker.ts
9991
+ import { execSync } from "child_process";
9992
+ import path17 from "path";
9993
+ import os2 from "os";
9994
+ import * as p7 from "@clack/prompts";
9995
+ async function pickFolder(message = "Select a folder") {
9996
+ const platform = os2.platform();
9997
+ try {
9998
+ const folder = await openNativePicker(platform, message);
9999
+ if (folder) {
10000
+ return folder;
10001
+ }
10002
+ } catch (e) {
10003
+ }
10004
+ return manualFolderEntry(message);
10005
+ }
10006
+ async function openNativePicker(platform, title) {
10007
+ return new Promise((resolve) => {
10008
+ let command;
10009
+ let args;
10010
+ if (platform === "win32") {
10011
+ const psScript = `
10012
+ Add-Type -AssemblyName System.Windows.Forms
10013
+ $dialog = New-Object System.Windows.Forms.FolderBrowserDialog
10014
+ $dialog.Description = "${title}"
10015
+ $dialog.ShowNewFolderButton = $true
10016
+ if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
10017
+ Write-Output $dialog.SelectedPath
10018
+ }
10019
+ `;
10020
+ try {
10021
+ const result = execSync(`powershell -Command "${psScript.replace(/\n/g, " ")}"`, {
10022
+ encoding: "utf-8",
10023
+ timeout: 6e4,
10024
+ // 60 second timeout
10025
+ windowsHide: true
10026
+ });
10027
+ const folder = result.trim();
10028
+ resolve(folder || null);
10029
+ } catch {
10030
+ resolve(null);
10031
+ }
10032
+ return;
10033
+ }
10034
+ if (platform === "darwin") {
10035
+ const script = `
10036
+ tell application "System Events"
10037
+ activate
10038
+ set theFolder to choose folder with prompt "${title}"
10039
+ return POSIX path of theFolder
10040
+ end tell
10041
+ `;
10042
+ try {
10043
+ const result = execSync(`osascript -e '${script.replace(/'/g, `'"'"'`)}'`, {
10044
+ encoding: "utf-8",
10045
+ timeout: 6e4
10046
+ });
10047
+ const folder = result.trim();
10048
+ resolve(folder || null);
10049
+ } catch {
10050
+ resolve(null);
10051
+ }
10052
+ return;
10053
+ }
10054
+ if (platform === "linux") {
10055
+ try {
10056
+ const result = execSync(`zenity --file-selection --directory --title="${title}" 2>/dev/null`, {
10057
+ encoding: "utf-8",
10058
+ timeout: 6e4
10059
+ });
10060
+ resolve(result.trim() || null);
10061
+ return;
10062
+ } catch {
10063
+ try {
10064
+ const result = execSync(`kdialog --getexistingdirectory ~ --title "${title}" 2>/dev/null`, {
10065
+ encoding: "utf-8",
10066
+ timeout: 6e4
10067
+ });
10068
+ resolve(result.trim() || null);
10069
+ return;
10070
+ } catch {
10071
+ resolve(null);
10072
+ }
10073
+ }
10074
+ return;
10075
+ }
10076
+ resolve(null);
10077
+ });
10078
+ }
10079
+ async function manualFolderEntry(message) {
10080
+ console.log("");
10081
+ console.log(colors.muted(" \u{1F4A1} Tip: You can drag & drop a folder into the terminal"));
10082
+ console.log("");
10083
+ const homeDir = os2.homedir();
10084
+ const commonPaths = [
10085
+ { label: "\u{1F4C1} Current folder", value: process.cwd() },
10086
+ { label: "\u{1F3E0} Home", value: homeDir },
10087
+ { label: "\u{1F4C2} Desktop", value: path17.join(homeDir, "Desktop") },
10088
+ { label: "\u{1F4C2} Documents", value: path17.join(homeDir, "Documents") },
10089
+ { label: "\u{1F4C2} Downloads", value: path17.join(homeDir, "Downloads") },
10090
+ { label: "\u270F\uFE0F Type custom path", value: "__custom__" }
10091
+ ];
10092
+ const choice = await p7.select({
10093
+ message,
10094
+ options: commonPaths.map((p9) => ({
10095
+ value: p9.value,
10096
+ label: p9.label,
10097
+ hint: p9.value !== "__custom__" ? p9.value : void 0
10098
+ }))
10099
+ });
10100
+ if (p7.isCancel(choice)) {
10101
+ return null;
10102
+ }
10103
+ if (choice === "__custom__") {
10104
+ const customPath = await p7.text({
10105
+ message: "Enter folder path:",
10106
+ placeholder: "/path/to/folder",
10107
+ validate: (value) => {
10108
+ if (!value) return "Path is required";
10109
+ return void 0;
10110
+ }
10111
+ });
10112
+ if (p7.isCancel(customPath)) {
10113
+ return null;
10114
+ }
10115
+ let cleanPath = customPath.trim();
10116
+ cleanPath = cleanPath.replace(/^["']|["']$/g, "");
10117
+ cleanPath = cleanPath.replace(/\\ /g, " ");
10118
+ return cleanPath;
10119
+ }
10120
+ return choice;
10121
+ }
10122
+
10123
+ // src/services/git.ts
10124
+ import simpleGit from "simple-git";
10125
+ import fs17 from "fs-extra";
10126
+ import path18 from "path";
9523
10127
  var GitService = class {
9524
10128
  git;
9525
10129
  projectPath;
@@ -9528,7 +10132,7 @@ var GitService = class {
9528
10132
  this.git = simpleGit(projectPath);
9529
10133
  }
9530
10134
  async isRepo() {
9531
- return fs16.pathExists(path16.join(this.projectPath, ".git"));
10135
+ return fs17.pathExists(path18.join(this.projectPath, ".git"));
9532
10136
  }
9533
10137
  async init() {
9534
10138
  await this.git.init();
@@ -9639,7 +10243,7 @@ var VercelService = class {
9639
10243
  };
9640
10244
 
9641
10245
  // src/index.ts
9642
- var VERSION = "1.0.0";
10246
+ var VERSION = "3.3.0";
9643
10247
  async function main() {
9644
10248
  const config = new Config();
9645
10249
  const args = process.argv.slice(2);
@@ -9655,22 +10259,36 @@ async function main() {
9655
10259
  await runSetup(config);
9656
10260
  return;
9657
10261
  }
9658
- showHeader();
9659
- if (!config.isConfigured()) {
9660
- showWarning("Not configured yet. Let's set up your API key.");
9661
- await runSetup(config);
9662
- if (!config.isConfigured()) {
9663
- showError("Setup incomplete. Run `cb setup` to configure.");
9664
- return;
9665
- }
10262
+ if (args[0] === "login") {
10263
+ await auth.login();
10264
+ return;
9666
10265
  }
9667
10266
  const memory = new Memory();
9668
10267
  await memory.init();
10268
+ if (needsOnboarding(config, memory)) {
10269
+ const completed = await runOnboarding(config, memory);
10270
+ if (!completed) {
10271
+ console.log("");
10272
+ console.log(colors.muted(" Run `cb` again when you're ready."));
10273
+ console.log("");
10274
+ return;
10275
+ }
10276
+ }
10277
+ showHeader();
10278
+ console.log(colors.muted(` v${VERSION}`));
10279
+ console.log("");
9669
10280
  const scanner = new ProjectScanner();
9670
10281
  const structure = await scanner.detectProject();
9671
10282
  const editor = new FileEditor();
9672
10283
  const git = new GitService();
9673
- showProjectStatus(structure.name, structure.framework);
10284
+ const identity = memory.getIdentity();
10285
+ if (identity.name) {
10286
+ console.log(colors.white(` \u{1F4C1} ${identity.name}`) + colors.muted(` (${structure.framework || "Project"})`));
10287
+ } else {
10288
+ console.log(colors.white(` \u{1F4C1} ${structure.name}`) + colors.muted(` (${structure.framework || "Unknown"})`));
10289
+ console.log(colors.dim(" Run /init to enable project memory"));
10290
+ }
10291
+ console.log("");
9674
10292
  let ai;
9675
10293
  try {
9676
10294
  ai = new AIEngine(config, memory, scanner);
@@ -9682,27 +10300,18 @@ async function main() {
9682
10300
  const modeManager = getModeManager();
9683
10301
  const suggestions = new SmartSuggestions(memory, scanner);
9684
10302
  const proactive = new ProactiveAssistant(memory, scanner, config);
9685
- const startupAction = await proactive.onStartup();
9686
- if (startupAction) {
9687
- console.log(proactive.formatAction(startupAction));
9688
- proactive.markSuggestionShown();
9689
- }
9690
- const identity = memory.getIdentity();
9691
- if (!identity.name) {
9692
- showInfo('Project not initialized. Say "initialize project" or use /init');
9693
- }
9694
- showWelcome();
9695
- console.log(colors.muted(" Modes: " + modeManager.getStatusBar()));
10303
+ console.log(colors.muted(" Just tell me what you need:"));
10304
+ console.log(colors.dim(' "Add a login page" \u2022 "Fix the navbar" \u2022 /help'));
9696
10305
  console.log("");
9697
10306
  let lastAction;
9698
10307
  let running = true;
9699
10308
  while (running) {
9700
10309
  const modePrompt = modeManager.getPrompt();
9701
- const input = await p6.text({
10310
+ const input = await p8.text({
9702
10311
  message: modePrompt,
9703
10312
  placeholder: "What would you like to build? (Shift+Tab to change mode)"
9704
10313
  });
9705
- if (p6.isCancel(input)) {
10314
+ if (p8.isCancel(input)) {
9706
10315
  running = false;
9707
10316
  showInfo("Goodbye! \u{1F44B}");
9708
10317
  break;
@@ -9760,8 +10369,8 @@ async function main() {
9760
10369
  showSuccess(`Decision recorded: ${result.params.content}`);
9761
10370
  } else {
9762
10371
  showInfo("What decision would you like to record?");
9763
- const decision = await p6.text({ message: "Decision:" });
9764
- if (!p6.isCancel(decision) && decision) {
10372
+ const decision = await p8.text({ message: "Decision:" });
10373
+ if (!p8.isCancel(decision) && decision) {
9765
10374
  memory.addDecision(decision);
9766
10375
  await memory.save();
9767
10376
  showSuccess(`Decision recorded: ${decision}`);
@@ -9775,8 +10384,8 @@ async function main() {
9775
10384
  showSuccess(`Rule added: ${result.params.content}`);
9776
10385
  } else {
9777
10386
  showInfo("What rule would you like to add?");
9778
- const rule = await p6.text({ message: "Rule:" });
9779
- if (!p6.isCancel(rule) && rule) {
10387
+ const rule = await p8.text({ message: "Rule:" });
10388
+ if (!p8.isCancel(rule) && rule) {
9780
10389
  memory.addCustomRule(rule);
9781
10390
  await memory.save();
9782
10391
  showSuccess(`Rule added: ${rule}`);
@@ -9841,17 +10450,20 @@ async function main() {
9841
10450
  case "index":
9842
10451
  await handleIndex(ctx);
9843
10452
  break;
10453
+ case "folder":
10454
+ await handleFolderChange();
10455
+ break;
9844
10456
  case "generate":
9845
10457
  default:
9846
10458
  const inputHandler = new InputHandler(config, memory, scanner);
9847
10459
  const detected = await inputHandler.detectAndProcess(cmd);
9848
10460
  if (detected.type !== "text") {
9849
10461
  console.log(inputHandler.formatDetection(detected));
9850
- const proceed = await p6.confirm({
10462
+ const proceed = await p8.confirm({
9851
10463
  message: `Process this ${detected.type}?`,
9852
10464
  initialValue: true
9853
10465
  });
9854
- if (!proceed || p6.isCancel(proceed)) break;
10466
+ if (!proceed || p8.isCancel(proceed)) break;
9855
10467
  const enhancedCmd = inputHandler.enhancePrompt(detected, cmd);
9856
10468
  await handleGeneration(enhancedCmd, ctx);
9857
10469
  break;
@@ -9870,11 +10482,11 @@ async function main() {
9870
10482
  console.log(colors.secondary(" \u{1F4A1} This looks like a complex request."));
9871
10483
  console.log(colors.muted(" Parallel build could be ~3x faster."));
9872
10484
  console.log("");
9873
- const useParallel = await p6.confirm({
10485
+ const useParallel = await p8.confirm({
9874
10486
  message: "Use parallel build with 3 agents?",
9875
10487
  initialValue: true
9876
10488
  });
9877
- if (useParallel && !p6.isCancel(useParallel)) {
10489
+ if (useParallel && !p8.isCancel(useParallel)) {
9878
10490
  await handleParallelBuild(cmd, ctx);
9879
10491
  break;
9880
10492
  }
@@ -9886,11 +10498,11 @@ async function main() {
9886
10498
  console.log(colors.secondary(` \u{1F4A1} I recommend the "${suggestedTemplate.name}" template.`));
9887
10499
  console.log(colors.muted(` ${suggestedTemplate.description}`));
9888
10500
  console.log("");
9889
- const useTemplate = await p6.confirm({
10501
+ const useTemplate = await p8.confirm({
9890
10502
  message: "Install this template first?",
9891
10503
  initialValue: true
9892
10504
  });
9893
- if (useTemplate && !p6.isCancel(useTemplate)) {
10505
+ if (useTemplate && !p8.isCancel(useTemplate)) {
9894
10506
  await handleInstallTemplate(suggestedTemplate.id, ctx);
9895
10507
  showSuccess("Template installed! Now customizing...");
9896
10508
  }
@@ -10029,7 +10641,7 @@ async function handleCreate(name, ctx) {
10029
10641
  const { config } = ctx;
10030
10642
  let projectName = name;
10031
10643
  if (!projectName) {
10032
- const nameInput = await p6.text({
10644
+ const nameInput = await p8.text({
10033
10645
  message: "Project name:",
10034
10646
  placeholder: "my-awesome-app",
10035
10647
  validate: (value) => {
@@ -10037,23 +10649,23 @@ async function handleCreate(name, ctx) {
10037
10649
  if (!/^[a-z0-9-]+$/.test(value)) return "Use lowercase letters, numbers, and hyphens only";
10038
10650
  }
10039
10651
  });
10040
- if (p6.isCancel(nameInput)) return;
10652
+ if (p8.isCancel(nameInput)) return;
10041
10653
  projectName = nameInput;
10042
10654
  }
10043
10655
  console.log("");
10044
- const github = await p6.confirm({
10656
+ const github = await p8.confirm({
10045
10657
  message: "Create GitHub repository?",
10046
10658
  initialValue: !!config.getGithubToken()
10047
10659
  });
10048
- const supabase = await p6.confirm({
10660
+ const supabase = await p8.confirm({
10049
10661
  message: "Create Supabase project?",
10050
10662
  initialValue: !!config.getSupabaseToken()
10051
10663
  });
10052
- const vercel = await p6.confirm({
10664
+ const vercel = await p8.confirm({
10053
10665
  message: "Deploy to Vercel?",
10054
10666
  initialValue: !!config.getVercelToken()
10055
10667
  });
10056
- if (p6.isCancel(github) || p6.isCancel(supabase) || p6.isCancel(vercel)) return;
10668
+ if (p8.isCancel(github) || p8.isCancel(supabase) || p8.isCancel(vercel)) return;
10057
10669
  const creator = new ProjectCreator(config);
10058
10670
  const spinner = ora3("Creating project...").start();
10059
10671
  const result = await creator.create(
@@ -10114,14 +10726,14 @@ async function handleInstallTemplate(templateId, ctx) {
10114
10726
  let id = templateId;
10115
10727
  if (!id) {
10116
10728
  const templates = templateManager.listTemplates();
10117
- const choice = await p6.select({
10729
+ const choice = await p8.select({
10118
10730
  message: "Choose a template:",
10119
10731
  options: templates.map((t) => ({
10120
10732
  value: t.id,
10121
10733
  label: `${t.name} - ${t.description}`
10122
10734
  }))
10123
10735
  });
10124
- if (p6.isCancel(choice)) return;
10736
+ if (p8.isCancel(choice)) return;
10125
10737
  id = choice;
10126
10738
  }
10127
10739
  const spinner = ora3(`Installing ${id}...`).start();
@@ -10197,11 +10809,11 @@ async function handleParallelBuild(request, ctx) {
10197
10809
  console.log(colors.muted(` + ${change.path}`));
10198
10810
  }
10199
10811
  console.log("");
10200
- const apply = await p6.confirm({
10812
+ const apply = await p8.confirm({
10201
10813
  message: "Apply all files?",
10202
10814
  initialValue: true
10203
10815
  });
10204
- if (apply && !p6.isCancel(apply)) {
10816
+ if (apply && !p8.isCancel(apply)) {
10205
10817
  const applied = await editor.apply();
10206
10818
  showSuccess(`Applied ${applied.length} files`);
10207
10819
  for (const file of applied) {
@@ -10273,11 +10885,11 @@ async function handlePlanMode(request, ctx) {
10273
10885
  const plan = await planExecutor.createPlan(request);
10274
10886
  spinner.stop();
10275
10887
  console.log(planExecutor.formatPlan(plan));
10276
- const execute = await p6.confirm({
10888
+ const execute = await p8.confirm({
10277
10889
  message: "Execute this plan?",
10278
10890
  initialValue: true
10279
10891
  });
10280
- if (execute && !p6.isCancel(execute)) {
10892
+ if (execute && !p8.isCancel(execute)) {
10281
10893
  await handleGeneration(request, ctx);
10282
10894
  }
10283
10895
  } catch (error) {
@@ -10340,11 +10952,11 @@ async function handleTestGeneration(filePath, ctx) {
10340
10952
  const { config, scanner, editor } = ctx;
10341
10953
  const testGen = new TestGenerator(config, scanner);
10342
10954
  if (!filePath) {
10343
- const file = await p6.text({
10955
+ const file = await p8.text({
10344
10956
  message: "File to generate tests for:",
10345
10957
  placeholder: "src/components/Button.tsx"
10346
10958
  });
10347
- if (p6.isCancel(file) || !file) return;
10959
+ if (p8.isCancel(file) || !file) return;
10348
10960
  filePath = file;
10349
10961
  }
10350
10962
  const spinner = ora3(`Generating tests for ${filePath}...`).start();
@@ -10361,11 +10973,11 @@ async function handleTestGeneration(filePath, ctx) {
10361
10973
  console.log(colors.muted(" " + test.content.split("\n").slice(0, 10).join("\n ")));
10362
10974
  console.log(colors.muted(" ..."));
10363
10975
  console.log("");
10364
- const save = await p6.confirm({
10976
+ const save = await p8.confirm({
10365
10977
  message: `Save to ${test.testPath}?`,
10366
10978
  initialValue: true
10367
10979
  });
10368
- if (save && !p6.isCancel(save)) {
10980
+ if (save && !p8.isCancel(save)) {
10369
10981
  await testGen.writeTest(test);
10370
10982
  showSuccess(`Test saved to ${test.testPath}`);
10371
10983
  }
@@ -10403,11 +11015,11 @@ async function handleLivePreview(ctx) {
10403
11015
  const { scanner } = ctx;
10404
11016
  const preview = new LivePreview(scanner);
10405
11017
  if (preview.isRunning()) {
10406
- const stop = await p6.confirm({
11018
+ const stop = await p8.confirm({
10407
11019
  message: "Preview is running. Stop it?",
10408
11020
  initialValue: false
10409
11021
  });
10410
- if (stop && !p6.isCancel(stop)) {
11022
+ if (stop && !p8.isCancel(stop)) {
10411
11023
  await preview.stop();
10412
11024
  showSuccess("Preview stopped");
10413
11025
  } else {
@@ -10437,11 +11049,11 @@ async function handleSpecGeneration(input, ctx) {
10437
11049
  const { config, memory, scanner, editor, ai } = ctx;
10438
11050
  let description = input.replace(/^\/spec\s*/i, "").replace(/^\/prd\s*/i, "").replace(/^\/plan\s*/i, "").trim();
10439
11051
  if (!description) {
10440
- const desc = await p6.text({
11052
+ const desc = await p8.text({
10441
11053
  message: "What do you want to build?",
10442
11054
  placeholder: "An Uber for dog walkers"
10443
11055
  });
10444
- if (p6.isCancel(desc) || !desc) return;
11056
+ if (p8.isCancel(desc) || !desc) return;
10445
11057
  description = desc;
10446
11058
  }
10447
11059
  const specGen = new SpecGenerator(config);
@@ -10452,11 +11064,11 @@ async function handleSpecGeneration(input, ctx) {
10452
11064
  return;
10453
11065
  }
10454
11066
  console.log(specGen.formatSpec(spec));
10455
- const buildNow = await p6.confirm({
11067
+ const buildNow = await p8.confirm({
10456
11068
  message: "Build from this spec?",
10457
11069
  initialValue: true
10458
11070
  });
10459
- if (buildNow && !p6.isCancel(buildNow)) {
11071
+ if (buildNow && !p8.isCancel(buildNow)) {
10460
11072
  const builder = new ProjectBuilder(config, memory, scanner, editor, ai);
10461
11073
  let cancelled = false;
10462
11074
  const checkCancelled = () => cancelled;
@@ -10598,7 +11210,7 @@ async function handleAudit(args, ctx) {
10598
11210
  const fixType = args?.includes("critical") ? "critical" : args?.includes("all") ? "all" : null;
10599
11211
  let issuesToFix = report.critical;
10600
11212
  if (!fixType) {
10601
- const choice = await p6.select({
11213
+ const choice = await p8.select({
10602
11214
  message: "What would you like to fix?",
10603
11215
  options: [
10604
11216
  { value: "critical", label: `Critical issues only (${report.critical.length})` },
@@ -10606,7 +11218,7 @@ async function handleAudit(args, ctx) {
10606
11218
  { value: "all", label: `Everything (${report.totalIssues})` }
10607
11219
  ]
10608
11220
  });
10609
- if (p6.isCancel(choice)) return;
11221
+ if (p8.isCancel(choice)) return;
10610
11222
  if (choice === "warnings") {
10611
11223
  issuesToFix = [...report.critical, ...report.warnings];
10612
11224
  } else if (choice === "all") {
@@ -10637,11 +11249,11 @@ async function handleAudit(args, ctx) {
10637
11249
  const files = result.changes.map((c) => c.file);
10638
11250
  await git.commitFiles(files, "fix: resolve codebase audit issues");
10639
11251
  console.log("");
10640
- const push = await p6.confirm({
11252
+ const push = await p8.confirm({
10641
11253
  message: "Push and create PR?",
10642
11254
  initialValue: true
10643
11255
  });
10644
- if (push && !p6.isCancel(push)) {
11256
+ if (push && !p8.isCancel(push)) {
10645
11257
  await git.push();
10646
11258
  const pr = await git.createPR(branchName, await git.getMainBranch(), "Fix: Codebase Audit Issues");
10647
11259
  if (pr?.url) {
@@ -10659,7 +11271,7 @@ async function handleAudit(args, ctx) {
10659
11271
  spinner.stop();
10660
11272
  const markdown = auditor.exportMarkdown(report);
10661
11273
  const reportPath = "AUDIT_REPORT.md";
10662
- await fs17.writeFile(reportPath, markdown);
11274
+ await fs18.writeFile(reportPath, markdown);
10663
11275
  console.log(auditor.formatReport(report));
10664
11276
  showSuccess(`Report saved to ${reportPath}`);
10665
11277
  break;
@@ -10754,21 +11366,44 @@ async function handleIndex(ctx) {
10754
11366
  showSuccess("Codebase indexed! Context retrieval is now smarter.");
10755
11367
  console.log(colors.muted(" Re-run /index after major changes to keep it updated."));
10756
11368
  }
11369
+ async function handleFolderChange() {
11370
+ console.log("");
11371
+ console.log(colors.white(" \u{1F4C1} Change Working Folder"));
11372
+ console.log("");
11373
+ const folder = await pickFolder("Select project folder");
11374
+ if (!folder) {
11375
+ console.log(colors.muted(" Cancelled"));
11376
+ return;
11377
+ }
11378
+ if (!await fs18.pathExists(folder)) {
11379
+ showError(`Folder not found: ${folder}`);
11380
+ return;
11381
+ }
11382
+ try {
11383
+ process.chdir(folder);
11384
+ console.log("");
11385
+ showSuccess(`Changed to: ${folder}`);
11386
+ console.log(colors.muted(" Restart CB to reload project context"));
11387
+ console.log("");
11388
+ } catch (error) {
11389
+ showError(`Cannot access folder: ${error instanceof Error ? error.message : "Unknown error"}`);
11390
+ }
11391
+ }
10757
11392
  async function initProject(ctx) {
10758
11393
  const { memory, scanner } = ctx;
10759
11394
  const structure = await scanner.detectProject();
10760
11395
  console.log("");
10761
- const name = await p6.text({
11396
+ const name = await p8.text({
10762
11397
  message: "Project name:",
10763
11398
  initialValue: structure.name
10764
11399
  });
10765
- if (p6.isCancel(name)) return;
10766
- const description = await p6.text({
11400
+ if (p8.isCancel(name)) return;
11401
+ const description = await p8.text({
10767
11402
  message: "Description:",
10768
11403
  placeholder: "A brief description of your project"
10769
11404
  });
10770
- if (p6.isCancel(description)) return;
10771
- const stack = await p6.text({
11405
+ if (p8.isCancel(description)) return;
11406
+ const stack = await p8.text({
10772
11407
  message: "Tech stack (comma-separated):",
10773
11408
  initialValue: [
10774
11409
  structure.framework,
@@ -10777,7 +11412,7 @@ async function initProject(ctx) {
10777
11412
  "Tailwind"
10778
11413
  ].filter(Boolean).join(", ")
10779
11414
  });
10780
- if (p6.isCancel(stack)) return;
11415
+ if (p8.isCancel(stack)) return;
10781
11416
  memory.setIdentity(
10782
11417
  name,
10783
11418
  description,
@@ -10820,11 +11455,11 @@ async function undoChanges(ctx, steps) {
10820
11455
  const snapshot = snapshots[targetIndex];
10821
11456
  console.log("");
10822
11457
  console.log(colors.white(` Rolling back to: ${snapshot.description}`));
10823
- const confirm7 = await p6.confirm({
11458
+ const confirm8 = await p8.confirm({
10824
11459
  message: "Proceed with rollback?",
10825
11460
  initialValue: false
10826
11461
  });
10827
- if (confirm7 && !p6.isCancel(confirm7)) {
11462
+ if (confirm8 && !p8.isCancel(confirm8)) {
10828
11463
  const restored = await memory.rollback(snapshot.id);
10829
11464
  showSuccess(`Restored ${restored.length} file${restored.length > 1 ? "s" : ""}`);
10830
11465
  }
@@ -10832,11 +11467,11 @@ async function undoChanges(ctx, steps) {
10832
11467
  async function commitChanges(ctx, message) {
10833
11468
  const { git, memory } = ctx;
10834
11469
  if (!await git.isRepo()) {
10835
- const init = await p6.confirm({
11470
+ const init = await p8.confirm({
10836
11471
  message: "No git repo found. Initialize one?",
10837
11472
  initialValue: true
10838
11473
  });
10839
- if (init && !p6.isCancel(init)) {
11474
+ if (init && !p8.isCancel(init)) {
10840
11475
  await git.init();
10841
11476
  showSuccess("Git repository initialized");
10842
11477
  } else {
@@ -10861,13 +11496,13 @@ async function deployProject(ctx) {
10861
11496
  showError("Vercel CLI not installed. Run: npm i -g vercel");
10862
11497
  return;
10863
11498
  }
10864
- const prod = await p6.confirm({
11499
+ const prod = await p8.confirm({
10865
11500
  message: "Deploy to production?",
10866
11501
  initialValue: false
10867
11502
  });
10868
11503
  const spinner = ora3("Deploying...").start();
10869
11504
  try {
10870
- const result = await vercel.deploy(process.cwd(), prod && !p6.isCancel(prod));
11505
+ const result = await vercel.deploy(process.cwd(), prod && !p8.isCancel(prod));
10871
11506
  spinner.stop();
10872
11507
  showSuccess(`Deployed: ${result.url}`);
10873
11508
  } catch (error) {
@@ -10877,11 +11512,11 @@ async function deployProject(ctx) {
10877
11512
  }
10878
11513
  async function reviewCodebase(ctx) {
10879
11514
  const { ai } = ctx;
10880
- const includeAI = await p6.confirm({
11515
+ const includeAI = await p8.confirm({
10881
11516
  message: "Include AI deep analysis? (slower but more thorough)",
10882
11517
  initialValue: true
10883
11518
  });
10884
- if (p6.isCancel(includeAI)) return;
11519
+ if (p8.isCancel(includeAI)) return;
10885
11520
  const analyzer = new CodebaseAnalyzer(
10886
11521
  process.cwd(),
10887
11522
  includeAI ? ai : void 0
@@ -10895,11 +11530,11 @@ async function reviewCodebase(ctx) {
10895
11530
  const formatted = analyzer.formatReport(report);
10896
11531
  console.log(formatted);
10897
11532
  if (report.byCategory.patterns.length > 0) {
10898
- const fix = await p6.confirm({
11533
+ const fix = await p8.confirm({
10899
11534
  message: `Fix ${report.byCategory.patterns.length} pattern violations automatically?`,
10900
11535
  initialValue: false
10901
11536
  });
10902
- if (fix && !p6.isCancel(fix)) {
11537
+ if (fix && !p8.isCancel(fix)) {
10903
11538
  showInfo("Use `/fix` command to auto-fix pattern violations (coming soon)");
10904
11539
  }
10905
11540
  }
@@ -10912,7 +11547,7 @@ async function runSetup(config) {
10912
11547
  console.log("");
10913
11548
  console.log(colors.white(" Setup CodeBakers CLI"));
10914
11549
  divider();
10915
- const apiKey = await p6.text({
11550
+ const apiKey = await p8.text({
10916
11551
  message: "Anthropic API key:",
10917
11552
  placeholder: "sk-ant-...",
10918
11553
  validate: (value) => {
@@ -10920,30 +11555,30 @@ async function runSetup(config) {
10920
11555
  if (!value.startsWith("sk-ant-")) return "Invalid format";
10921
11556
  }
10922
11557
  });
10923
- if (p6.isCancel(apiKey)) return;
11558
+ if (p8.isCancel(apiKey)) return;
10924
11559
  config.setAnthropicKey(apiKey);
10925
- const setupGithub = await p6.confirm({
11560
+ const setupGithub = await p8.confirm({
10926
11561
  message: "Set up GitHub token? (optional)",
10927
11562
  initialValue: false
10928
11563
  });
10929
- if (setupGithub && !p6.isCancel(setupGithub)) {
10930
- const token = await p6.text({
11564
+ if (setupGithub && !p8.isCancel(setupGithub)) {
11565
+ const token = await p8.text({
10931
11566
  message: "GitHub token:",
10932
11567
  placeholder: "ghp_..."
10933
11568
  });
10934
- if (!p6.isCancel(token) && token) {
11569
+ if (!p8.isCancel(token) && token) {
10935
11570
  config.setGithubToken(token);
10936
11571
  }
10937
11572
  }
10938
- const setupVercel = await p6.confirm({
11573
+ const setupVercel = await p8.confirm({
10939
11574
  message: "Set up Vercel token? (optional)",
10940
11575
  initialValue: false
10941
11576
  });
10942
- if (setupVercel && !p6.isCancel(setupVercel)) {
10943
- const token = await p6.text({
11577
+ if (setupVercel && !p8.isCancel(setupVercel)) {
11578
+ const token = await p8.text({
10944
11579
  message: "Vercel token:"
10945
11580
  });
10946
- if (!p6.isCancel(token) && token) {
11581
+ if (!p8.isCancel(token) && token) {
10947
11582
  config.setVercelToken(token);
10948
11583
  }
10949
11584
  }