codebakers 3.1.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.
- package/dist/index.js +778 -156
- 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
|
|
9
|
+
import * as p8 from "@clack/prompts";
|
|
10
10
|
import ora3 from "ora";
|
|
11
|
-
import
|
|
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((
|
|
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
|
|
1503
|
-
if (
|
|
1504
|
-
issues.push(
|
|
1505
|
-
} else if (
|
|
1506
|
-
suggestions.push(
|
|
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 (
|
|
1576
|
-
const f = await this.loadFile(
|
|
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
|
);
|
|
@@ -1765,12 +1765,6 @@ function showHeader() {
|
|
|
1765
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"));
|
|
1766
1766
|
console.log("");
|
|
1767
1767
|
}
|
|
1768
|
-
function showProjectStatus(name, framework) {
|
|
1769
|
-
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"));
|
|
1770
|
-
console.log(colors.white(` \u{1F4C1} ${name}`) + colors.muted(` (${framework || "Unknown"})`));
|
|
1771
|
-
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"));
|
|
1772
|
-
console.log("");
|
|
1773
|
-
}
|
|
1774
1768
|
function showSuccess(message) {
|
|
1775
1769
|
console.log(` ${sym.check} ${colors.white(message)}`);
|
|
1776
1770
|
}
|
|
@@ -1787,15 +1781,6 @@ function divider() {
|
|
|
1787
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"));
|
|
1788
1782
|
}
|
|
1789
1783
|
var promptSymbol = colors.primary("\u276F");
|
|
1790
|
-
function showWelcome() {
|
|
1791
|
-
console.log(colors.muted(" Just tell me what you need:"));
|
|
1792
|
-
console.log(colors.muted(' "Add a login page" - Generate code'));
|
|
1793
|
-
console.log(colors.muted(' "Review my code" - Analyze codebase'));
|
|
1794
|
-
console.log(colors.muted(' "Deploy to production" - Ship it'));
|
|
1795
|
-
console.log(colors.muted(' "Undo that" - Rollback'));
|
|
1796
|
-
console.log(colors.muted(" /help - All commands"));
|
|
1797
|
-
console.log("");
|
|
1798
|
-
}
|
|
1799
1784
|
|
|
1800
1785
|
// src/core/nlp.ts
|
|
1801
1786
|
var INTENT_PATTERNS = [
|
|
@@ -2411,7 +2396,11 @@ var NLPInterpreter = class {
|
|
|
2411
2396
|
"account": "whoami",
|
|
2412
2397
|
"me": "whoami",
|
|
2413
2398
|
"index": "index",
|
|
2414
|
-
"rag": "index"
|
|
2399
|
+
"rag": "index",
|
|
2400
|
+
"folder": "folder",
|
|
2401
|
+
"cd": "folder",
|
|
2402
|
+
"chdir": "folder",
|
|
2403
|
+
"browse": "folder"
|
|
2415
2404
|
};
|
|
2416
2405
|
const intent = commandMap[lower] || "unclear";
|
|
2417
2406
|
const params = {};
|
|
@@ -2514,12 +2503,12 @@ var NLPInterpreter = class {
|
|
|
2514
2503
|
deploy: "This will deploy your code. Continue?"
|
|
2515
2504
|
};
|
|
2516
2505
|
console.log("");
|
|
2517
|
-
const
|
|
2506
|
+
const confirm8 = await p.confirm({
|
|
2518
2507
|
message: colors.warning(messages[intent.type] || "Are you sure?"),
|
|
2519
2508
|
initialValue: intent.type !== "deploy"
|
|
2520
2509
|
// Default no for deploy
|
|
2521
2510
|
});
|
|
2522
|
-
return !p.isCancel(
|
|
2511
|
+
return !p.isCancel(confirm8) && confirm8 === true;
|
|
2523
2512
|
}
|
|
2524
2513
|
};
|
|
2525
2514
|
var nlp = new NLPInterpreter();
|
|
@@ -2747,22 +2736,22 @@ Please provide ONLY the corrected file content with the path. No explanation nee
|
|
|
2747
2736
|
// HELPERS
|
|
2748
2737
|
// ============================================================================
|
|
2749
2738
|
async findMissingPackages(packages) {
|
|
2750
|
-
const
|
|
2751
|
-
const
|
|
2752
|
-
const pkgPath =
|
|
2753
|
-
if (!await
|
|
2754
|
-
const pkg = await
|
|
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);
|
|
2755
2744
|
const installed = {
|
|
2756
2745
|
...pkg.dependencies,
|
|
2757
2746
|
...pkg.devDependencies
|
|
2758
2747
|
};
|
|
2759
|
-
return packages.filter((
|
|
2748
|
+
return packages.filter((p9) => !installed[p9]);
|
|
2760
2749
|
}
|
|
2761
|
-
spin(
|
|
2750
|
+
spin(text6) {
|
|
2762
2751
|
if (this.spinner) {
|
|
2763
|
-
this.spinner.text =
|
|
2752
|
+
this.spinner.text = text6 + " (ESC to cancel)";
|
|
2764
2753
|
} else {
|
|
2765
|
-
this.spinner = ora(
|
|
2754
|
+
this.spinner = ora(text6 + " (ESC to cancel)").start();
|
|
2766
2755
|
}
|
|
2767
2756
|
}
|
|
2768
2757
|
stop() {
|
|
@@ -4080,9 +4069,9 @@ Create ALL files listed above.`;
|
|
|
4080
4069
|
const count = pathMap.get(file.path) || 0;
|
|
4081
4070
|
pathMap.set(file.path, count + 1);
|
|
4082
4071
|
}
|
|
4083
|
-
for (const [
|
|
4072
|
+
for (const [path19, count] of pathMap) {
|
|
4084
4073
|
if (count > 1) {
|
|
4085
|
-
conflicts.push(`Multiple agents created: ${
|
|
4074
|
+
conflicts.push(`Multiple agents created: ${path19}`);
|
|
4086
4075
|
}
|
|
4087
4076
|
}
|
|
4088
4077
|
for (const file of files) {
|
|
@@ -4890,11 +4879,11 @@ var AgentExecutor = class {
|
|
|
4890
4879
|
}
|
|
4891
4880
|
return Array.from(packages);
|
|
4892
4881
|
}
|
|
4893
|
-
spin(
|
|
4882
|
+
spin(text6) {
|
|
4894
4883
|
if (this.spinner) {
|
|
4895
|
-
this.spinner.text =
|
|
4884
|
+
this.spinner.text = text6;
|
|
4896
4885
|
} else {
|
|
4897
|
-
this.spinner = ora2(
|
|
4886
|
+
this.spinner = ora2(text6).start();
|
|
4898
4887
|
}
|
|
4899
4888
|
}
|
|
4900
4889
|
stop() {
|
|
@@ -5199,7 +5188,7 @@ ${chunks[i]}`,
|
|
|
5199
5188
|
projectName: analysis.projectName,
|
|
5200
5189
|
totalFeatures: analysis.features.length,
|
|
5201
5190
|
completedFeatures: analysis.features.filter((f) => f.status === "complete").length,
|
|
5202
|
-
currentPhase: analysis.phases.find((
|
|
5191
|
+
currentPhase: analysis.phases.find((p9) => p9.status === "in_progress")?.id || analysis.phases[0]?.id || "",
|
|
5203
5192
|
currentFeature: analysis.features.find((f) => f.status === "in_progress")?.id || "",
|
|
5204
5193
|
features: analysis.features.map((f) => ({ id: f.id, status: f.status })),
|
|
5205
5194
|
startedAt: Date.now(),
|
|
@@ -6695,8 +6684,8 @@ var SmartGitManager = class {
|
|
|
6695
6684
|
const pr = await this.createPR(phaseBranch, baseBranch);
|
|
6696
6685
|
return pr;
|
|
6697
6686
|
}
|
|
6698
|
-
slugify(
|
|
6699
|
-
return
|
|
6687
|
+
slugify(text6) {
|
|
6688
|
+
return text6.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 30);
|
|
6700
6689
|
}
|
|
6701
6690
|
// ============================================================================
|
|
6702
6691
|
// SMART COMMITS
|
|
@@ -6975,7 +6964,7 @@ var ProjectBuilder = class {
|
|
|
6975
6964
|
totalDuration: 0
|
|
6976
6965
|
};
|
|
6977
6966
|
try {
|
|
6978
|
-
const phaseNames = spec.buildPhases.map((
|
|
6967
|
+
const phaseNames = spec.buildPhases.map((p9) => p9.name.replace(/Phase \d+:\s*/i, ""));
|
|
6979
6968
|
const strategy = await this.git.createProjectStrategy(spec.name, phaseNames);
|
|
6980
6969
|
console.log(this.git.formatStrategy(strategy));
|
|
6981
6970
|
const proceed = await p4.confirm({
|
|
@@ -7682,7 +7671,7 @@ Return ONLY the fixed code, no explanations. Keep all other code exactly the sam
|
|
|
7682
7671
|
return this.patterns;
|
|
7683
7672
|
}
|
|
7684
7673
|
enablePattern(id) {
|
|
7685
|
-
const pattern = this.patterns.find((
|
|
7674
|
+
const pattern = this.patterns.find((p9) => p9.id === id);
|
|
7686
7675
|
if (pattern) {
|
|
7687
7676
|
pattern.enabled = true;
|
|
7688
7677
|
return true;
|
|
@@ -7690,7 +7679,7 @@ Return ONLY the fixed code, no explanations. Keep all other code exactly the sam
|
|
|
7690
7679
|
return false;
|
|
7691
7680
|
}
|
|
7692
7681
|
disablePattern(id) {
|
|
7693
|
-
const pattern = this.patterns.find((
|
|
7682
|
+
const pattern = this.patterns.find((p9) => p9.id === id);
|
|
7694
7683
|
if (pattern) {
|
|
7695
7684
|
pattern.enabled = false;
|
|
7696
7685
|
return true;
|
|
@@ -7749,8 +7738,8 @@ Return ONLY the fixed code, no explanations. Keep all other code exactly the sam
|
|
|
7749
7738
|
formatPatterns() {
|
|
7750
7739
|
let output = "\n";
|
|
7751
7740
|
output += colors.white(" \u{1F4CB} Pattern Rules") + "\n\n";
|
|
7752
|
-
const enabled = this.patterns.filter((
|
|
7753
|
-
const disabled = this.patterns.filter((
|
|
7741
|
+
const enabled = this.patterns.filter((p9) => p9.enabled);
|
|
7742
|
+
const disabled = this.patterns.filter((p9) => !p9.enabled);
|
|
7754
7743
|
output += colors.success(" ENABLED") + "\n";
|
|
7755
7744
|
for (const pattern of enabled) {
|
|
7756
7745
|
const severityIcon = pattern.severity === "critical" ? "\u{1F534}" : pattern.severity === "warning" ? "\u{1F7E1}" : "\u{1F7E2}";
|
|
@@ -7775,7 +7764,7 @@ Return ONLY the fixed code, no explanations. Keep all other code exactly the sam
|
|
|
7775
7764
|
return grouped;
|
|
7776
7765
|
}
|
|
7777
7766
|
getPatternName(id) {
|
|
7778
|
-
const pattern = this.patterns.find((
|
|
7767
|
+
const pattern = this.patterns.find((p9) => p9.id === id);
|
|
7779
7768
|
return pattern?.name || id;
|
|
7780
7769
|
}
|
|
7781
7770
|
// ============================================================================
|
|
@@ -7981,7 +7970,7 @@ var SmartSuggestions = class {
|
|
|
7981
7970
|
/platform\s*(that|which|for)/,
|
|
7982
7971
|
/saas\s*(for|that|which)/
|
|
7983
7972
|
];
|
|
7984
|
-
return ideaPatterns.some((
|
|
7973
|
+
return ideaPatterns.some((p9) => p9.test(lower));
|
|
7985
7974
|
}
|
|
7986
7975
|
looksLikeComplexRequest(input) {
|
|
7987
7976
|
const lower = input.toLowerCase();
|
|
@@ -8011,7 +8000,7 @@ var SmartSuggestions = class {
|
|
|
8011
8000
|
/clean\s*up/,
|
|
8012
8001
|
/improve\s*(the\s*)?(code|quality)/
|
|
8013
8002
|
];
|
|
8014
|
-
return patterns.some((
|
|
8003
|
+
return patterns.some((p9) => p9.test(lower));
|
|
8015
8004
|
}
|
|
8016
8005
|
// ============================================================================
|
|
8017
8006
|
// DISPLAY
|
|
@@ -8041,6 +8030,23 @@ var AUTH_STORE = new Conf2({
|
|
|
8041
8030
|
projectName: "codebakers",
|
|
8042
8031
|
encryptionKey: "cb-secure-storage-key-2026"
|
|
8043
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
|
+
];
|
|
8044
8050
|
var FEATURES = {
|
|
8045
8051
|
// Free features
|
|
8046
8052
|
basic_build: "basic_build",
|
|
@@ -8057,6 +8063,7 @@ var FEATURES = {
|
|
|
8057
8063
|
whitelabel: "whitelabel",
|
|
8058
8064
|
priority_support: "priority_support"
|
|
8059
8065
|
};
|
|
8066
|
+
var ALL_FEATURES = Object.values(FEATURES);
|
|
8060
8067
|
var Auth = class _Auth {
|
|
8061
8068
|
static instance;
|
|
8062
8069
|
constructor() {
|
|
@@ -8068,7 +8075,7 @@ var Auth = class _Auth {
|
|
|
8068
8075
|
return _Auth.instance;
|
|
8069
8076
|
}
|
|
8070
8077
|
// ============================================================================
|
|
8071
|
-
// LOGIN FLOW
|
|
8078
|
+
// LOGIN FLOW - Multiple methods
|
|
8072
8079
|
// ============================================================================
|
|
8073
8080
|
async login() {
|
|
8074
8081
|
const existing = this.getAuth();
|
|
@@ -8084,6 +8091,163 @@ var Auth = class _Auth {
|
|
|
8084
8091
|
console.log("");
|
|
8085
8092
|
console.log(colors.white(" \u{1F510} CodeBakers Login"));
|
|
8086
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() {
|
|
8087
8251
|
try {
|
|
8088
8252
|
const deviceCode = await this.requestDeviceCode();
|
|
8089
8253
|
if (!deviceCode) {
|
|
@@ -8112,6 +8276,15 @@ var Auth = class _Auth {
|
|
|
8112
8276
|
console.log(colors.error(" Authentication failed or timed out."));
|
|
8113
8277
|
return false;
|
|
8114
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
|
+
}
|
|
8115
8288
|
this.saveAuth(auth2);
|
|
8116
8289
|
console.log("");
|
|
8117
8290
|
console.log(colors.success(` \u2713 Logged in as ${auth2.user.email}`));
|
|
@@ -8134,6 +8307,13 @@ var Auth = class _Auth {
|
|
|
8134
8307
|
console.log(colors.success(" \u2713 Logged out successfully"));
|
|
8135
8308
|
}
|
|
8136
8309
|
// ============================================================================
|
|
8310
|
+
// IS LOGGED IN - Quick check
|
|
8311
|
+
// ============================================================================
|
|
8312
|
+
isLoggedIn() {
|
|
8313
|
+
const auth2 = this.getAuth();
|
|
8314
|
+
return auth2 !== null && !this.isExpired(auth2);
|
|
8315
|
+
}
|
|
8316
|
+
// ============================================================================
|
|
8137
8317
|
// WHO AM I
|
|
8138
8318
|
// ============================================================================
|
|
8139
8319
|
async whoami() {
|
|
@@ -8145,16 +8325,26 @@ var Auth = class _Auth {
|
|
|
8145
8325
|
console.log("");
|
|
8146
8326
|
return;
|
|
8147
8327
|
}
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8328
|
+
if (auth2.authType === "device") {
|
|
8329
|
+
const freshLicense = await this.verifyLicense();
|
|
8330
|
+
if (freshLicense) {
|
|
8331
|
+
auth2.license = freshLicense;
|
|
8332
|
+
this.saveAuth(auth2);
|
|
8333
|
+
}
|
|
8152
8334
|
}
|
|
8153
8335
|
console.log("");
|
|
8154
8336
|
console.log(colors.white(" \u{1F464} CodeBakers Account"));
|
|
8155
8337
|
console.log("");
|
|
8156
8338
|
console.log(colors.secondary(` Email: ${auth2.user.email}`));
|
|
8157
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"}`));
|
|
8158
8348
|
console.log("");
|
|
8159
8349
|
console.log(colors.white(" \u{1F4C4} License"));
|
|
8160
8350
|
console.log(colors.secondary(` Tier: ${auth2.license.tier.toUpperCase()}`));
|
|
@@ -8170,7 +8360,7 @@ var Auth = class _Auth {
|
|
|
8170
8360
|
for (const feature of auth2.license.features) {
|
|
8171
8361
|
console.log(colors.success(` \u2713 ${this.formatFeatureName(feature)}`));
|
|
8172
8362
|
}
|
|
8173
|
-
if (auth2.license.usage) {
|
|
8363
|
+
if (auth2.license.usage && auth2.authType !== "admin") {
|
|
8174
8364
|
console.log("");
|
|
8175
8365
|
console.log(colors.white(" \u{1F4CA} Usage This Month"));
|
|
8176
8366
|
const pct = Math.round(auth2.license.usage.current / auth2.license.usage.limit * 100);
|
|
@@ -8673,7 +8863,7 @@ ${issues.map((i) => ` \u2022 ${i}`).join("\n")}` : "\n\nEverything looks good!"
|
|
|
8673
8863
|
/^(ugh|argh|damn|shit|fuck)/i
|
|
8674
8864
|
// Frustration words
|
|
8675
8865
|
];
|
|
8676
|
-
return frustrationPatterns.some((
|
|
8866
|
+
return frustrationPatterns.some((p9) => p9.test(input));
|
|
8677
8867
|
}
|
|
8678
8868
|
// ============================================================================
|
|
8679
8869
|
// RATE LIMITING (Don't be annoying)
|
|
@@ -8935,8 +9125,8 @@ ${chunk.content.slice(0, 2e3)}`
|
|
|
8935
9125
|
chunk.embedding = this.simpleEmbed(chunk.content + " " + chunk.summary);
|
|
8936
9126
|
}
|
|
8937
9127
|
}
|
|
8938
|
-
simpleEmbed(
|
|
8939
|
-
const words =
|
|
9128
|
+
simpleEmbed(text6) {
|
|
9129
|
+
const words = text6.toLowerCase().split(/\W+/).filter((w) => w.length > 2);
|
|
8940
9130
|
const embedding = new Array(256).fill(0);
|
|
8941
9131
|
for (const word of words) {
|
|
8942
9132
|
const hash = this.hashString(word);
|
|
@@ -9281,8 +9471,8 @@ ${content.slice(0, 3e3)}`
|
|
|
9281
9471
|
for (const feature of commonFeatures) {
|
|
9282
9472
|
if (!features.has(feature)) {
|
|
9283
9473
|
const relatedFiles = [...files.entries()].filter(
|
|
9284
|
-
([
|
|
9285
|
-
).map(([
|
|
9474
|
+
([path19, summary]) => path19.toLowerCase().includes(feature) || summary.summary.toLowerCase().includes(feature)
|
|
9475
|
+
).map(([path19]) => path19);
|
|
9286
9476
|
if (relatedFiles.length > 0) {
|
|
9287
9477
|
features.set(feature, {
|
|
9288
9478
|
name: feature,
|
|
@@ -9397,7 +9587,7 @@ ${featureList}`
|
|
|
9397
9587
|
"Redux": ["@reduxjs/toolkit", "redux"]
|
|
9398
9588
|
};
|
|
9399
9589
|
for (const [name, packages] of Object.entries(categories)) {
|
|
9400
|
-
if (packages.some((
|
|
9590
|
+
if (packages.some((p9) => deps.has(p9))) {
|
|
9401
9591
|
stack.push(name);
|
|
9402
9592
|
}
|
|
9403
9593
|
}
|
|
@@ -9443,8 +9633,8 @@ ${featureList}`
|
|
|
9443
9633
|
}
|
|
9444
9634
|
}
|
|
9445
9635
|
const relevantFiles = [...this.index.files.entries()].filter(
|
|
9446
|
-
([
|
|
9447
|
-
(word) => word.length > 2 && (
|
|
9636
|
+
([path19, summary]) => queryLower.split(" ").some(
|
|
9637
|
+
(word) => word.length > 2 && (path19.toLowerCase().includes(word) || summary.summary.toLowerCase().includes(word))
|
|
9448
9638
|
)
|
|
9449
9639
|
).slice(0, 10);
|
|
9450
9640
|
if (relevantFiles.length > 0) {
|
|
@@ -9529,10 +9719,411 @@ ${featureList}`
|
|
|
9529
9719
|
}
|
|
9530
9720
|
};
|
|
9531
9721
|
|
|
9532
|
-
// src/
|
|
9533
|
-
import
|
|
9722
|
+
// src/core/onboarding.ts
|
|
9723
|
+
import * as p6 from "@clack/prompts";
|
|
9534
9724
|
import fs16 from "fs-extra";
|
|
9535
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";
|
|
9536
10127
|
var GitService = class {
|
|
9537
10128
|
git;
|
|
9538
10129
|
projectPath;
|
|
@@ -9541,7 +10132,7 @@ var GitService = class {
|
|
|
9541
10132
|
this.git = simpleGit(projectPath);
|
|
9542
10133
|
}
|
|
9543
10134
|
async isRepo() {
|
|
9544
|
-
return
|
|
10135
|
+
return fs17.pathExists(path18.join(this.projectPath, ".git"));
|
|
9545
10136
|
}
|
|
9546
10137
|
async init() {
|
|
9547
10138
|
await this.git.init();
|
|
@@ -9652,7 +10243,7 @@ var VercelService = class {
|
|
|
9652
10243
|
};
|
|
9653
10244
|
|
|
9654
10245
|
// src/index.ts
|
|
9655
|
-
var VERSION = "
|
|
10246
|
+
var VERSION = "3.3.0";
|
|
9656
10247
|
async function main() {
|
|
9657
10248
|
const config = new Config();
|
|
9658
10249
|
const args = process.argv.slice(2);
|
|
@@ -9668,22 +10259,36 @@ async function main() {
|
|
|
9668
10259
|
await runSetup(config);
|
|
9669
10260
|
return;
|
|
9670
10261
|
}
|
|
9671
|
-
|
|
9672
|
-
|
|
9673
|
-
|
|
9674
|
-
await runSetup(config);
|
|
9675
|
-
if (!config.isConfigured()) {
|
|
9676
|
-
showError("Setup incomplete. Run `cb setup` to configure.");
|
|
9677
|
-
return;
|
|
9678
|
-
}
|
|
10262
|
+
if (args[0] === "login") {
|
|
10263
|
+
await auth.login();
|
|
10264
|
+
return;
|
|
9679
10265
|
}
|
|
9680
10266
|
const memory = new Memory();
|
|
9681
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("");
|
|
9682
10280
|
const scanner = new ProjectScanner();
|
|
9683
10281
|
const structure = await scanner.detectProject();
|
|
9684
10282
|
const editor = new FileEditor();
|
|
9685
10283
|
const git = new GitService();
|
|
9686
|
-
|
|
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("");
|
|
9687
10292
|
let ai;
|
|
9688
10293
|
try {
|
|
9689
10294
|
ai = new AIEngine(config, memory, scanner);
|
|
@@ -9695,27 +10300,18 @@ async function main() {
|
|
|
9695
10300
|
const modeManager = getModeManager();
|
|
9696
10301
|
const suggestions = new SmartSuggestions(memory, scanner);
|
|
9697
10302
|
const proactive = new ProactiveAssistant(memory, scanner, config);
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
console.log(proactive.formatAction(startupAction));
|
|
9701
|
-
proactive.markSuggestionShown();
|
|
9702
|
-
}
|
|
9703
|
-
const identity = memory.getIdentity();
|
|
9704
|
-
if (!identity.name) {
|
|
9705
|
-
showInfo('Project not initialized. Say "initialize project" or use /init');
|
|
9706
|
-
}
|
|
9707
|
-
showWelcome();
|
|
9708
|
-
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'));
|
|
9709
10305
|
console.log("");
|
|
9710
10306
|
let lastAction;
|
|
9711
10307
|
let running = true;
|
|
9712
10308
|
while (running) {
|
|
9713
10309
|
const modePrompt = modeManager.getPrompt();
|
|
9714
|
-
const input = await
|
|
10310
|
+
const input = await p8.text({
|
|
9715
10311
|
message: modePrompt,
|
|
9716
10312
|
placeholder: "What would you like to build? (Shift+Tab to change mode)"
|
|
9717
10313
|
});
|
|
9718
|
-
if (
|
|
10314
|
+
if (p8.isCancel(input)) {
|
|
9719
10315
|
running = false;
|
|
9720
10316
|
showInfo("Goodbye! \u{1F44B}");
|
|
9721
10317
|
break;
|
|
@@ -9773,8 +10369,8 @@ async function main() {
|
|
|
9773
10369
|
showSuccess(`Decision recorded: ${result.params.content}`);
|
|
9774
10370
|
} else {
|
|
9775
10371
|
showInfo("What decision would you like to record?");
|
|
9776
|
-
const decision = await
|
|
9777
|
-
if (!
|
|
10372
|
+
const decision = await p8.text({ message: "Decision:" });
|
|
10373
|
+
if (!p8.isCancel(decision) && decision) {
|
|
9778
10374
|
memory.addDecision(decision);
|
|
9779
10375
|
await memory.save();
|
|
9780
10376
|
showSuccess(`Decision recorded: ${decision}`);
|
|
@@ -9788,8 +10384,8 @@ async function main() {
|
|
|
9788
10384
|
showSuccess(`Rule added: ${result.params.content}`);
|
|
9789
10385
|
} else {
|
|
9790
10386
|
showInfo("What rule would you like to add?");
|
|
9791
|
-
const rule = await
|
|
9792
|
-
if (!
|
|
10387
|
+
const rule = await p8.text({ message: "Rule:" });
|
|
10388
|
+
if (!p8.isCancel(rule) && rule) {
|
|
9793
10389
|
memory.addCustomRule(rule);
|
|
9794
10390
|
await memory.save();
|
|
9795
10391
|
showSuccess(`Rule added: ${rule}`);
|
|
@@ -9854,17 +10450,20 @@ async function main() {
|
|
|
9854
10450
|
case "index":
|
|
9855
10451
|
await handleIndex(ctx);
|
|
9856
10452
|
break;
|
|
10453
|
+
case "folder":
|
|
10454
|
+
await handleFolderChange();
|
|
10455
|
+
break;
|
|
9857
10456
|
case "generate":
|
|
9858
10457
|
default:
|
|
9859
10458
|
const inputHandler = new InputHandler(config, memory, scanner);
|
|
9860
10459
|
const detected = await inputHandler.detectAndProcess(cmd);
|
|
9861
10460
|
if (detected.type !== "text") {
|
|
9862
10461
|
console.log(inputHandler.formatDetection(detected));
|
|
9863
|
-
const proceed = await
|
|
10462
|
+
const proceed = await p8.confirm({
|
|
9864
10463
|
message: `Process this ${detected.type}?`,
|
|
9865
10464
|
initialValue: true
|
|
9866
10465
|
});
|
|
9867
|
-
if (!proceed ||
|
|
10466
|
+
if (!proceed || p8.isCancel(proceed)) break;
|
|
9868
10467
|
const enhancedCmd = inputHandler.enhancePrompt(detected, cmd);
|
|
9869
10468
|
await handleGeneration(enhancedCmd, ctx);
|
|
9870
10469
|
break;
|
|
@@ -9883,11 +10482,11 @@ async function main() {
|
|
|
9883
10482
|
console.log(colors.secondary(" \u{1F4A1} This looks like a complex request."));
|
|
9884
10483
|
console.log(colors.muted(" Parallel build could be ~3x faster."));
|
|
9885
10484
|
console.log("");
|
|
9886
|
-
const useParallel = await
|
|
10485
|
+
const useParallel = await p8.confirm({
|
|
9887
10486
|
message: "Use parallel build with 3 agents?",
|
|
9888
10487
|
initialValue: true
|
|
9889
10488
|
});
|
|
9890
|
-
if (useParallel && !
|
|
10489
|
+
if (useParallel && !p8.isCancel(useParallel)) {
|
|
9891
10490
|
await handleParallelBuild(cmd, ctx);
|
|
9892
10491
|
break;
|
|
9893
10492
|
}
|
|
@@ -9899,11 +10498,11 @@ async function main() {
|
|
|
9899
10498
|
console.log(colors.secondary(` \u{1F4A1} I recommend the "${suggestedTemplate.name}" template.`));
|
|
9900
10499
|
console.log(colors.muted(` ${suggestedTemplate.description}`));
|
|
9901
10500
|
console.log("");
|
|
9902
|
-
const useTemplate = await
|
|
10501
|
+
const useTemplate = await p8.confirm({
|
|
9903
10502
|
message: "Install this template first?",
|
|
9904
10503
|
initialValue: true
|
|
9905
10504
|
});
|
|
9906
|
-
if (useTemplate && !
|
|
10505
|
+
if (useTemplate && !p8.isCancel(useTemplate)) {
|
|
9907
10506
|
await handleInstallTemplate(suggestedTemplate.id, ctx);
|
|
9908
10507
|
showSuccess("Template installed! Now customizing...");
|
|
9909
10508
|
}
|
|
@@ -10042,7 +10641,7 @@ async function handleCreate(name, ctx) {
|
|
|
10042
10641
|
const { config } = ctx;
|
|
10043
10642
|
let projectName = name;
|
|
10044
10643
|
if (!projectName) {
|
|
10045
|
-
const nameInput = await
|
|
10644
|
+
const nameInput = await p8.text({
|
|
10046
10645
|
message: "Project name:",
|
|
10047
10646
|
placeholder: "my-awesome-app",
|
|
10048
10647
|
validate: (value) => {
|
|
@@ -10050,23 +10649,23 @@ async function handleCreate(name, ctx) {
|
|
|
10050
10649
|
if (!/^[a-z0-9-]+$/.test(value)) return "Use lowercase letters, numbers, and hyphens only";
|
|
10051
10650
|
}
|
|
10052
10651
|
});
|
|
10053
|
-
if (
|
|
10652
|
+
if (p8.isCancel(nameInput)) return;
|
|
10054
10653
|
projectName = nameInput;
|
|
10055
10654
|
}
|
|
10056
10655
|
console.log("");
|
|
10057
|
-
const github = await
|
|
10656
|
+
const github = await p8.confirm({
|
|
10058
10657
|
message: "Create GitHub repository?",
|
|
10059
10658
|
initialValue: !!config.getGithubToken()
|
|
10060
10659
|
});
|
|
10061
|
-
const supabase = await
|
|
10660
|
+
const supabase = await p8.confirm({
|
|
10062
10661
|
message: "Create Supabase project?",
|
|
10063
10662
|
initialValue: !!config.getSupabaseToken()
|
|
10064
10663
|
});
|
|
10065
|
-
const vercel = await
|
|
10664
|
+
const vercel = await p8.confirm({
|
|
10066
10665
|
message: "Deploy to Vercel?",
|
|
10067
10666
|
initialValue: !!config.getVercelToken()
|
|
10068
10667
|
});
|
|
10069
|
-
if (
|
|
10668
|
+
if (p8.isCancel(github) || p8.isCancel(supabase) || p8.isCancel(vercel)) return;
|
|
10070
10669
|
const creator = new ProjectCreator(config);
|
|
10071
10670
|
const spinner = ora3("Creating project...").start();
|
|
10072
10671
|
const result = await creator.create(
|
|
@@ -10127,14 +10726,14 @@ async function handleInstallTemplate(templateId, ctx) {
|
|
|
10127
10726
|
let id = templateId;
|
|
10128
10727
|
if (!id) {
|
|
10129
10728
|
const templates = templateManager.listTemplates();
|
|
10130
|
-
const choice = await
|
|
10729
|
+
const choice = await p8.select({
|
|
10131
10730
|
message: "Choose a template:",
|
|
10132
10731
|
options: templates.map((t) => ({
|
|
10133
10732
|
value: t.id,
|
|
10134
10733
|
label: `${t.name} - ${t.description}`
|
|
10135
10734
|
}))
|
|
10136
10735
|
});
|
|
10137
|
-
if (
|
|
10736
|
+
if (p8.isCancel(choice)) return;
|
|
10138
10737
|
id = choice;
|
|
10139
10738
|
}
|
|
10140
10739
|
const spinner = ora3(`Installing ${id}...`).start();
|
|
@@ -10210,11 +10809,11 @@ async function handleParallelBuild(request, ctx) {
|
|
|
10210
10809
|
console.log(colors.muted(` + ${change.path}`));
|
|
10211
10810
|
}
|
|
10212
10811
|
console.log("");
|
|
10213
|
-
const apply = await
|
|
10812
|
+
const apply = await p8.confirm({
|
|
10214
10813
|
message: "Apply all files?",
|
|
10215
10814
|
initialValue: true
|
|
10216
10815
|
});
|
|
10217
|
-
if (apply && !
|
|
10816
|
+
if (apply && !p8.isCancel(apply)) {
|
|
10218
10817
|
const applied = await editor.apply();
|
|
10219
10818
|
showSuccess(`Applied ${applied.length} files`);
|
|
10220
10819
|
for (const file of applied) {
|
|
@@ -10286,11 +10885,11 @@ async function handlePlanMode(request, ctx) {
|
|
|
10286
10885
|
const plan = await planExecutor.createPlan(request);
|
|
10287
10886
|
spinner.stop();
|
|
10288
10887
|
console.log(planExecutor.formatPlan(plan));
|
|
10289
|
-
const execute = await
|
|
10888
|
+
const execute = await p8.confirm({
|
|
10290
10889
|
message: "Execute this plan?",
|
|
10291
10890
|
initialValue: true
|
|
10292
10891
|
});
|
|
10293
|
-
if (execute && !
|
|
10892
|
+
if (execute && !p8.isCancel(execute)) {
|
|
10294
10893
|
await handleGeneration(request, ctx);
|
|
10295
10894
|
}
|
|
10296
10895
|
} catch (error) {
|
|
@@ -10353,11 +10952,11 @@ async function handleTestGeneration(filePath, ctx) {
|
|
|
10353
10952
|
const { config, scanner, editor } = ctx;
|
|
10354
10953
|
const testGen = new TestGenerator(config, scanner);
|
|
10355
10954
|
if (!filePath) {
|
|
10356
|
-
const file = await
|
|
10955
|
+
const file = await p8.text({
|
|
10357
10956
|
message: "File to generate tests for:",
|
|
10358
10957
|
placeholder: "src/components/Button.tsx"
|
|
10359
10958
|
});
|
|
10360
|
-
if (
|
|
10959
|
+
if (p8.isCancel(file) || !file) return;
|
|
10361
10960
|
filePath = file;
|
|
10362
10961
|
}
|
|
10363
10962
|
const spinner = ora3(`Generating tests for ${filePath}...`).start();
|
|
@@ -10374,11 +10973,11 @@ async function handleTestGeneration(filePath, ctx) {
|
|
|
10374
10973
|
console.log(colors.muted(" " + test.content.split("\n").slice(0, 10).join("\n ")));
|
|
10375
10974
|
console.log(colors.muted(" ..."));
|
|
10376
10975
|
console.log("");
|
|
10377
|
-
const save = await
|
|
10976
|
+
const save = await p8.confirm({
|
|
10378
10977
|
message: `Save to ${test.testPath}?`,
|
|
10379
10978
|
initialValue: true
|
|
10380
10979
|
});
|
|
10381
|
-
if (save && !
|
|
10980
|
+
if (save && !p8.isCancel(save)) {
|
|
10382
10981
|
await testGen.writeTest(test);
|
|
10383
10982
|
showSuccess(`Test saved to ${test.testPath}`);
|
|
10384
10983
|
}
|
|
@@ -10416,11 +11015,11 @@ async function handleLivePreview(ctx) {
|
|
|
10416
11015
|
const { scanner } = ctx;
|
|
10417
11016
|
const preview = new LivePreview(scanner);
|
|
10418
11017
|
if (preview.isRunning()) {
|
|
10419
|
-
const stop = await
|
|
11018
|
+
const stop = await p8.confirm({
|
|
10420
11019
|
message: "Preview is running. Stop it?",
|
|
10421
11020
|
initialValue: false
|
|
10422
11021
|
});
|
|
10423
|
-
if (stop && !
|
|
11022
|
+
if (stop && !p8.isCancel(stop)) {
|
|
10424
11023
|
await preview.stop();
|
|
10425
11024
|
showSuccess("Preview stopped");
|
|
10426
11025
|
} else {
|
|
@@ -10450,11 +11049,11 @@ async function handleSpecGeneration(input, ctx) {
|
|
|
10450
11049
|
const { config, memory, scanner, editor, ai } = ctx;
|
|
10451
11050
|
let description = input.replace(/^\/spec\s*/i, "").replace(/^\/prd\s*/i, "").replace(/^\/plan\s*/i, "").trim();
|
|
10452
11051
|
if (!description) {
|
|
10453
|
-
const desc = await
|
|
11052
|
+
const desc = await p8.text({
|
|
10454
11053
|
message: "What do you want to build?",
|
|
10455
11054
|
placeholder: "An Uber for dog walkers"
|
|
10456
11055
|
});
|
|
10457
|
-
if (
|
|
11056
|
+
if (p8.isCancel(desc) || !desc) return;
|
|
10458
11057
|
description = desc;
|
|
10459
11058
|
}
|
|
10460
11059
|
const specGen = new SpecGenerator(config);
|
|
@@ -10465,11 +11064,11 @@ async function handleSpecGeneration(input, ctx) {
|
|
|
10465
11064
|
return;
|
|
10466
11065
|
}
|
|
10467
11066
|
console.log(specGen.formatSpec(spec));
|
|
10468
|
-
const buildNow = await
|
|
11067
|
+
const buildNow = await p8.confirm({
|
|
10469
11068
|
message: "Build from this spec?",
|
|
10470
11069
|
initialValue: true
|
|
10471
11070
|
});
|
|
10472
|
-
if (buildNow && !
|
|
11071
|
+
if (buildNow && !p8.isCancel(buildNow)) {
|
|
10473
11072
|
const builder = new ProjectBuilder(config, memory, scanner, editor, ai);
|
|
10474
11073
|
let cancelled = false;
|
|
10475
11074
|
const checkCancelled = () => cancelled;
|
|
@@ -10611,7 +11210,7 @@ async function handleAudit(args, ctx) {
|
|
|
10611
11210
|
const fixType = args?.includes("critical") ? "critical" : args?.includes("all") ? "all" : null;
|
|
10612
11211
|
let issuesToFix = report.critical;
|
|
10613
11212
|
if (!fixType) {
|
|
10614
|
-
const choice = await
|
|
11213
|
+
const choice = await p8.select({
|
|
10615
11214
|
message: "What would you like to fix?",
|
|
10616
11215
|
options: [
|
|
10617
11216
|
{ value: "critical", label: `Critical issues only (${report.critical.length})` },
|
|
@@ -10619,7 +11218,7 @@ async function handleAudit(args, ctx) {
|
|
|
10619
11218
|
{ value: "all", label: `Everything (${report.totalIssues})` }
|
|
10620
11219
|
]
|
|
10621
11220
|
});
|
|
10622
|
-
if (
|
|
11221
|
+
if (p8.isCancel(choice)) return;
|
|
10623
11222
|
if (choice === "warnings") {
|
|
10624
11223
|
issuesToFix = [...report.critical, ...report.warnings];
|
|
10625
11224
|
} else if (choice === "all") {
|
|
@@ -10650,11 +11249,11 @@ async function handleAudit(args, ctx) {
|
|
|
10650
11249
|
const files = result.changes.map((c) => c.file);
|
|
10651
11250
|
await git.commitFiles(files, "fix: resolve codebase audit issues");
|
|
10652
11251
|
console.log("");
|
|
10653
|
-
const push = await
|
|
11252
|
+
const push = await p8.confirm({
|
|
10654
11253
|
message: "Push and create PR?",
|
|
10655
11254
|
initialValue: true
|
|
10656
11255
|
});
|
|
10657
|
-
if (push && !
|
|
11256
|
+
if (push && !p8.isCancel(push)) {
|
|
10658
11257
|
await git.push();
|
|
10659
11258
|
const pr = await git.createPR(branchName, await git.getMainBranch(), "Fix: Codebase Audit Issues");
|
|
10660
11259
|
if (pr?.url) {
|
|
@@ -10672,7 +11271,7 @@ async function handleAudit(args, ctx) {
|
|
|
10672
11271
|
spinner.stop();
|
|
10673
11272
|
const markdown = auditor.exportMarkdown(report);
|
|
10674
11273
|
const reportPath = "AUDIT_REPORT.md";
|
|
10675
|
-
await
|
|
11274
|
+
await fs18.writeFile(reportPath, markdown);
|
|
10676
11275
|
console.log(auditor.formatReport(report));
|
|
10677
11276
|
showSuccess(`Report saved to ${reportPath}`);
|
|
10678
11277
|
break;
|
|
@@ -10767,21 +11366,44 @@ async function handleIndex(ctx) {
|
|
|
10767
11366
|
showSuccess("Codebase indexed! Context retrieval is now smarter.");
|
|
10768
11367
|
console.log(colors.muted(" Re-run /index after major changes to keep it updated."));
|
|
10769
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
|
+
}
|
|
10770
11392
|
async function initProject(ctx) {
|
|
10771
11393
|
const { memory, scanner } = ctx;
|
|
10772
11394
|
const structure = await scanner.detectProject();
|
|
10773
11395
|
console.log("");
|
|
10774
|
-
const name = await
|
|
11396
|
+
const name = await p8.text({
|
|
10775
11397
|
message: "Project name:",
|
|
10776
11398
|
initialValue: structure.name
|
|
10777
11399
|
});
|
|
10778
|
-
if (
|
|
10779
|
-
const description = await
|
|
11400
|
+
if (p8.isCancel(name)) return;
|
|
11401
|
+
const description = await p8.text({
|
|
10780
11402
|
message: "Description:",
|
|
10781
11403
|
placeholder: "A brief description of your project"
|
|
10782
11404
|
});
|
|
10783
|
-
if (
|
|
10784
|
-
const stack = await
|
|
11405
|
+
if (p8.isCancel(description)) return;
|
|
11406
|
+
const stack = await p8.text({
|
|
10785
11407
|
message: "Tech stack (comma-separated):",
|
|
10786
11408
|
initialValue: [
|
|
10787
11409
|
structure.framework,
|
|
@@ -10790,7 +11412,7 @@ async function initProject(ctx) {
|
|
|
10790
11412
|
"Tailwind"
|
|
10791
11413
|
].filter(Boolean).join(", ")
|
|
10792
11414
|
});
|
|
10793
|
-
if (
|
|
11415
|
+
if (p8.isCancel(stack)) return;
|
|
10794
11416
|
memory.setIdentity(
|
|
10795
11417
|
name,
|
|
10796
11418
|
description,
|
|
@@ -10833,11 +11455,11 @@ async function undoChanges(ctx, steps) {
|
|
|
10833
11455
|
const snapshot = snapshots[targetIndex];
|
|
10834
11456
|
console.log("");
|
|
10835
11457
|
console.log(colors.white(` Rolling back to: ${snapshot.description}`));
|
|
10836
|
-
const
|
|
11458
|
+
const confirm8 = await p8.confirm({
|
|
10837
11459
|
message: "Proceed with rollback?",
|
|
10838
11460
|
initialValue: false
|
|
10839
11461
|
});
|
|
10840
|
-
if (
|
|
11462
|
+
if (confirm8 && !p8.isCancel(confirm8)) {
|
|
10841
11463
|
const restored = await memory.rollback(snapshot.id);
|
|
10842
11464
|
showSuccess(`Restored ${restored.length} file${restored.length > 1 ? "s" : ""}`);
|
|
10843
11465
|
}
|
|
@@ -10845,11 +11467,11 @@ async function undoChanges(ctx, steps) {
|
|
|
10845
11467
|
async function commitChanges(ctx, message) {
|
|
10846
11468
|
const { git, memory } = ctx;
|
|
10847
11469
|
if (!await git.isRepo()) {
|
|
10848
|
-
const init = await
|
|
11470
|
+
const init = await p8.confirm({
|
|
10849
11471
|
message: "No git repo found. Initialize one?",
|
|
10850
11472
|
initialValue: true
|
|
10851
11473
|
});
|
|
10852
|
-
if (init && !
|
|
11474
|
+
if (init && !p8.isCancel(init)) {
|
|
10853
11475
|
await git.init();
|
|
10854
11476
|
showSuccess("Git repository initialized");
|
|
10855
11477
|
} else {
|
|
@@ -10874,13 +11496,13 @@ async function deployProject(ctx) {
|
|
|
10874
11496
|
showError("Vercel CLI not installed. Run: npm i -g vercel");
|
|
10875
11497
|
return;
|
|
10876
11498
|
}
|
|
10877
|
-
const prod = await
|
|
11499
|
+
const prod = await p8.confirm({
|
|
10878
11500
|
message: "Deploy to production?",
|
|
10879
11501
|
initialValue: false
|
|
10880
11502
|
});
|
|
10881
11503
|
const spinner = ora3("Deploying...").start();
|
|
10882
11504
|
try {
|
|
10883
|
-
const result = await vercel.deploy(process.cwd(), prod && !
|
|
11505
|
+
const result = await vercel.deploy(process.cwd(), prod && !p8.isCancel(prod));
|
|
10884
11506
|
spinner.stop();
|
|
10885
11507
|
showSuccess(`Deployed: ${result.url}`);
|
|
10886
11508
|
} catch (error) {
|
|
@@ -10890,11 +11512,11 @@ async function deployProject(ctx) {
|
|
|
10890
11512
|
}
|
|
10891
11513
|
async function reviewCodebase(ctx) {
|
|
10892
11514
|
const { ai } = ctx;
|
|
10893
|
-
const includeAI = await
|
|
11515
|
+
const includeAI = await p8.confirm({
|
|
10894
11516
|
message: "Include AI deep analysis? (slower but more thorough)",
|
|
10895
11517
|
initialValue: true
|
|
10896
11518
|
});
|
|
10897
|
-
if (
|
|
11519
|
+
if (p8.isCancel(includeAI)) return;
|
|
10898
11520
|
const analyzer = new CodebaseAnalyzer(
|
|
10899
11521
|
process.cwd(),
|
|
10900
11522
|
includeAI ? ai : void 0
|
|
@@ -10908,11 +11530,11 @@ async function reviewCodebase(ctx) {
|
|
|
10908
11530
|
const formatted = analyzer.formatReport(report);
|
|
10909
11531
|
console.log(formatted);
|
|
10910
11532
|
if (report.byCategory.patterns.length > 0) {
|
|
10911
|
-
const fix = await
|
|
11533
|
+
const fix = await p8.confirm({
|
|
10912
11534
|
message: `Fix ${report.byCategory.patterns.length} pattern violations automatically?`,
|
|
10913
11535
|
initialValue: false
|
|
10914
11536
|
});
|
|
10915
|
-
if (fix && !
|
|
11537
|
+
if (fix && !p8.isCancel(fix)) {
|
|
10916
11538
|
showInfo("Use `/fix` command to auto-fix pattern violations (coming soon)");
|
|
10917
11539
|
}
|
|
10918
11540
|
}
|
|
@@ -10925,7 +11547,7 @@ async function runSetup(config) {
|
|
|
10925
11547
|
console.log("");
|
|
10926
11548
|
console.log(colors.white(" Setup CodeBakers CLI"));
|
|
10927
11549
|
divider();
|
|
10928
|
-
const apiKey = await
|
|
11550
|
+
const apiKey = await p8.text({
|
|
10929
11551
|
message: "Anthropic API key:",
|
|
10930
11552
|
placeholder: "sk-ant-...",
|
|
10931
11553
|
validate: (value) => {
|
|
@@ -10933,30 +11555,30 @@ async function runSetup(config) {
|
|
|
10933
11555
|
if (!value.startsWith("sk-ant-")) return "Invalid format";
|
|
10934
11556
|
}
|
|
10935
11557
|
});
|
|
10936
|
-
if (
|
|
11558
|
+
if (p8.isCancel(apiKey)) return;
|
|
10937
11559
|
config.setAnthropicKey(apiKey);
|
|
10938
|
-
const setupGithub = await
|
|
11560
|
+
const setupGithub = await p8.confirm({
|
|
10939
11561
|
message: "Set up GitHub token? (optional)",
|
|
10940
11562
|
initialValue: false
|
|
10941
11563
|
});
|
|
10942
|
-
if (setupGithub && !
|
|
10943
|
-
const token = await
|
|
11564
|
+
if (setupGithub && !p8.isCancel(setupGithub)) {
|
|
11565
|
+
const token = await p8.text({
|
|
10944
11566
|
message: "GitHub token:",
|
|
10945
11567
|
placeholder: "ghp_..."
|
|
10946
11568
|
});
|
|
10947
|
-
if (!
|
|
11569
|
+
if (!p8.isCancel(token) && token) {
|
|
10948
11570
|
config.setGithubToken(token);
|
|
10949
11571
|
}
|
|
10950
11572
|
}
|
|
10951
|
-
const setupVercel = await
|
|
11573
|
+
const setupVercel = await p8.confirm({
|
|
10952
11574
|
message: "Set up Vercel token? (optional)",
|
|
10953
11575
|
initialValue: false
|
|
10954
11576
|
});
|
|
10955
|
-
if (setupVercel && !
|
|
10956
|
-
const token = await
|
|
11577
|
+
if (setupVercel && !p8.isCancel(setupVercel)) {
|
|
11578
|
+
const token = await p8.text({
|
|
10957
11579
|
message: "Vercel token:"
|
|
10958
11580
|
});
|
|
10959
|
-
if (!
|
|
11581
|
+
if (!p8.isCancel(token) && token) {
|
|
10960
11582
|
config.setVercelToken(token);
|
|
10961
11583
|
}
|
|
10962
11584
|
}
|