@codebakers/cli 3.8.7 → 3.8.9
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/commands/go.d.ts +8 -0
- package/dist/commands/go.js +286 -29
- package/dist/index.js +12 -1
- package/package.json +1 -1
- package/src/commands/go.ts +328 -32
- package/src/index.ts +12 -1
package/dist/commands/go.d.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
interface GoOptions {
|
|
2
2
|
verbose?: boolean;
|
|
3
|
+
type?: 'personal' | 'client' | 'business';
|
|
4
|
+
name?: string;
|
|
5
|
+
describe?: 'guided' | 'template' | 'paste' | 'chat' | 'files';
|
|
6
|
+
skipReview?: boolean;
|
|
3
7
|
}
|
|
4
8
|
/**
|
|
5
9
|
* Zero-friction entry point - start using CodeBakers instantly
|
|
6
10
|
* Single command for both trial and paid users
|
|
11
|
+
*
|
|
12
|
+
* SMART BEHAVIOR:
|
|
13
|
+
* - If CodeBakers already set up → Show context and resume from where you left off
|
|
14
|
+
* - If not set up → Run first-time setup (trial or login)
|
|
7
15
|
*/
|
|
8
16
|
export declare function go(options?: GoOptions): Promise<void>;
|
|
9
17
|
export {};
|
package/dist/commands/go.js
CHANGED
|
@@ -709,6 +709,190 @@ function updateGitignore(cwd) {
|
|
|
709
709
|
}
|
|
710
710
|
}
|
|
711
711
|
}
|
|
712
|
+
function analyzeProjectState(cwd) {
|
|
713
|
+
const state = {
|
|
714
|
+
isSetUp: false,
|
|
715
|
+
hasPrd: false,
|
|
716
|
+
inProgressTasks: [],
|
|
717
|
+
completedTasks: [],
|
|
718
|
+
blockers: [],
|
|
719
|
+
suggestion: '',
|
|
720
|
+
};
|
|
721
|
+
// Check if CodeBakers is set up
|
|
722
|
+
const codebakersJsonPath = (0, path_1.join)(cwd, '.codebakers.json');
|
|
723
|
+
if (!(0, fs_1.existsSync)(codebakersJsonPath)) {
|
|
724
|
+
state.suggestion = 'Project not set up. Running first-time setup...';
|
|
725
|
+
return state;
|
|
726
|
+
}
|
|
727
|
+
state.isSetUp = true;
|
|
728
|
+
// Read .codebakers.json
|
|
729
|
+
try {
|
|
730
|
+
const cbState = JSON.parse((0, fs_1.readFileSync)(codebakersJsonPath, 'utf-8'));
|
|
731
|
+
state.projectName = cbState.projectName;
|
|
732
|
+
state.projectType = cbState.projectType;
|
|
733
|
+
}
|
|
734
|
+
catch {
|
|
735
|
+
// Ignore parse errors
|
|
736
|
+
}
|
|
737
|
+
// Check for PRD.md
|
|
738
|
+
const prdPath = (0, path_1.join)(cwd, 'PRD.md');
|
|
739
|
+
if ((0, fs_1.existsSync)(prdPath)) {
|
|
740
|
+
state.hasPrd = true;
|
|
741
|
+
try {
|
|
742
|
+
const prdContent = (0, fs_1.readFileSync)(prdPath, 'utf-8');
|
|
743
|
+
// Extract one-liner if present
|
|
744
|
+
const oneLineMatch = prdContent.match(/\*\*One-liner:\*\*\s*(.+)/);
|
|
745
|
+
if (oneLineMatch) {
|
|
746
|
+
state.prdSummary = oneLineMatch[1].trim();
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
// Get first non-comment, non-header line
|
|
750
|
+
const lines = prdContent.split('\n').filter(l => l.trim() && !l.startsWith('#') && !l.startsWith('<!--'));
|
|
751
|
+
if (lines[0]) {
|
|
752
|
+
state.prdSummary = lines[0].substring(0, 100);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
catch {
|
|
757
|
+
// Ignore read errors
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
// Read PROJECT-STATE.md for tasks
|
|
761
|
+
const projectStatePath = (0, path_1.join)(cwd, 'PROJECT-STATE.md');
|
|
762
|
+
if ((0, fs_1.existsSync)(projectStatePath)) {
|
|
763
|
+
try {
|
|
764
|
+
const content = (0, fs_1.readFileSync)(projectStatePath, 'utf-8');
|
|
765
|
+
// Extract In Progress section
|
|
766
|
+
const inProgressMatch = content.match(/## In Progress\n([\s\S]*?)(?=\n##|$)/);
|
|
767
|
+
if (inProgressMatch) {
|
|
768
|
+
const lines = inProgressMatch[1].split('\n')
|
|
769
|
+
.filter(l => l.trim().startsWith('-'))
|
|
770
|
+
.map(l => l.replace(/^-\s*/, '').trim())
|
|
771
|
+
.filter(l => l && !l.startsWith('<!--'));
|
|
772
|
+
state.inProgressTasks = lines;
|
|
773
|
+
}
|
|
774
|
+
// Extract Completed section (last 5)
|
|
775
|
+
const completedMatch = content.match(/## Completed\n([\s\S]*?)(?=\n##|$)/);
|
|
776
|
+
if (completedMatch) {
|
|
777
|
+
const lines = completedMatch[1].split('\n')
|
|
778
|
+
.filter(l => l.trim().startsWith('-'))
|
|
779
|
+
.map(l => l.replace(/^-\s*/, '').trim())
|
|
780
|
+
.filter(l => l && !l.startsWith('<!--'));
|
|
781
|
+
state.completedTasks = lines.slice(-5);
|
|
782
|
+
}
|
|
783
|
+
// Extract Blockers section
|
|
784
|
+
const blockersMatch = content.match(/## Blockers\n([\s\S]*?)(?=\n##|$)/);
|
|
785
|
+
if (blockersMatch) {
|
|
786
|
+
const lines = blockersMatch[1].split('\n')
|
|
787
|
+
.filter(l => l.trim().startsWith('-'))
|
|
788
|
+
.map(l => l.replace(/^-\s*/, '').trim())
|
|
789
|
+
.filter(l => l && !l.startsWith('<!--'));
|
|
790
|
+
state.blockers = lines;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
catch {
|
|
794
|
+
// Ignore read errors
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
// Read DEVLOG for last session
|
|
798
|
+
const devlogPath = (0, path_1.join)(cwd, '.codebakers', 'DEVLOG.md');
|
|
799
|
+
if ((0, fs_1.existsSync)(devlogPath)) {
|
|
800
|
+
try {
|
|
801
|
+
const content = (0, fs_1.readFileSync)(devlogPath, 'utf-8');
|
|
802
|
+
// Get first session entry
|
|
803
|
+
const sessionMatch = content.match(/## .+?\n\*\*Session:\*\*\s*(.+)/);
|
|
804
|
+
if (sessionMatch) {
|
|
805
|
+
state.lastSession = sessionMatch[1].trim();
|
|
806
|
+
}
|
|
807
|
+
// Get "What was done" from most recent entry
|
|
808
|
+
const whatDoneMatch = content.match(/### What was done:\n([\s\S]*?)(?=\n###|---|\n\n)/);
|
|
809
|
+
if (whatDoneMatch && !state.lastSession) {
|
|
810
|
+
const lines = whatDoneMatch[1].split('\n')
|
|
811
|
+
.filter(l => l.trim().startsWith('-'))
|
|
812
|
+
.map(l => l.replace(/^-\s*/, '').trim());
|
|
813
|
+
if (lines[0]) {
|
|
814
|
+
state.lastSession = lines[0];
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
catch {
|
|
819
|
+
// Ignore read errors
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
// Determine suggestion based on state
|
|
823
|
+
if (state.blockers.length > 0) {
|
|
824
|
+
state.suggestion = `BLOCKED: ${state.blockers[0]}. Address this blocker first.`;
|
|
825
|
+
}
|
|
826
|
+
else if (state.inProgressTasks.length > 0) {
|
|
827
|
+
state.suggestion = `CONTINUE: ${state.inProgressTasks[0]}`;
|
|
828
|
+
}
|
|
829
|
+
else if (state.hasPrd && state.completedTasks.length === 0) {
|
|
830
|
+
state.suggestion = `START BUILDING: PRD exists. Begin implementing features from PRD.md`;
|
|
831
|
+
}
|
|
832
|
+
else if (!state.hasPrd) {
|
|
833
|
+
state.suggestion = `DEFINE PROJECT: No PRD found. Describe what you want to build.`;
|
|
834
|
+
}
|
|
835
|
+
else {
|
|
836
|
+
state.suggestion = `READY: Project set up. Ask for the next feature to build.`;
|
|
837
|
+
}
|
|
838
|
+
return state;
|
|
839
|
+
}
|
|
840
|
+
function showResumeContext(state) {
|
|
841
|
+
console.log(chalk_1.default.blue(`
|
|
842
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
843
|
+
║ ║
|
|
844
|
+
║ ${chalk_1.default.bold.white('CodeBakers - Resuming Session')} ║
|
|
845
|
+
║ ║
|
|
846
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
847
|
+
`));
|
|
848
|
+
console.log(chalk_1.default.white(` 📁 Project: ${chalk_1.default.cyan(state.projectName || 'Unknown')}`));
|
|
849
|
+
if (state.prdSummary) {
|
|
850
|
+
console.log(chalk_1.default.gray(` 📝 ${state.prdSummary}`));
|
|
851
|
+
}
|
|
852
|
+
console.log('');
|
|
853
|
+
// Show blockers first (critical)
|
|
854
|
+
if (state.blockers.length > 0) {
|
|
855
|
+
console.log(chalk_1.default.red(' ⚠️ BLOCKERS:'));
|
|
856
|
+
for (const blocker of state.blockers) {
|
|
857
|
+
console.log(chalk_1.default.red(` • ${blocker}`));
|
|
858
|
+
}
|
|
859
|
+
console.log('');
|
|
860
|
+
}
|
|
861
|
+
// Show in-progress tasks
|
|
862
|
+
if (state.inProgressTasks.length > 0) {
|
|
863
|
+
console.log(chalk_1.default.yellow(' 🔄 IN PROGRESS:'));
|
|
864
|
+
for (const task of state.inProgressTasks) {
|
|
865
|
+
console.log(chalk_1.default.yellow(` • ${task}`));
|
|
866
|
+
}
|
|
867
|
+
console.log('');
|
|
868
|
+
}
|
|
869
|
+
// Show recent completed (context)
|
|
870
|
+
if (state.completedTasks.length > 0) {
|
|
871
|
+
console.log(chalk_1.default.green(' ✓ RECENTLY COMPLETED:'));
|
|
872
|
+
for (const task of state.completedTasks.slice(-3)) {
|
|
873
|
+
console.log(chalk_1.default.gray(` • ${task}`));
|
|
874
|
+
}
|
|
875
|
+
console.log('');
|
|
876
|
+
}
|
|
877
|
+
// Show last session timestamp if available
|
|
878
|
+
if (state.lastSession) {
|
|
879
|
+
console.log(chalk_1.default.gray(` 📅 Last session: ${state.lastSession}`));
|
|
880
|
+
console.log('');
|
|
881
|
+
}
|
|
882
|
+
// Show the suggestion prominently
|
|
883
|
+
console.log(chalk_1.default.cyan(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
884
|
+
console.log(chalk_1.default.white.bold(`\n → ${state.suggestion}\n`));
|
|
885
|
+
console.log(chalk_1.default.cyan(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
886
|
+
// Output machine-readable context for AI
|
|
887
|
+
console.log(chalk_1.default.gray(' [AI Context]'));
|
|
888
|
+
console.log(chalk_1.default.gray(` Project: ${state.projectName || 'Unknown'}`));
|
|
889
|
+
console.log(chalk_1.default.gray(` Status: ${state.inProgressTasks.length > 0 ? 'IN_PROGRESS' : state.blockers.length > 0 ? 'BLOCKED' : 'READY'}`));
|
|
890
|
+
console.log(chalk_1.default.gray(` Next Action: ${state.suggestion}`));
|
|
891
|
+
if (state.hasPrd) {
|
|
892
|
+
console.log(chalk_1.default.gray(` PRD: Available at PRD.md`));
|
|
893
|
+
}
|
|
894
|
+
console.log('');
|
|
895
|
+
}
|
|
712
896
|
/**
|
|
713
897
|
* Get CLI version from package.json
|
|
714
898
|
*/
|
|
@@ -754,11 +938,42 @@ function log(message, options) {
|
|
|
754
938
|
/**
|
|
755
939
|
* Zero-friction entry point - start using CodeBakers instantly
|
|
756
940
|
* Single command for both trial and paid users
|
|
941
|
+
*
|
|
942
|
+
* SMART BEHAVIOR:
|
|
943
|
+
* - If CodeBakers already set up → Show context and resume from where you left off
|
|
944
|
+
* - If not set up → Run first-time setup (trial or login)
|
|
757
945
|
*/
|
|
758
946
|
async function go(options = {}) {
|
|
759
947
|
log('Starting go command...', options);
|
|
760
948
|
log(`API URL: ${(0, config_js_1.getApiUrl)()}`, options);
|
|
761
949
|
log(`Working directory: ${process.cwd()}`, options);
|
|
950
|
+
const cwd = process.cwd();
|
|
951
|
+
// =========================================================================
|
|
952
|
+
// SMART CONTEXT CHECK - If already set up, show resume context
|
|
953
|
+
// =========================================================================
|
|
954
|
+
const projectState = analyzeProjectState(cwd);
|
|
955
|
+
if (projectState.isSetUp) {
|
|
956
|
+
// Project already has CodeBakers - show context and resume
|
|
957
|
+
showResumeContext(projectState);
|
|
958
|
+
// Verify auth is still valid
|
|
959
|
+
const existingApiKey = (0, config_js_1.getApiKey)();
|
|
960
|
+
const existingTrial = (0, config_js_1.getTrialState)();
|
|
961
|
+
if (existingApiKey) {
|
|
962
|
+
console.log(chalk_1.default.green(' ✓ Authenticated (API key)\n'));
|
|
963
|
+
}
|
|
964
|
+
else if (existingTrial && !(0, config_js_1.isTrialExpired)()) {
|
|
965
|
+
const daysRemaining = (0, config_js_1.getTrialDaysRemaining)();
|
|
966
|
+
console.log(chalk_1.default.green(` ✓ Trial active (${daysRemaining} days remaining)\n`));
|
|
967
|
+
}
|
|
968
|
+
else if (existingTrial && (0, config_js_1.isTrialExpired)()) {
|
|
969
|
+
console.log(chalk_1.default.yellow(' ⚠️ Trial expired. Run `codebakers extend` or login.\n'));
|
|
970
|
+
}
|
|
971
|
+
// Don't run setup again - just show context
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
// =========================================================================
|
|
975
|
+
// FIRST-TIME SETUP - Project not yet configured
|
|
976
|
+
// =========================================================================
|
|
762
977
|
console.log(chalk_1.default.blue(`
|
|
763
978
|
╔═══════════════════════════════════════════════════════════╗
|
|
764
979
|
║ ║
|
|
@@ -1113,19 +1328,29 @@ async function setupProject(options = {}, auth) {
|
|
|
1113
1328
|
}
|
|
1114
1329
|
async function setupNewProject(cwd, options = {}, auth) {
|
|
1115
1330
|
console.log(chalk_1.default.cyan('\n ━━━ New Project Setup ━━━\n'));
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('PERSONAL') + chalk_1.default.gray(' - Just building for myself'));
|
|
1119
|
-
console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('CLIENT') + chalk_1.default.gray(' - Building for someone else'));
|
|
1120
|
-
console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('BUSINESS') + chalk_1.default.gray(' - My own product/startup\n'));
|
|
1121
|
-
let typeChoice = '';
|
|
1122
|
-
while (!['1', '2', '3'].includes(typeChoice)) {
|
|
1123
|
-
typeChoice = await prompt(' Enter 1, 2, or 3: ');
|
|
1124
|
-
}
|
|
1125
|
-
const typeMap = { '1': 'personal', '2': 'client', '3': 'business' };
|
|
1126
|
-
const projectType = typeMap[typeChoice];
|
|
1331
|
+
let projectType;
|
|
1332
|
+
let projectName;
|
|
1127
1333
|
const defaultName = cwd.split(/[\\/]/).pop() || 'my-project';
|
|
1128
|
-
|
|
1334
|
+
// Use flags if provided (non-interactive mode for AI)
|
|
1335
|
+
if (options.type) {
|
|
1336
|
+
projectType = options.type;
|
|
1337
|
+
projectName = options.name || defaultName;
|
|
1338
|
+
console.log(chalk_1.default.green(` Using: ${projectType.toUpperCase()} project named "${projectName}"\n`));
|
|
1339
|
+
}
|
|
1340
|
+
else {
|
|
1341
|
+
// Interactive mode - ask questions
|
|
1342
|
+
console.log(chalk_1.default.white(' What kind of project is this?\n'));
|
|
1343
|
+
console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('PERSONAL') + chalk_1.default.gray(' - Just building for myself'));
|
|
1344
|
+
console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('CLIENT') + chalk_1.default.gray(' - Building for someone else'));
|
|
1345
|
+
console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('BUSINESS') + chalk_1.default.gray(' - My own product/startup\n'));
|
|
1346
|
+
let typeChoice = '';
|
|
1347
|
+
while (!['1', '2', '3'].includes(typeChoice)) {
|
|
1348
|
+
typeChoice = await prompt(' Enter 1, 2, or 3: ');
|
|
1349
|
+
}
|
|
1350
|
+
const typeMap = { '1': 'personal', '2': 'client', '3': 'business' };
|
|
1351
|
+
projectType = typeMap[typeChoice];
|
|
1352
|
+
projectName = await prompt(` Project name (${defaultName}): `) || defaultName;
|
|
1353
|
+
}
|
|
1129
1354
|
console.log(chalk_1.default.green(`\n ✓ Setting up "${projectName}" as ${projectType.toUpperCase()} project\n`));
|
|
1130
1355
|
// Install bootstrap files
|
|
1131
1356
|
console.log(chalk_1.default.white(' Installing CodeBakers...\n'));
|
|
@@ -1140,15 +1365,26 @@ async function setupNewProject(cwd, options = {}, auth) {
|
|
|
1140
1365
|
// Update .gitignore
|
|
1141
1366
|
updateGitignore(cwd);
|
|
1142
1367
|
// How to describe project
|
|
1143
|
-
console.log(chalk_1.default.white('\n 📝 How would you like to describe your project?\n'));
|
|
1144
|
-
console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('GUIDED QUESTIONS') + chalk_1.default.gray(' - I\'ll ask you step by step'));
|
|
1145
|
-
console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('WRITE A PRD') + chalk_1.default.gray(' - Create a blank template to fill out'));
|
|
1146
|
-
console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('PASTE/UPLOAD PRD') + chalk_1.default.gray(' - I already have requirements written'));
|
|
1147
|
-
console.log(chalk_1.default.gray(' 4. ') + chalk_1.default.cyan('DESCRIBE IN CHAT') + chalk_1.default.gray(' - Just tell the AI what you want'));
|
|
1148
|
-
console.log(chalk_1.default.gray(' 5. ') + chalk_1.default.cyan('SHARE FILES') + chalk_1.default.gray(' - I\'ll share docs/mockups/screenshots\n'));
|
|
1149
1368
|
let describeChoice = '';
|
|
1150
|
-
|
|
1151
|
-
|
|
1369
|
+
// Use flag if provided (non-interactive mode for AI)
|
|
1370
|
+
if (options.describe) {
|
|
1371
|
+
const describeMap = {
|
|
1372
|
+
'guided': '1', 'template': '2', 'paste': '3', 'chat': '4', 'files': '5'
|
|
1373
|
+
};
|
|
1374
|
+
describeChoice = describeMap[options.describe] || '4';
|
|
1375
|
+
console.log(chalk_1.default.green(` Using: ${options.describe} mode for project description\n`));
|
|
1376
|
+
}
|
|
1377
|
+
else {
|
|
1378
|
+
// Interactive mode
|
|
1379
|
+
console.log(chalk_1.default.white('\n 📝 How would you like to describe your project?\n'));
|
|
1380
|
+
console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('GUIDED QUESTIONS') + chalk_1.default.gray(' - I\'ll ask you step by step'));
|
|
1381
|
+
console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('WRITE A PRD') + chalk_1.default.gray(' - Create a blank template to fill out'));
|
|
1382
|
+
console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('PASTE/UPLOAD PRD') + chalk_1.default.gray(' - I already have requirements written'));
|
|
1383
|
+
console.log(chalk_1.default.gray(' 4. ') + chalk_1.default.cyan('DESCRIBE IN CHAT') + chalk_1.default.gray(' - Just tell the AI what you want'));
|
|
1384
|
+
console.log(chalk_1.default.gray(' 5. ') + chalk_1.default.cyan('SHARE FILES') + chalk_1.default.gray(' - I\'ll share docs/mockups/screenshots\n'));
|
|
1385
|
+
while (!['1', '2', '3', '4', '5'].includes(describeChoice)) {
|
|
1386
|
+
describeChoice = await prompt(' Enter 1-5: ');
|
|
1387
|
+
}
|
|
1152
1388
|
}
|
|
1153
1389
|
let prdCreated = false;
|
|
1154
1390
|
if (describeChoice === '1') {
|
|
@@ -1244,15 +1480,36 @@ async function setupExistingProject(cwd, projectInfo, options = {}, auth) {
|
|
|
1244
1480
|
}
|
|
1245
1481
|
// Get project name
|
|
1246
1482
|
const defaultName = cwd.split(/[\\/]/).pop() || 'my-project';
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1483
|
+
let projectName;
|
|
1484
|
+
let reviewChoice;
|
|
1485
|
+
// Use flags if provided (non-interactive mode for AI)
|
|
1486
|
+
if (options.name) {
|
|
1487
|
+
projectName = options.name;
|
|
1488
|
+
console.log(chalk_1.default.green(`\n Using project name: "${projectName}"\n`));
|
|
1489
|
+
}
|
|
1490
|
+
else {
|
|
1491
|
+
projectName = await prompt(`\n Project name (${defaultName}): `) || defaultName;
|
|
1492
|
+
}
|
|
1493
|
+
// Use skipReview flag or ask
|
|
1494
|
+
if (options.skipReview) {
|
|
1495
|
+
reviewChoice = '3';
|
|
1496
|
+
console.log(chalk_1.default.gray(' Skipping code review (--skip-review flag)\n'));
|
|
1497
|
+
}
|
|
1498
|
+
else if (options.type) {
|
|
1499
|
+
// If running in non-interactive mode, default to skip review
|
|
1500
|
+
reviewChoice = '3';
|
|
1501
|
+
console.log(chalk_1.default.gray(' Skipping code review (non-interactive mode)\n'));
|
|
1502
|
+
}
|
|
1503
|
+
else {
|
|
1504
|
+
// Interactive mode - ask about code review
|
|
1505
|
+
console.log(chalk_1.default.white('\n Want me to review your code and bring it up to CodeBakers standards?\n'));
|
|
1506
|
+
console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('YES, REVIEW & FIX') + chalk_1.default.gray(' - Run audit, then auto-fix issues'));
|
|
1507
|
+
console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('REVIEW ONLY') + chalk_1.default.gray(' - Just show me the issues'));
|
|
1508
|
+
console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('SKIP') + chalk_1.default.gray(' - Just install CodeBakers\n'));
|
|
1509
|
+
reviewChoice = '';
|
|
1510
|
+
while (!['1', '2', '3'].includes(reviewChoice)) {
|
|
1511
|
+
reviewChoice = await prompt(' Enter 1, 2, or 3: ');
|
|
1512
|
+
}
|
|
1256
1513
|
}
|
|
1257
1514
|
let auditScore;
|
|
1258
1515
|
if (reviewChoice !== '3') {
|
package/dist/index.js
CHANGED
|
@@ -202,7 +202,18 @@ program
|
|
|
202
202
|
.alias('start')
|
|
203
203
|
.description('Start using CodeBakers instantly (no signup required)')
|
|
204
204
|
.option('-v, --verbose', 'Show detailed debug output for troubleshooting')
|
|
205
|
-
|
|
205
|
+
// Non-interactive flags for programmatic use (e.g., by AI assistants)
|
|
206
|
+
.option('-t, --type <type>', 'Project type: personal, client, or business')
|
|
207
|
+
.option('-n, --name <name>', 'Project name')
|
|
208
|
+
.option('-d, --describe <mode>', 'Description mode: guided, template, paste, chat, or files')
|
|
209
|
+
.option('--skip-review', 'Skip the review question for existing projects')
|
|
210
|
+
.action((options) => (0, go_js_1.go)({
|
|
211
|
+
verbose: options.verbose,
|
|
212
|
+
type: options.type,
|
|
213
|
+
name: options.name,
|
|
214
|
+
describe: options.describe,
|
|
215
|
+
skipReview: options.skipReview,
|
|
216
|
+
}));
|
|
206
217
|
program
|
|
207
218
|
.command('extend')
|
|
208
219
|
.description('Extend your free trial with GitHub')
|
package/package.json
CHANGED
package/src/commands/go.ts
CHANGED
|
@@ -771,6 +771,227 @@ function updateGitignore(cwd: string): void {
|
|
|
771
771
|
|
|
772
772
|
interface GoOptions {
|
|
773
773
|
verbose?: boolean;
|
|
774
|
+
// Non-interactive flags for programmatic use (e.g., by AI assistants)
|
|
775
|
+
type?: 'personal' | 'client' | 'business';
|
|
776
|
+
name?: string;
|
|
777
|
+
describe?: 'guided' | 'template' | 'paste' | 'chat' | 'files';
|
|
778
|
+
skipReview?: boolean;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// ============================================================================
|
|
782
|
+
// SMART CONTEXT DETECTION - "Where am I? What's next?"
|
|
783
|
+
// ============================================================================
|
|
784
|
+
|
|
785
|
+
interface ProjectState {
|
|
786
|
+
isSetUp: boolean;
|
|
787
|
+
projectName?: string;
|
|
788
|
+
projectType?: string;
|
|
789
|
+
hasPrd: boolean;
|
|
790
|
+
prdSummary?: string;
|
|
791
|
+
inProgressTasks: string[];
|
|
792
|
+
completedTasks: string[];
|
|
793
|
+
blockers: string[];
|
|
794
|
+
lastSession?: string;
|
|
795
|
+
suggestion: string;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function analyzeProjectState(cwd: string): ProjectState {
|
|
799
|
+
const state: ProjectState = {
|
|
800
|
+
isSetUp: false,
|
|
801
|
+
hasPrd: false,
|
|
802
|
+
inProgressTasks: [],
|
|
803
|
+
completedTasks: [],
|
|
804
|
+
blockers: [],
|
|
805
|
+
suggestion: '',
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
// Check if CodeBakers is set up
|
|
809
|
+
const codebakersJsonPath = join(cwd, '.codebakers.json');
|
|
810
|
+
if (!existsSync(codebakersJsonPath)) {
|
|
811
|
+
state.suggestion = 'Project not set up. Running first-time setup...';
|
|
812
|
+
return state;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
state.isSetUp = true;
|
|
816
|
+
|
|
817
|
+
// Read .codebakers.json
|
|
818
|
+
try {
|
|
819
|
+
const cbState = JSON.parse(readFileSync(codebakersJsonPath, 'utf-8'));
|
|
820
|
+
state.projectName = cbState.projectName;
|
|
821
|
+
state.projectType = cbState.projectType;
|
|
822
|
+
} catch {
|
|
823
|
+
// Ignore parse errors
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// Check for PRD.md
|
|
827
|
+
const prdPath = join(cwd, 'PRD.md');
|
|
828
|
+
if (existsSync(prdPath)) {
|
|
829
|
+
state.hasPrd = true;
|
|
830
|
+
try {
|
|
831
|
+
const prdContent = readFileSync(prdPath, 'utf-8');
|
|
832
|
+
// Extract one-liner if present
|
|
833
|
+
const oneLineMatch = prdContent.match(/\*\*One-liner:\*\*\s*(.+)/);
|
|
834
|
+
if (oneLineMatch) {
|
|
835
|
+
state.prdSummary = oneLineMatch[1].trim();
|
|
836
|
+
} else {
|
|
837
|
+
// Get first non-comment, non-header line
|
|
838
|
+
const lines = prdContent.split('\n').filter(l =>
|
|
839
|
+
l.trim() && !l.startsWith('#') && !l.startsWith('<!--')
|
|
840
|
+
);
|
|
841
|
+
if (lines[0]) {
|
|
842
|
+
state.prdSummary = lines[0].substring(0, 100);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
} catch {
|
|
846
|
+
// Ignore read errors
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Read PROJECT-STATE.md for tasks
|
|
851
|
+
const projectStatePath = join(cwd, 'PROJECT-STATE.md');
|
|
852
|
+
if (existsSync(projectStatePath)) {
|
|
853
|
+
try {
|
|
854
|
+
const content = readFileSync(projectStatePath, 'utf-8');
|
|
855
|
+
|
|
856
|
+
// Extract In Progress section
|
|
857
|
+
const inProgressMatch = content.match(/## In Progress\n([\s\S]*?)(?=\n##|$)/);
|
|
858
|
+
if (inProgressMatch) {
|
|
859
|
+
const lines = inProgressMatch[1].split('\n')
|
|
860
|
+
.filter(l => l.trim().startsWith('-'))
|
|
861
|
+
.map(l => l.replace(/^-\s*/, '').trim())
|
|
862
|
+
.filter(l => l && !l.startsWith('<!--'));
|
|
863
|
+
state.inProgressTasks = lines;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// Extract Completed section (last 5)
|
|
867
|
+
const completedMatch = content.match(/## Completed\n([\s\S]*?)(?=\n##|$)/);
|
|
868
|
+
if (completedMatch) {
|
|
869
|
+
const lines = completedMatch[1].split('\n')
|
|
870
|
+
.filter(l => l.trim().startsWith('-'))
|
|
871
|
+
.map(l => l.replace(/^-\s*/, '').trim())
|
|
872
|
+
.filter(l => l && !l.startsWith('<!--'));
|
|
873
|
+
state.completedTasks = lines.slice(-5);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// Extract Blockers section
|
|
877
|
+
const blockersMatch = content.match(/## Blockers\n([\s\S]*?)(?=\n##|$)/);
|
|
878
|
+
if (blockersMatch) {
|
|
879
|
+
const lines = blockersMatch[1].split('\n')
|
|
880
|
+
.filter(l => l.trim().startsWith('-'))
|
|
881
|
+
.map(l => l.replace(/^-\s*/, '').trim())
|
|
882
|
+
.filter(l => l && !l.startsWith('<!--'));
|
|
883
|
+
state.blockers = lines;
|
|
884
|
+
}
|
|
885
|
+
} catch {
|
|
886
|
+
// Ignore read errors
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// Read DEVLOG for last session
|
|
891
|
+
const devlogPath = join(cwd, '.codebakers', 'DEVLOG.md');
|
|
892
|
+
if (existsSync(devlogPath)) {
|
|
893
|
+
try {
|
|
894
|
+
const content = readFileSync(devlogPath, 'utf-8');
|
|
895
|
+
// Get first session entry
|
|
896
|
+
const sessionMatch = content.match(/## .+?\n\*\*Session:\*\*\s*(.+)/);
|
|
897
|
+
if (sessionMatch) {
|
|
898
|
+
state.lastSession = sessionMatch[1].trim();
|
|
899
|
+
}
|
|
900
|
+
// Get "What was done" from most recent entry
|
|
901
|
+
const whatDoneMatch = content.match(/### What was done:\n([\s\S]*?)(?=\n###|---|\n\n)/);
|
|
902
|
+
if (whatDoneMatch && !state.lastSession) {
|
|
903
|
+
const lines = whatDoneMatch[1].split('\n')
|
|
904
|
+
.filter(l => l.trim().startsWith('-'))
|
|
905
|
+
.map(l => l.replace(/^-\s*/, '').trim());
|
|
906
|
+
if (lines[0]) {
|
|
907
|
+
state.lastSession = lines[0];
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
} catch {
|
|
911
|
+
// Ignore read errors
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
// Determine suggestion based on state
|
|
916
|
+
if (state.blockers.length > 0) {
|
|
917
|
+
state.suggestion = `BLOCKED: ${state.blockers[0]}. Address this blocker first.`;
|
|
918
|
+
} else if (state.inProgressTasks.length > 0) {
|
|
919
|
+
state.suggestion = `CONTINUE: ${state.inProgressTasks[0]}`;
|
|
920
|
+
} else if (state.hasPrd && state.completedTasks.length === 0) {
|
|
921
|
+
state.suggestion = `START BUILDING: PRD exists. Begin implementing features from PRD.md`;
|
|
922
|
+
} else if (!state.hasPrd) {
|
|
923
|
+
state.suggestion = `DEFINE PROJECT: No PRD found. Describe what you want to build.`;
|
|
924
|
+
} else {
|
|
925
|
+
state.suggestion = `READY: Project set up. Ask for the next feature to build.`;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
return state;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
function showResumeContext(state: ProjectState): void {
|
|
932
|
+
console.log(chalk.blue(`
|
|
933
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
934
|
+
║ ║
|
|
935
|
+
║ ${chalk.bold.white('CodeBakers - Resuming Session')} ║
|
|
936
|
+
║ ║
|
|
937
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
938
|
+
`));
|
|
939
|
+
|
|
940
|
+
console.log(chalk.white(` 📁 Project: ${chalk.cyan(state.projectName || 'Unknown')}`));
|
|
941
|
+
|
|
942
|
+
if (state.prdSummary) {
|
|
943
|
+
console.log(chalk.gray(` 📝 ${state.prdSummary}`));
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
console.log('');
|
|
947
|
+
|
|
948
|
+
// Show blockers first (critical)
|
|
949
|
+
if (state.blockers.length > 0) {
|
|
950
|
+
console.log(chalk.red(' ⚠️ BLOCKERS:'));
|
|
951
|
+
for (const blocker of state.blockers) {
|
|
952
|
+
console.log(chalk.red(` • ${blocker}`));
|
|
953
|
+
}
|
|
954
|
+
console.log('');
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// Show in-progress tasks
|
|
958
|
+
if (state.inProgressTasks.length > 0) {
|
|
959
|
+
console.log(chalk.yellow(' 🔄 IN PROGRESS:'));
|
|
960
|
+
for (const task of state.inProgressTasks) {
|
|
961
|
+
console.log(chalk.yellow(` • ${task}`));
|
|
962
|
+
}
|
|
963
|
+
console.log('');
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// Show recent completed (context)
|
|
967
|
+
if (state.completedTasks.length > 0) {
|
|
968
|
+
console.log(chalk.green(' ✓ RECENTLY COMPLETED:'));
|
|
969
|
+
for (const task of state.completedTasks.slice(-3)) {
|
|
970
|
+
console.log(chalk.gray(` • ${task}`));
|
|
971
|
+
}
|
|
972
|
+
console.log('');
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// Show last session timestamp if available
|
|
976
|
+
if (state.lastSession) {
|
|
977
|
+
console.log(chalk.gray(` 📅 Last session: ${state.lastSession}`));
|
|
978
|
+
console.log('');
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// Show the suggestion prominently
|
|
982
|
+
console.log(chalk.cyan(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
983
|
+
console.log(chalk.white.bold(`\n → ${state.suggestion}\n`));
|
|
984
|
+
console.log(chalk.cyan(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
985
|
+
|
|
986
|
+
// Output machine-readable context for AI
|
|
987
|
+
console.log(chalk.gray(' [AI Context]'));
|
|
988
|
+
console.log(chalk.gray(` Project: ${state.projectName || 'Unknown'}`));
|
|
989
|
+
console.log(chalk.gray(` Status: ${state.inProgressTasks.length > 0 ? 'IN_PROGRESS' : state.blockers.length > 0 ? 'BLOCKED' : 'READY'}`));
|
|
990
|
+
console.log(chalk.gray(` Next Action: ${state.suggestion}`));
|
|
991
|
+
if (state.hasPrd) {
|
|
992
|
+
console.log(chalk.gray(` PRD: Available at PRD.md`));
|
|
993
|
+
}
|
|
994
|
+
console.log('');
|
|
774
995
|
}
|
|
775
996
|
|
|
776
997
|
interface ConfirmData {
|
|
@@ -833,12 +1054,48 @@ function log(message: string, options?: GoOptions): void {
|
|
|
833
1054
|
/**
|
|
834
1055
|
* Zero-friction entry point - start using CodeBakers instantly
|
|
835
1056
|
* Single command for both trial and paid users
|
|
1057
|
+
*
|
|
1058
|
+
* SMART BEHAVIOR:
|
|
1059
|
+
* - If CodeBakers already set up → Show context and resume from where you left off
|
|
1060
|
+
* - If not set up → Run first-time setup (trial or login)
|
|
836
1061
|
*/
|
|
837
1062
|
export async function go(options: GoOptions = {}): Promise<void> {
|
|
838
1063
|
log('Starting go command...', options);
|
|
839
1064
|
log(`API URL: ${getApiUrl()}`, options);
|
|
840
1065
|
log(`Working directory: ${process.cwd()}`, options);
|
|
841
1066
|
|
|
1067
|
+
const cwd = process.cwd();
|
|
1068
|
+
|
|
1069
|
+
// =========================================================================
|
|
1070
|
+
// SMART CONTEXT CHECK - If already set up, show resume context
|
|
1071
|
+
// =========================================================================
|
|
1072
|
+
const projectState = analyzeProjectState(cwd);
|
|
1073
|
+
|
|
1074
|
+
if (projectState.isSetUp) {
|
|
1075
|
+
// Project already has CodeBakers - show context and resume
|
|
1076
|
+
showResumeContext(projectState);
|
|
1077
|
+
|
|
1078
|
+
// Verify auth is still valid
|
|
1079
|
+
const existingApiKey = getApiKey();
|
|
1080
|
+
const existingTrial = getTrialState();
|
|
1081
|
+
|
|
1082
|
+
if (existingApiKey) {
|
|
1083
|
+
console.log(chalk.green(' ✓ Authenticated (API key)\n'));
|
|
1084
|
+
} else if (existingTrial && !isTrialExpired()) {
|
|
1085
|
+
const daysRemaining = getTrialDaysRemaining();
|
|
1086
|
+
console.log(chalk.green(` ✓ Trial active (${daysRemaining} days remaining)\n`));
|
|
1087
|
+
} else if (existingTrial && isTrialExpired()) {
|
|
1088
|
+
console.log(chalk.yellow(' ⚠️ Trial expired. Run `codebakers extend` or login.\n'));
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
// Don't run setup again - just show context
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// =========================================================================
|
|
1096
|
+
// FIRST-TIME SETUP - Project not yet configured
|
|
1097
|
+
// =========================================================================
|
|
1098
|
+
|
|
842
1099
|
console.log(chalk.blue(`
|
|
843
1100
|
╔═══════════════════════════════════════════════════════════╗
|
|
844
1101
|
║ ║
|
|
@@ -1240,22 +1497,31 @@ async function setupProject(options: GoOptions = {}, auth?: AuthInfo): Promise<v
|
|
|
1240
1497
|
async function setupNewProject(cwd: string, options: GoOptions = {}, auth?: AuthInfo): Promise<void> {
|
|
1241
1498
|
console.log(chalk.cyan('\n ━━━ New Project Setup ━━━\n'));
|
|
1242
1499
|
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
console.log(chalk.gray(' 2. ') + chalk.cyan('CLIENT') + chalk.gray(' - Building for someone else'));
|
|
1247
|
-
console.log(chalk.gray(' 3. ') + chalk.cyan('BUSINESS') + chalk.gray(' - My own product/startup\n'));
|
|
1248
|
-
|
|
1249
|
-
let typeChoice = '';
|
|
1250
|
-
while (!['1', '2', '3'].includes(typeChoice)) {
|
|
1251
|
-
typeChoice = await prompt(' Enter 1, 2, or 3: ');
|
|
1252
|
-
}
|
|
1500
|
+
let projectType: string;
|
|
1501
|
+
let projectName: string;
|
|
1502
|
+
const defaultName = cwd.split(/[\\/]/).pop() || 'my-project';
|
|
1253
1503
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1504
|
+
// Use flags if provided (non-interactive mode for AI)
|
|
1505
|
+
if (options.type) {
|
|
1506
|
+
projectType = options.type;
|
|
1507
|
+
projectName = options.name || defaultName;
|
|
1508
|
+
console.log(chalk.green(` Using: ${projectType.toUpperCase()} project named "${projectName}"\n`));
|
|
1509
|
+
} else {
|
|
1510
|
+
// Interactive mode - ask questions
|
|
1511
|
+
console.log(chalk.white(' What kind of project is this?\n'));
|
|
1512
|
+
console.log(chalk.gray(' 1. ') + chalk.cyan('PERSONAL') + chalk.gray(' - Just building for myself'));
|
|
1513
|
+
console.log(chalk.gray(' 2. ') + chalk.cyan('CLIENT') + chalk.gray(' - Building for someone else'));
|
|
1514
|
+
console.log(chalk.gray(' 3. ') + chalk.cyan('BUSINESS') + chalk.gray(' - My own product/startup\n'));
|
|
1515
|
+
|
|
1516
|
+
let typeChoice = '';
|
|
1517
|
+
while (!['1', '2', '3'].includes(typeChoice)) {
|
|
1518
|
+
typeChoice = await prompt(' Enter 1, 2, or 3: ');
|
|
1519
|
+
}
|
|
1256
1520
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1521
|
+
const typeMap: Record<string, string> = { '1': 'personal', '2': 'client', '3': 'business' };
|
|
1522
|
+
projectType = typeMap[typeChoice];
|
|
1523
|
+
projectName = await prompt(` Project name (${defaultName}): `) || defaultName;
|
|
1524
|
+
}
|
|
1259
1525
|
|
|
1260
1526
|
console.log(chalk.green(`\n ✓ Setting up "${projectName}" as ${projectType.toUpperCase()} project\n`));
|
|
1261
1527
|
|
|
@@ -1276,16 +1542,27 @@ async function setupNewProject(cwd: string, options: GoOptions = {}, auth?: Auth
|
|
|
1276
1542
|
updateGitignore(cwd);
|
|
1277
1543
|
|
|
1278
1544
|
// How to describe project
|
|
1279
|
-
console.log(chalk.white('\n 📝 How would you like to describe your project?\n'));
|
|
1280
|
-
console.log(chalk.gray(' 1. ') + chalk.cyan('GUIDED QUESTIONS') + chalk.gray(' - I\'ll ask you step by step'));
|
|
1281
|
-
console.log(chalk.gray(' 2. ') + chalk.cyan('WRITE A PRD') + chalk.gray(' - Create a blank template to fill out'));
|
|
1282
|
-
console.log(chalk.gray(' 3. ') + chalk.cyan('PASTE/UPLOAD PRD') + chalk.gray(' - I already have requirements written'));
|
|
1283
|
-
console.log(chalk.gray(' 4. ') + chalk.cyan('DESCRIBE IN CHAT') + chalk.gray(' - Just tell the AI what you want'));
|
|
1284
|
-
console.log(chalk.gray(' 5. ') + chalk.cyan('SHARE FILES') + chalk.gray(' - I\'ll share docs/mockups/screenshots\n'));
|
|
1285
|
-
|
|
1286
1545
|
let describeChoice = '';
|
|
1287
|
-
|
|
1288
|
-
|
|
1546
|
+
|
|
1547
|
+
// Use flag if provided (non-interactive mode for AI)
|
|
1548
|
+
if (options.describe) {
|
|
1549
|
+
const describeMap: Record<string, string> = {
|
|
1550
|
+
'guided': '1', 'template': '2', 'paste': '3', 'chat': '4', 'files': '5'
|
|
1551
|
+
};
|
|
1552
|
+
describeChoice = describeMap[options.describe] || '4';
|
|
1553
|
+
console.log(chalk.green(` Using: ${options.describe} mode for project description\n`));
|
|
1554
|
+
} else {
|
|
1555
|
+
// Interactive mode
|
|
1556
|
+
console.log(chalk.white('\n 📝 How would you like to describe your project?\n'));
|
|
1557
|
+
console.log(chalk.gray(' 1. ') + chalk.cyan('GUIDED QUESTIONS') + chalk.gray(' - I\'ll ask you step by step'));
|
|
1558
|
+
console.log(chalk.gray(' 2. ') + chalk.cyan('WRITE A PRD') + chalk.gray(' - Create a blank template to fill out'));
|
|
1559
|
+
console.log(chalk.gray(' 3. ') + chalk.cyan('PASTE/UPLOAD PRD') + chalk.gray(' - I already have requirements written'));
|
|
1560
|
+
console.log(chalk.gray(' 4. ') + chalk.cyan('DESCRIBE IN CHAT') + chalk.gray(' - Just tell the AI what you want'));
|
|
1561
|
+
console.log(chalk.gray(' 5. ') + chalk.cyan('SHARE FILES') + chalk.gray(' - I\'ll share docs/mockups/screenshots\n'));
|
|
1562
|
+
|
|
1563
|
+
while (!['1', '2', '3', '4', '5'].includes(describeChoice)) {
|
|
1564
|
+
describeChoice = await prompt(' Enter 1-5: ');
|
|
1565
|
+
}
|
|
1289
1566
|
}
|
|
1290
1567
|
|
|
1291
1568
|
let prdCreated = false;
|
|
@@ -1384,17 +1661,36 @@ async function setupExistingProject(cwd: string, projectInfo: ProjectInfo, optio
|
|
|
1384
1661
|
|
|
1385
1662
|
// Get project name
|
|
1386
1663
|
const defaultName = cwd.split(/[\\/]/).pop() || 'my-project';
|
|
1387
|
-
|
|
1664
|
+
let projectName: string;
|
|
1665
|
+
let reviewChoice: string;
|
|
1388
1666
|
|
|
1389
|
-
//
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1667
|
+
// Use flags if provided (non-interactive mode for AI)
|
|
1668
|
+
if (options.name) {
|
|
1669
|
+
projectName = options.name;
|
|
1670
|
+
console.log(chalk.green(`\n Using project name: "${projectName}"\n`));
|
|
1671
|
+
} else {
|
|
1672
|
+
projectName = await prompt(`\n Project name (${defaultName}): `) || defaultName;
|
|
1673
|
+
}
|
|
1394
1674
|
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
reviewChoice =
|
|
1675
|
+
// Use skipReview flag or ask
|
|
1676
|
+
if (options.skipReview) {
|
|
1677
|
+
reviewChoice = '3';
|
|
1678
|
+
console.log(chalk.gray(' Skipping code review (--skip-review flag)\n'));
|
|
1679
|
+
} else if (options.type) {
|
|
1680
|
+
// If running in non-interactive mode, default to skip review
|
|
1681
|
+
reviewChoice = '3';
|
|
1682
|
+
console.log(chalk.gray(' Skipping code review (non-interactive mode)\n'));
|
|
1683
|
+
} else {
|
|
1684
|
+
// Interactive mode - ask about code review
|
|
1685
|
+
console.log(chalk.white('\n Want me to review your code and bring it up to CodeBakers standards?\n'));
|
|
1686
|
+
console.log(chalk.gray(' 1. ') + chalk.cyan('YES, REVIEW & FIX') + chalk.gray(' - Run audit, then auto-fix issues'));
|
|
1687
|
+
console.log(chalk.gray(' 2. ') + chalk.cyan('REVIEW ONLY') + chalk.gray(' - Just show me the issues'));
|
|
1688
|
+
console.log(chalk.gray(' 3. ') + chalk.cyan('SKIP') + chalk.gray(' - Just install CodeBakers\n'));
|
|
1689
|
+
|
|
1690
|
+
reviewChoice = '';
|
|
1691
|
+
while (!['1', '2', '3'].includes(reviewChoice)) {
|
|
1692
|
+
reviewChoice = await prompt(' Enter 1, 2, or 3: ');
|
|
1693
|
+
}
|
|
1398
1694
|
}
|
|
1399
1695
|
|
|
1400
1696
|
let auditScore: number | undefined;
|
package/src/index.ts
CHANGED
|
@@ -224,7 +224,18 @@ program
|
|
|
224
224
|
.alias('start')
|
|
225
225
|
.description('Start using CodeBakers instantly (no signup required)')
|
|
226
226
|
.option('-v, --verbose', 'Show detailed debug output for troubleshooting')
|
|
227
|
-
|
|
227
|
+
// Non-interactive flags for programmatic use (e.g., by AI assistants)
|
|
228
|
+
.option('-t, --type <type>', 'Project type: personal, client, or business')
|
|
229
|
+
.option('-n, --name <name>', 'Project name')
|
|
230
|
+
.option('-d, --describe <mode>', 'Description mode: guided, template, paste, chat, or files')
|
|
231
|
+
.option('--skip-review', 'Skip the review question for existing projects')
|
|
232
|
+
.action((options) => go({
|
|
233
|
+
verbose: options.verbose,
|
|
234
|
+
type: options.type,
|
|
235
|
+
name: options.name,
|
|
236
|
+
describe: options.describe,
|
|
237
|
+
skipReview: options.skipReview,
|
|
238
|
+
}));
|
|
228
239
|
|
|
229
240
|
program
|
|
230
241
|
.command('extend')
|