faf-cli 2.4.0 → 2.4.2
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/README.md +154 -210
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +55 -143
- package/dist/cli.js.map +1 -1
- package/dist/commands/art.d.ts.map +1 -1
- package/dist/commands/art.js +3 -2
- package/dist/commands/art.js.map +1 -1
- package/dist/commands/enhance-real.d.ts +18 -0
- package/dist/commands/enhance-real.d.ts.map +1 -0
- package/dist/commands/enhance-real.js +1027 -0
- package/dist/commands/enhance-real.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +3 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/notifications.d.ts +12 -0
- package/dist/commands/notifications.d.ts.map +1 -0
- package/dist/commands/notifications.js +38 -0
- package/dist/commands/notifications.js.map +1 -0
- package/dist/commands/score-v3.d.ts.map +1 -1
- package/dist/commands/score-v3.js +7 -14
- package/dist/commands/score-v3.js.map +1 -1
- package/dist/commands/score.d.ts.map +1 -1
- package/dist/commands/score.js +10 -30
- package/dist/commands/score.js.map +1 -1
- package/dist/commands/subscribe.d.ts +12 -0
- package/dist/commands/subscribe.d.ts.map +1 -0
- package/dist/commands/subscribe.js +38 -0
- package/dist/commands/subscribe.js.map +1 -0
- package/dist/engine-bridge.d.ts +5 -5
- package/dist/engine-bridge.d.ts.map +1 -1
- package/dist/engine-bridge.js +7 -20
- package/dist/engine-bridge.js.map +1 -1
- package/dist/types/faf-types.d.ts +144 -0
- package/dist/types/faf-types.d.ts.map +1 -0
- package/dist/types/faf-types.js +21 -0
- package/dist/types/faf-types.js.map +1 -0
- package/dist/utils/announcements.d.ts +16 -0
- package/dist/utils/announcements.d.ts.map +1 -0
- package/dist/utils/announcements.js +136 -0
- package/dist/utils/announcements.js.map +1 -0
- package/dist/utils/art-gallery.d.ts +9 -1
- package/dist/utils/art-gallery.d.ts.map +1 -1
- package/dist/utils/art-gallery.js +46 -1
- package/dist/utils/art-gallery.js.map +1 -1
- package/dist/utils/championship-style.d.ts +1 -1
- package/dist/utils/championship-style.d.ts.map +1 -1
- package/dist/utils/championship-style.js +13 -17
- package/dist/utils/championship-style.js.map +1 -1
- package/dist/utils/email-opt-in.d.ts +31 -0
- package/dist/utils/email-opt-in.d.ts.map +1 -0
- package/dist/utils/email-opt-in.js +195 -0
- package/dist/utils/email-opt-in.js.map +1 -0
- package/dist/utils/feedback-messages.d.ts +13 -0
- package/dist/utils/feedback-messages.d.ts.map +1 -0
- package/dist/utils/feedback-messages.js +121 -0
- package/dist/utils/feedback-messages.js.map +1 -0
- package/dist/utils/score-header.js +16 -10
- package/dist/utils/score-header.js.map +1 -1
- package/dist/utils/update-checker.d.ts.map +1 -1
- package/dist/utils/update-checker.js +3 -12
- package/dist/utils/update-checker.js.map +1 -1
- package/dist/utils/yaml-generator.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,1027 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 🚀 REAL faf enhance - Actually improves scores with facts, not BS
|
|
4
|
+
* No placeholders, no mocks - real improvements based on project analysis
|
|
5
|
+
* RELENTLESS pursuit of highest score through real data or human input
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.realEnhanceFaf = realEnhanceFaf;
|
|
45
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
46
|
+
const fs_1 = require("fs");
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const YAML = __importStar(require("yaml"));
|
|
49
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
50
|
+
const file_utils_1 = require("../utils/file-utils");
|
|
51
|
+
const faf_compiler_1 = require("../compiler/faf-compiler");
|
|
52
|
+
const fab_formats_engine_1 = require("../utils/fab-formats-engine");
|
|
53
|
+
const child_process_1 = require("child_process");
|
|
54
|
+
/**
|
|
55
|
+
* REAL Enhancement that RELENTLESSLY improves scores
|
|
56
|
+
* Loops until target score achieved or no more improvements possible
|
|
57
|
+
*/
|
|
58
|
+
async function realEnhanceFaf(file, options = {}) {
|
|
59
|
+
try {
|
|
60
|
+
const fafPath = file || (await (0, file_utils_1.findFafFile)());
|
|
61
|
+
if (!fafPath) {
|
|
62
|
+
console.log(chalk_1.default.red("❌ No .faf file found"));
|
|
63
|
+
console.log(chalk_1.default.yellow('💡 Run "faf init" to create one'));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
const projectPath = path.dirname(fafPath);
|
|
67
|
+
console.log(chalk_1.default.cyan("⚡ Real Enhancement Starting..."));
|
|
68
|
+
console.log(chalk_1.default.gray(" No BS, just facts from your project"));
|
|
69
|
+
console.log(chalk_1.default.gray(` Enhancing: ${fafPath}`));
|
|
70
|
+
// Read current .faf file
|
|
71
|
+
const content = await fs_1.promises.readFile(fafPath, "utf-8");
|
|
72
|
+
let fafData = YAML.parse(content) || {};
|
|
73
|
+
// Get REAL current score with detailed breakdown
|
|
74
|
+
const compiler = new faf_compiler_1.FafCompiler();
|
|
75
|
+
let currentScore = await compiler.compile(fafPath);
|
|
76
|
+
const targetScore = options.targetScore || 100; // Changed from 80 to 100
|
|
77
|
+
console.log(chalk_1.default.yellow(`📊 Current Score: ${currentScore.score}%`));
|
|
78
|
+
console.log(chalk_1.default.gray(` Target Score: ${targetScore}%`));
|
|
79
|
+
console.log(chalk_1.default.gray(` Filled: ${currentScore.filled}/${currentScore.total} slots`));
|
|
80
|
+
// Show what's missing
|
|
81
|
+
if (options.verbose) {
|
|
82
|
+
displayMissingSlots(currentScore);
|
|
83
|
+
}
|
|
84
|
+
// RELENTLESS enhancement loop
|
|
85
|
+
let iteration = 0;
|
|
86
|
+
const maxIterations = 10; // Safety limit
|
|
87
|
+
while (currentScore.score < targetScore && iteration < maxIterations) {
|
|
88
|
+
iteration++;
|
|
89
|
+
console.log(chalk_1.default.cyan(`\n🔄 Enhancement Round ${iteration}...`));
|
|
90
|
+
// Analyze project for REAL improvements
|
|
91
|
+
const improvements = await analyzeProjectForRealImprovements(projectPath, fafData, currentScore);
|
|
92
|
+
if (options.verbose) {
|
|
93
|
+
console.log(chalk_1.default.gray(`Found ${Object.keys(improvements).length} automatic improvements`));
|
|
94
|
+
if (Object.keys(improvements).length > 0 && Object.keys(improvements).length <= 3) {
|
|
95
|
+
console.log(chalk_1.default.gray(` Improvements: ${Object.keys(improvements).join(', ')}`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// If no automatic improvements found and interactive mode, ask human
|
|
99
|
+
if (Object.keys(improvements).length === 0 && options.interactive !== false) {
|
|
100
|
+
// Check if we're missing critical human context
|
|
101
|
+
const missingHuman = !fafData.human_context?.who || !fafData.human_context?.what ||
|
|
102
|
+
!fafData.human_context?.why || !fafData.human_context?.where ||
|
|
103
|
+
!fafData.human_context?.when || !fafData.human_context?.how;
|
|
104
|
+
if (missingHuman) {
|
|
105
|
+
console.log(chalk_1.default.yellow('\n⚠️ Missing critical Human Context (the 6 W\'s)'));
|
|
106
|
+
console.log(chalk_1.default.gray(' This is the biggest opportunity to improve your score'));
|
|
107
|
+
}
|
|
108
|
+
const humanInput = await askHumanForMissingData(fafData, currentScore);
|
|
109
|
+
Object.assign(improvements, humanInput);
|
|
110
|
+
if (options.verbose && Object.keys(humanInput).length > 0) {
|
|
111
|
+
console.log(chalk_1.default.gray(`Added ${Object.keys(humanInput).length} improvements from human input`));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// If still no improvements, we're done
|
|
115
|
+
if (Object.keys(improvements).length === 0) {
|
|
116
|
+
console.log(chalk_1.default.yellow("\n⚠️ No more improvements possible with available data"));
|
|
117
|
+
if (options.interactive === false) {
|
|
118
|
+
console.log(chalk_1.default.gray(" (Interactive mode disabled - try with -i true to provide missing data)"));
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
if (options.dryRun) {
|
|
123
|
+
console.log(chalk_1.default.cyan("\n🔍 Improvements Found (Dry Run):"));
|
|
124
|
+
displayImprovements(improvements);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
// Apply REAL improvements
|
|
128
|
+
fafData = applyRealEnhancements(fafData, improvements);
|
|
129
|
+
// Save enhanced file
|
|
130
|
+
const enhancedYaml = YAML.stringify(fafData, null, 2);
|
|
131
|
+
await fs_1.promises.writeFile(fafPath, enhancedYaml);
|
|
132
|
+
// Calculate new score
|
|
133
|
+
const newScore = await compiler.compile(fafPath);
|
|
134
|
+
const improvement = newScore.score - currentScore.score;
|
|
135
|
+
if (improvement > 0) {
|
|
136
|
+
console.log(chalk_1.default.green(`✅ Improvement: +${improvement}% (${currentScore.score}% → ${newScore.score}%)`));
|
|
137
|
+
// Show what was actually added
|
|
138
|
+
if (options.verbose) {
|
|
139
|
+
console.log(chalk_1.default.cyan("📝 Changes Made:"));
|
|
140
|
+
displayImprovements(improvements);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
currentScore = newScore;
|
|
144
|
+
}
|
|
145
|
+
// Final results
|
|
146
|
+
console.log(chalk_1.default.cyan("\n" + "=".repeat(60)));
|
|
147
|
+
if (currentScore.score >= targetScore) {
|
|
148
|
+
console.log(chalk_1.default.green(`🎯 TARGET ACHIEVED! Score: ${currentScore.score}%`));
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.log(chalk_1.default.yellow(`📊 Final Score: ${currentScore.score}%`));
|
|
152
|
+
console.log(chalk_1.default.gray(` (Target was ${targetScore}%)`));
|
|
153
|
+
}
|
|
154
|
+
console.log(chalk_1.default.cyan("=".repeat(60)));
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
console.log(chalk_1.default.red("💥 Enhancement failed:"));
|
|
158
|
+
console.log(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Display what slots are missing for transparency
|
|
164
|
+
*/
|
|
165
|
+
function displayMissingSlots(score) {
|
|
166
|
+
const missing = [];
|
|
167
|
+
// Check project slots
|
|
168
|
+
if (score.breakdown.project.filled < score.breakdown.project.total) {
|
|
169
|
+
const projectSlots = score.breakdown.project.slots;
|
|
170
|
+
projectSlots.forEach((slot) => {
|
|
171
|
+
if (!slot.filled && slot.id.includes('project')) {
|
|
172
|
+
const field = slot.id.replace('slot_', '').replace('project.', '');
|
|
173
|
+
missing.push(`Project: ${field}`);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// Check stack slots
|
|
178
|
+
if (score.breakdown.stack.filled < score.breakdown.stack.total) {
|
|
179
|
+
const stackSlots = score.breakdown.stack.slots;
|
|
180
|
+
stackSlots.forEach((slot) => {
|
|
181
|
+
if (!slot.filled && slot.id.includes('stack')) {
|
|
182
|
+
const field = slot.id.replace('slot_', '').replace('stack.', '');
|
|
183
|
+
missing.push(`Stack: ${field}`);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
// Check human context slots
|
|
188
|
+
if (score.breakdown.human.filled < score.breakdown.human.total) {
|
|
189
|
+
const humanSlots = score.breakdown.human.slots;
|
|
190
|
+
humanSlots.forEach((slot) => {
|
|
191
|
+
if (!slot.filled && slot.id.includes('human')) {
|
|
192
|
+
const field = slot.id.replace('slot_', '').replace('human.', '');
|
|
193
|
+
missing.push(`Human Context: ${field}`);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
if (missing.length > 0) {
|
|
198
|
+
console.log(chalk_1.default.yellow('\n⚠️ Missing Context (affecting score):'));
|
|
199
|
+
missing.forEach(m => console.log(chalk_1.default.gray(` • ${m}`)));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Ask human for missing critical data via inquirer
|
|
204
|
+
* RELENTLESS 1-6 questionnaire for the 6 W's of Human Context
|
|
205
|
+
*/
|
|
206
|
+
async function askHumanForMissingData(currentFaf, score) {
|
|
207
|
+
const improvements = {};
|
|
208
|
+
const questions = [];
|
|
209
|
+
// Priority 1: Project data (most critical for AI)
|
|
210
|
+
if (!currentFaf.project?.name) {
|
|
211
|
+
questions.push({
|
|
212
|
+
type: 'input',
|
|
213
|
+
name: 'projectName',
|
|
214
|
+
message: '🎯 What is your project name?',
|
|
215
|
+
validate: (input) => input.trim().length > 0 || 'Project name is required for AI context'
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
if (!currentFaf.project?.goal) {
|
|
219
|
+
questions.push({
|
|
220
|
+
type: 'input',
|
|
221
|
+
name: 'projectGoal',
|
|
222
|
+
message: '🎯 What does your project do? (one sentence)',
|
|
223
|
+
validate: (input) => input.trim().length > 10 || 'Please provide a meaningful description'
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
// Priority 2: The 6 W's - RELENTLESS Human Context Collection
|
|
227
|
+
// These are CRITICAL for AI understanding and score improvement
|
|
228
|
+
console.log(chalk_1.default.cyan('\n🧠 Human Context - The 6 W\'s (Critical for AI Understanding)'));
|
|
229
|
+
console.log(chalk_1.default.gray(' These 6 questions dramatically improve AI\'s ability to help you'));
|
|
230
|
+
// 1. WHO - Target audience/users
|
|
231
|
+
if (!currentFaf.human_context?.who) {
|
|
232
|
+
questions.push({
|
|
233
|
+
type: 'input',
|
|
234
|
+
name: 'who',
|
|
235
|
+
message: chalk_1.default.yellow('1/6 👤 WHO will use this? (developers, data scientists, designers, etc.)'),
|
|
236
|
+
default: getSmartDefault('who', currentFaf),
|
|
237
|
+
transformer: (input) => chalk_1.default.green(input),
|
|
238
|
+
validate: (input) => {
|
|
239
|
+
if (input.trim().length < 3)
|
|
240
|
+
return 'Please specify your target users';
|
|
241
|
+
if (genericAnswers.who.includes(input.toLowerCase())) {
|
|
242
|
+
return 'Please be more specific than "' + input + '"';
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
// 2. WHAT - Core problem being solved
|
|
249
|
+
if (!currentFaf.human_context?.what) {
|
|
250
|
+
questions.push({
|
|
251
|
+
type: 'input',
|
|
252
|
+
name: 'what',
|
|
253
|
+
message: chalk_1.default.yellow('2/6 📦 WHAT problem does it solve? (be specific)'),
|
|
254
|
+
default: getSmartDefault('what', currentFaf),
|
|
255
|
+
transformer: (input) => chalk_1.default.green(input),
|
|
256
|
+
validate: (input) => {
|
|
257
|
+
if (input.trim().length < 10)
|
|
258
|
+
return 'Please describe the specific problem';
|
|
259
|
+
if (genericAnswers.what.includes(input.toLowerCase())) {
|
|
260
|
+
return 'Please be more specific about the problem';
|
|
261
|
+
}
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
// 3. WHY - Importance and impact
|
|
267
|
+
if (!currentFaf.human_context?.why) {
|
|
268
|
+
questions.push({
|
|
269
|
+
type: 'input',
|
|
270
|
+
name: 'why',
|
|
271
|
+
message: chalk_1.default.yellow('3/6 💡 WHY is this important? (what impact/value does it create?)'),
|
|
272
|
+
default: getSmartDefault('why', currentFaf),
|
|
273
|
+
transformer: (input) => chalk_1.default.green(input),
|
|
274
|
+
validate: (input) => {
|
|
275
|
+
if (input.trim().length < 10)
|
|
276
|
+
return 'Please explain why this matters';
|
|
277
|
+
if (genericAnswers.why.includes(input.toLowerCase())) {
|
|
278
|
+
return 'Please be more specific about the value/impact';
|
|
279
|
+
}
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
// 4. WHERE - Deployment/usage context
|
|
285
|
+
if (!currentFaf.human_context?.where) {
|
|
286
|
+
questions.push({
|
|
287
|
+
type: 'input',
|
|
288
|
+
name: 'where',
|
|
289
|
+
message: chalk_1.default.yellow('4/6 🌍 WHERE will it be used? (cloud, on-premise, mobile, browser, etc.)'),
|
|
290
|
+
default: getSmartDefault('where', currentFaf),
|
|
291
|
+
transformer: (input) => chalk_1.default.green(input),
|
|
292
|
+
validate: (input) => {
|
|
293
|
+
if (input.trim().length < 3)
|
|
294
|
+
return 'Please specify the deployment context';
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
// 5. WHEN - Timeline/urgency
|
|
300
|
+
if (!currentFaf.human_context?.when) {
|
|
301
|
+
questions.push({
|
|
302
|
+
type: 'input',
|
|
303
|
+
name: 'when',
|
|
304
|
+
message: chalk_1.default.yellow('5/6 ⏰ WHEN do you need this? (now, Q1 2025, ongoing, etc.)'),
|
|
305
|
+
default: getSmartDefault('when', currentFaf),
|
|
306
|
+
transformer: (input) => chalk_1.default.green(input),
|
|
307
|
+
validate: (input) => {
|
|
308
|
+
if (input.trim().length < 3)
|
|
309
|
+
return 'Please specify the timeline';
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
// 6. HOW - Implementation approach
|
|
315
|
+
if (!currentFaf.human_context?.how) {
|
|
316
|
+
questions.push({
|
|
317
|
+
type: 'input',
|
|
318
|
+
name: 'how',
|
|
319
|
+
message: chalk_1.default.yellow('6/6 🔧 HOW will you build it? (agile, iterative, waterfall, etc.)'),
|
|
320
|
+
default: getSmartDefault('how', currentFaf),
|
|
321
|
+
transformer: (input) => chalk_1.default.green(input),
|
|
322
|
+
validate: (input) => {
|
|
323
|
+
if (input.trim().length < 5)
|
|
324
|
+
return 'Please describe your approach';
|
|
325
|
+
if (genericAnswers.how.includes(input.toLowerCase())) {
|
|
326
|
+
return 'Please be more specific about your methodology';
|
|
327
|
+
}
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
// Priority 3: Technical stack (only if really needed and missing)
|
|
333
|
+
const needsFrontend = !currentFaf.stack?.frontend &&
|
|
334
|
+
(currentFaf.project?.type?.includes('frontend') || currentFaf.project?.type?.includes('fullstack'));
|
|
335
|
+
const needsBackend = !currentFaf.stack?.backend &&
|
|
336
|
+
(currentFaf.project?.type?.includes('backend') || currentFaf.project?.type?.includes('api'));
|
|
337
|
+
const needsDatabase = !currentFaf.stack?.database && needsBackend;
|
|
338
|
+
const needsHosting = !currentFaf.stack?.hosting;
|
|
339
|
+
if (needsFrontend) {
|
|
340
|
+
questions.push({
|
|
341
|
+
type: 'list',
|
|
342
|
+
name: 'framework',
|
|
343
|
+
message: '🎨 Frontend framework?',
|
|
344
|
+
choices: ['React', 'Vue', 'Angular', 'Svelte', 'Next.js', 'Remix', 'Astro', 'None', 'Skip']
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
if (needsBackend) {
|
|
348
|
+
questions.push({
|
|
349
|
+
type: 'list',
|
|
350
|
+
name: 'backend',
|
|
351
|
+
message: '⚙️ Backend framework?',
|
|
352
|
+
choices: ['Express', 'Fastify', 'NestJS', 'Hono', 'Django', 'FastAPI', 'Rails', 'None', 'Skip']
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
if (needsDatabase) {
|
|
356
|
+
questions.push({
|
|
357
|
+
type: 'list',
|
|
358
|
+
name: 'database',
|
|
359
|
+
message: '💾 Database?',
|
|
360
|
+
choices: ['PostgreSQL', 'MySQL', 'MongoDB', 'SQLite', 'Redis', 'Supabase', 'PlanetScale', 'None', 'Skip']
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
if (needsHosting) {
|
|
364
|
+
questions.push({
|
|
365
|
+
type: 'list',
|
|
366
|
+
name: 'hosting',
|
|
367
|
+
message: '☁️ Hosting platform?',
|
|
368
|
+
choices: ['Vercel', 'Netlify', 'AWS', 'Google Cloud', 'Azure', 'Heroku', 'Railway', 'Fly.io', 'None', 'Skip']
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
// Only ask if we have questions
|
|
372
|
+
if (questions.length === 0) {
|
|
373
|
+
return improvements;
|
|
374
|
+
}
|
|
375
|
+
console.log(chalk_1.default.cyan('\n🎯 Let\'s fill the critical gaps to reach your target score:'));
|
|
376
|
+
const answers = await inquirer_1.default.prompt(questions);
|
|
377
|
+
// Map answers to improvements
|
|
378
|
+
Object.entries(answers).forEach(([key, value]) => {
|
|
379
|
+
if (value && value !== 'Skip') {
|
|
380
|
+
improvements[key] = value;
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
// Show progress after human input
|
|
384
|
+
const filledCount = Object.keys(improvements).length;
|
|
385
|
+
if (filledCount > 0) {
|
|
386
|
+
console.log(chalk_1.default.green(`\n✅ Added ${filledCount} improvements from your input`));
|
|
387
|
+
}
|
|
388
|
+
return improvements;
|
|
389
|
+
}
|
|
390
|
+
// Generic answers to reject for better specificity
|
|
391
|
+
const genericAnswers = {
|
|
392
|
+
who: ['users', 'people', 'everyone', 'anybody', 'someone'],
|
|
393
|
+
what: ['problems', 'issues', 'things', 'stuff', 'something'],
|
|
394
|
+
why: ['because', 'important', 'needed', 'required', 'necessary'],
|
|
395
|
+
how: ['normal', 'usual', 'standard', 'regular', 'typical']
|
|
396
|
+
};
|
|
397
|
+
// Smart defaults based on project type
|
|
398
|
+
function getSmartDefault(field, currentFaf) {
|
|
399
|
+
const projectType = currentFaf.project?.type || '';
|
|
400
|
+
const projectName = currentFaf.project?.name || '';
|
|
401
|
+
const language = currentFaf.project?.main_language || '';
|
|
402
|
+
const defaults = {
|
|
403
|
+
who: {
|
|
404
|
+
'cli-tool': 'Developers and DevOps engineers',
|
|
405
|
+
'frontend': 'End users and web visitors',
|
|
406
|
+
'backend-api': 'Frontend applications and API consumers',
|
|
407
|
+
'fullstack': 'Business users and administrators',
|
|
408
|
+
'library': `Developers using ${language || 'this technology'}`,
|
|
409
|
+
'chrome-extension': 'Chrome browser users',
|
|
410
|
+
'default': 'Development teams'
|
|
411
|
+
},
|
|
412
|
+
what: {
|
|
413
|
+
'cli-tool': 'Automates repetitive command-line tasks',
|
|
414
|
+
'frontend': 'Provides user interface for data interaction',
|
|
415
|
+
'backend-api': 'Manages data and business logic',
|
|
416
|
+
'fullstack': 'Complete solution for business operations',
|
|
417
|
+
'library': `Simplifies ${language || 'development'} tasks`,
|
|
418
|
+
'chrome-extension': 'Enhances browser functionality',
|
|
419
|
+
'default': 'Solves specific technical challenges'
|
|
420
|
+
},
|
|
421
|
+
why: {
|
|
422
|
+
'cli-tool': 'Saves time and reduces errors in workflows',
|
|
423
|
+
'frontend': 'Improves user experience and engagement',
|
|
424
|
+
'backend-api': 'Centralizes data management and processing',
|
|
425
|
+
'fullstack': 'Streamlines business processes',
|
|
426
|
+
'library': 'Reduces code duplication and complexity',
|
|
427
|
+
'chrome-extension': 'Adds missing browser features',
|
|
428
|
+
'default': 'Increases productivity and quality'
|
|
429
|
+
},
|
|
430
|
+
where: {
|
|
431
|
+
'cli-tool': 'Local development machines and CI/CD pipelines',
|
|
432
|
+
'frontend': 'Web browsers and CDN',
|
|
433
|
+
'backend-api': 'Cloud servers or containers',
|
|
434
|
+
'fullstack': 'Cloud platform with global availability',
|
|
435
|
+
'library': 'NPM/PyPI package registry',
|
|
436
|
+
'chrome-extension': 'Chrome Web Store',
|
|
437
|
+
'default': 'Cloud infrastructure'
|
|
438
|
+
},
|
|
439
|
+
when: {
|
|
440
|
+
'default': 'Ongoing development and maintenance'
|
|
441
|
+
},
|
|
442
|
+
how: {
|
|
443
|
+
'default': 'Agile development with continuous deployment'
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
const typeDefaults = defaults[field];
|
|
447
|
+
if (!typeDefaults)
|
|
448
|
+
return '';
|
|
449
|
+
return typeDefaults[projectType] || typeDefaults['default'] || '';
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Analyze project for REAL improvements based on actual files
|
|
453
|
+
*/
|
|
454
|
+
async function analyzeProjectForRealImprovements(projectPath, currentFaf, currentScore) {
|
|
455
|
+
const improvements = {};
|
|
456
|
+
// Priority order: Fill critical slots first
|
|
457
|
+
// 1. PROJECT SLOTS (name, goal, language) - Most critical for AI
|
|
458
|
+
// 2. HUMAN CONTEXT (6 W's) - Critical for understanding
|
|
459
|
+
// 3. STACK SLOTS - Technical details
|
|
460
|
+
// 1. Scan for package.json to get REAL project info
|
|
461
|
+
try {
|
|
462
|
+
const pkgPath = path.join(projectPath, 'package.json');
|
|
463
|
+
const pkgContent = await fs_1.promises.readFile(pkgPath, 'utf-8');
|
|
464
|
+
const pkg = JSON.parse(pkgContent);
|
|
465
|
+
// Extract REAL project data
|
|
466
|
+
if (!currentFaf.project?.name && pkg.name) {
|
|
467
|
+
improvements.projectName = pkg.name;
|
|
468
|
+
}
|
|
469
|
+
if (!currentFaf.project?.goal && pkg.description) {
|
|
470
|
+
improvements.projectGoal = pkg.description;
|
|
471
|
+
}
|
|
472
|
+
if (!currentFaf.project?.version && pkg.version) {
|
|
473
|
+
improvements.version = pkg.version;
|
|
474
|
+
}
|
|
475
|
+
if (!currentFaf.project?.author && pkg.author) {
|
|
476
|
+
improvements.author = typeof pkg.author === 'string' ? pkg.author : pkg.author.name;
|
|
477
|
+
}
|
|
478
|
+
if (!currentFaf.project?.license && pkg.license) {
|
|
479
|
+
improvements.license = pkg.license;
|
|
480
|
+
}
|
|
481
|
+
// Extract REAL dependencies for stack info
|
|
482
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
483
|
+
const frameworks = detectFrameworks(deps);
|
|
484
|
+
if (frameworks.length > 0 && !currentFaf.stack?.frontend) {
|
|
485
|
+
improvements.framework = frameworks[0];
|
|
486
|
+
}
|
|
487
|
+
// Detect testing framework
|
|
488
|
+
const testFramework = detectTestingFramework(deps);
|
|
489
|
+
if (testFramework && !currentFaf.stack?.testing) {
|
|
490
|
+
improvements.testing = testFramework;
|
|
491
|
+
}
|
|
492
|
+
// Detect database
|
|
493
|
+
const database = detectDatabase(deps);
|
|
494
|
+
if (database && !currentFaf.stack?.database) {
|
|
495
|
+
improvements.database = database;
|
|
496
|
+
}
|
|
497
|
+
// Detect CI/CD from scripts
|
|
498
|
+
if (pkg.scripts?.deploy && !currentFaf.stack?.cicd) {
|
|
499
|
+
improvements.cicd = 'npm deploy';
|
|
500
|
+
}
|
|
501
|
+
// Extract scripts for understanding project
|
|
502
|
+
if (pkg.scripts) {
|
|
503
|
+
const scripts = Object.keys(pkg.scripts);
|
|
504
|
+
if (!currentFaf.stack?.testing && scripts.some(s => s.includes('test'))) {
|
|
505
|
+
improvements.testing = 'jest'; // or detect from deps
|
|
506
|
+
}
|
|
507
|
+
if (!currentFaf.stack?.build && scripts.some(s => s.includes('build'))) {
|
|
508
|
+
improvements.buildTool = detectBuildTool(deps);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
catch (e) {
|
|
513
|
+
// No package.json, try other files
|
|
514
|
+
}
|
|
515
|
+
// 2. Use FAB-Formats to INTELLIGENTLY discover project structure
|
|
516
|
+
const fabEngine = new fab_formats_engine_1.FabFormatsEngine();
|
|
517
|
+
const fabAnalysis = await fabEngine.discoverFormats(projectPath);
|
|
518
|
+
if (fabAnalysis.discoveredFormats && fabAnalysis.discoveredFormats.length > 0) {
|
|
519
|
+
// Add discovered key files
|
|
520
|
+
const keyFiles = fabAnalysis.discoveredFormats
|
|
521
|
+
.map((f) => f.fileName)
|
|
522
|
+
.filter((f) => isImportantFile(f))
|
|
523
|
+
.slice(0, 5);
|
|
524
|
+
if (keyFiles.length > 0 && !currentFaf.instant_context?.key_files) {
|
|
525
|
+
improvements.keyFiles = keyFiles;
|
|
526
|
+
}
|
|
527
|
+
// Use ALL extracted context from FAB-Formats
|
|
528
|
+
const ctx = fabAnalysis.extractedContext;
|
|
529
|
+
// Project information
|
|
530
|
+
if (ctx.projectName && !currentFaf.project?.name) {
|
|
531
|
+
improvements.projectName = ctx.projectName;
|
|
532
|
+
}
|
|
533
|
+
if (ctx.projectDescription && !currentFaf.project?.goal) {
|
|
534
|
+
improvements.projectGoal = ctx.projectDescription;
|
|
535
|
+
}
|
|
536
|
+
if (ctx.projectType && !currentFaf.project?.type) {
|
|
537
|
+
improvements.projectType = ctx.projectType;
|
|
538
|
+
}
|
|
539
|
+
// Stack information from FAB-Formats
|
|
540
|
+
if (ctx.mainLanguage && !currentFaf.project?.main_language) {
|
|
541
|
+
improvements.mainLanguage = ctx.mainLanguage;
|
|
542
|
+
}
|
|
543
|
+
if (ctx.frameworks && ctx.frameworks.length > 0) {
|
|
544
|
+
if (!currentFaf.stack?.frontend && isFrontendFramework(ctx.frameworks[0])) {
|
|
545
|
+
improvements.framework = ctx.frameworks[0];
|
|
546
|
+
}
|
|
547
|
+
if (!currentFaf.stack?.backend && isBackendFramework(ctx.frameworks[0])) {
|
|
548
|
+
improvements.backend = ctx.frameworks[0];
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
if (ctx.database && !currentFaf.stack?.database) {
|
|
552
|
+
improvements.database = ctx.database;
|
|
553
|
+
}
|
|
554
|
+
if (ctx.backend && !currentFaf.stack?.backend) {
|
|
555
|
+
improvements.backend = ctx.backend;
|
|
556
|
+
}
|
|
557
|
+
if (ctx.hosting && !currentFaf.stack?.hosting) {
|
|
558
|
+
improvements.hosting = ctx.hosting;
|
|
559
|
+
}
|
|
560
|
+
// These might not exist in ctx, check if they do
|
|
561
|
+
if (ctx.buildTool && !currentFaf.stack?.build) {
|
|
562
|
+
improvements.buildTool = ctx.buildTool;
|
|
563
|
+
}
|
|
564
|
+
if (ctx.testing && !currentFaf.stack?.testing) {
|
|
565
|
+
improvements.testing = ctx.testing;
|
|
566
|
+
}
|
|
567
|
+
if (ctx.cicd && !currentFaf.stack?.cicd) {
|
|
568
|
+
improvements.cicd = ctx.cicd;
|
|
569
|
+
}
|
|
570
|
+
// Use FAB-Formats pattern analysis for better detection
|
|
571
|
+
const patterns = fabAnalysis.discoveredFormats.map((f) => f.pattern);
|
|
572
|
+
if (patterns.includes('dockerfile') && !currentFaf.stack?.hosting) {
|
|
573
|
+
improvements.hosting = 'Docker';
|
|
574
|
+
}
|
|
575
|
+
if (patterns.includes('kubernetes') && !currentFaf.stack?.hosting) {
|
|
576
|
+
improvements.hosting = 'Kubernetes';
|
|
577
|
+
}
|
|
578
|
+
if (patterns.includes('github-actions') && !currentFaf.stack?.cicd) {
|
|
579
|
+
improvements.cicd = 'GitHub Actions';
|
|
580
|
+
}
|
|
581
|
+
if (patterns.includes('gitlab-ci') && !currentFaf.stack?.cicd) {
|
|
582
|
+
improvements.cicd = 'GitLab CI';
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
// 3. Detect project type from files
|
|
586
|
+
const files = await fs_1.promises.readdir(projectPath);
|
|
587
|
+
const projectType = detectProjectType(files);
|
|
588
|
+
if (projectType && projectType !== 'unknown' && !currentFaf.project?.type) {
|
|
589
|
+
improvements.projectType = projectType;
|
|
590
|
+
}
|
|
591
|
+
// 3.5 Try to get README for project goal and human context
|
|
592
|
+
try {
|
|
593
|
+
const readmePath = path.join(projectPath, 'README.md');
|
|
594
|
+
const readmeContent = await fs_1.promises.readFile(readmePath, 'utf-8');
|
|
595
|
+
const readmeInfo = extractFromReadme(readmeContent);
|
|
596
|
+
if (readmeInfo.description && !currentFaf.project?.goal) {
|
|
597
|
+
improvements.projectGoal = readmeInfo.description;
|
|
598
|
+
}
|
|
599
|
+
if (readmeInfo.who && !currentFaf.human_context?.who) {
|
|
600
|
+
improvements.who = readmeInfo.who;
|
|
601
|
+
}
|
|
602
|
+
if (readmeInfo.what && !currentFaf.human_context?.what) {
|
|
603
|
+
improvements.what = readmeInfo.what;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
catch (e) {
|
|
607
|
+
// No README or can't parse
|
|
608
|
+
}
|
|
609
|
+
// 4. Add REAL human context from git
|
|
610
|
+
try {
|
|
611
|
+
// Get git remote URL for WHERE context
|
|
612
|
+
if (!currentFaf.human_context?.where) {
|
|
613
|
+
const gitRemote = (0, child_process_1.execSync)('git config --get remote.origin.url', { cwd: projectPath })
|
|
614
|
+
.toString().trim();
|
|
615
|
+
if (gitRemote) {
|
|
616
|
+
if (gitRemote.includes('github.com')) {
|
|
617
|
+
improvements.where = 'GitHub';
|
|
618
|
+
}
|
|
619
|
+
else if (gitRemote.includes('gitlab')) {
|
|
620
|
+
improvements.where = 'GitLab';
|
|
621
|
+
}
|
|
622
|
+
else if (gitRemote.includes('bitbucket')) {
|
|
623
|
+
improvements.where = 'Bitbucket';
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
// Get last commit date for WHEN context
|
|
628
|
+
if (!currentFaf.human_context?.when) {
|
|
629
|
+
const lastCommit = (0, child_process_1.execSync)('git log -1 --format=%cd --date=short', { cwd: projectPath })
|
|
630
|
+
.toString().trim();
|
|
631
|
+
if (lastCommit) {
|
|
632
|
+
improvements.when = `Active development since ${lastCommit}`;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
catch (e) {
|
|
637
|
+
// No git or git commands failed
|
|
638
|
+
}
|
|
639
|
+
// 5. Add REAL technical details
|
|
640
|
+
if (!currentFaf.stack?.language) {
|
|
641
|
+
const language = detectLanguage(files);
|
|
642
|
+
if (language) {
|
|
643
|
+
improvements.mainLanguage = language;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
// 6. Analyze file patterns for more intelligent stack detection
|
|
647
|
+
if (!currentFaf.stack?.hosting) {
|
|
648
|
+
if (files.includes('vercel.json'))
|
|
649
|
+
improvements.hosting = 'Vercel';
|
|
650
|
+
else if (files.includes('netlify.toml'))
|
|
651
|
+
improvements.hosting = 'Netlify';
|
|
652
|
+
else if (files.includes('app.yaml'))
|
|
653
|
+
improvements.hosting = 'Google App Engine';
|
|
654
|
+
else if (files.includes('Procfile'))
|
|
655
|
+
improvements.hosting = 'Heroku';
|
|
656
|
+
else if (files.includes('.elasticbeanstalk'))
|
|
657
|
+
improvements.hosting = 'AWS Elastic Beanstalk';
|
|
658
|
+
}
|
|
659
|
+
// 7. Intelligent project type detection from structure
|
|
660
|
+
if (!currentFaf.project?.type) {
|
|
661
|
+
const hasPublicDir = files.includes('public');
|
|
662
|
+
const hasSrcDir = files.includes('src');
|
|
663
|
+
const hasApiDir = files.includes('api');
|
|
664
|
+
const hasServerFile = files.some(f => f.includes('server'));
|
|
665
|
+
const hasIndexHtml = files.includes('index.html');
|
|
666
|
+
if (hasApiDir && hasPublicDir)
|
|
667
|
+
improvements.projectType = 'fullstack';
|
|
668
|
+
else if (hasServerFile && !hasIndexHtml)
|
|
669
|
+
improvements.projectType = 'backend-api';
|
|
670
|
+
else if (hasPublicDir && hasIndexHtml)
|
|
671
|
+
improvements.projectType = 'frontend';
|
|
672
|
+
else if (files.includes('cli.js') || files.includes('cli.ts'))
|
|
673
|
+
improvements.projectType = 'cli-tool';
|
|
674
|
+
}
|
|
675
|
+
// 8. Extract runtime from files
|
|
676
|
+
if (!currentFaf.stack?.runtime) {
|
|
677
|
+
if (files.includes('package.json'))
|
|
678
|
+
improvements.runtime = 'Node.js';
|
|
679
|
+
else if (files.includes('requirements.txt'))
|
|
680
|
+
improvements.runtime = 'Python';
|
|
681
|
+
else if (files.includes('Gemfile'))
|
|
682
|
+
improvements.runtime = 'Ruby';
|
|
683
|
+
else if (files.includes('go.mod'))
|
|
684
|
+
improvements.runtime = 'Go';
|
|
685
|
+
else if (files.includes('Cargo.toml'))
|
|
686
|
+
improvements.runtime = 'Rust';
|
|
687
|
+
}
|
|
688
|
+
// 9. Fill API type if we have a backend
|
|
689
|
+
if (!currentFaf.stack?.api_type && (currentFaf.stack?.backend || improvements.backend)) {
|
|
690
|
+
// Check package.json for API type hints
|
|
691
|
+
try {
|
|
692
|
+
const pkgPath = path.join(projectPath, 'package.json');
|
|
693
|
+
const pkgContent = await fs_1.promises.readFile(pkgPath, 'utf-8');
|
|
694
|
+
const pkg = JSON.parse(pkgContent);
|
|
695
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
696
|
+
if (allDeps['graphql'])
|
|
697
|
+
improvements.api_type = 'GraphQL';
|
|
698
|
+
else if (allDeps['@trpc/server'])
|
|
699
|
+
improvements.api_type = 'tRPC';
|
|
700
|
+
else if (allDeps['socket.io'])
|
|
701
|
+
improvements.api_type = 'WebSocket';
|
|
702
|
+
else
|
|
703
|
+
improvements.api_type = 'REST';
|
|
704
|
+
}
|
|
705
|
+
catch (e) {
|
|
706
|
+
improvements.api_type = 'REST'; // Default to REST if can't read package.json
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
return improvements;
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Apply REAL enhancements to faf data
|
|
713
|
+
*/
|
|
714
|
+
function applyRealEnhancements(fafData, improvements) {
|
|
715
|
+
const enhanced = { ...fafData };
|
|
716
|
+
// Ensure structure exists
|
|
717
|
+
enhanced.project = enhanced.project || {};
|
|
718
|
+
enhanced.stack = enhanced.stack || {};
|
|
719
|
+
enhanced.human_context = enhanced.human_context || {};
|
|
720
|
+
enhanced.instant_context = enhanced.instant_context || {};
|
|
721
|
+
// Apply project improvements (CRITICAL SLOTS)
|
|
722
|
+
if (improvements.projectName) {
|
|
723
|
+
enhanced.project.name = improvements.projectName;
|
|
724
|
+
}
|
|
725
|
+
if (improvements.projectGoal) {
|
|
726
|
+
enhanced.project.goal = improvements.projectGoal;
|
|
727
|
+
}
|
|
728
|
+
if (improvements.mainLanguage) {
|
|
729
|
+
enhanced.project.main_language = improvements.mainLanguage;
|
|
730
|
+
}
|
|
731
|
+
if (improvements.version) {
|
|
732
|
+
enhanced.project.version = improvements.version;
|
|
733
|
+
}
|
|
734
|
+
if (improvements.author) {
|
|
735
|
+
enhanced.project.author = improvements.author;
|
|
736
|
+
}
|
|
737
|
+
if (improvements.license) {
|
|
738
|
+
enhanced.project.license = improvements.license;
|
|
739
|
+
}
|
|
740
|
+
if (improvements.projectType) {
|
|
741
|
+
enhanced.project.type = improvements.projectType;
|
|
742
|
+
}
|
|
743
|
+
// Apply stack improvements (TECHNICAL SLOTS)
|
|
744
|
+
if (improvements.framework) {
|
|
745
|
+
enhanced.stack.frontend = improvements.framework;
|
|
746
|
+
}
|
|
747
|
+
if (improvements.backend) {
|
|
748
|
+
enhanced.stack.backend = improvements.backend;
|
|
749
|
+
}
|
|
750
|
+
if (improvements.database) {
|
|
751
|
+
enhanced.stack.database = improvements.database;
|
|
752
|
+
}
|
|
753
|
+
if (improvements.buildTool) {
|
|
754
|
+
enhanced.stack.build = improvements.buildTool;
|
|
755
|
+
}
|
|
756
|
+
if (improvements.testing) {
|
|
757
|
+
enhanced.stack.testing = improvements.testing;
|
|
758
|
+
}
|
|
759
|
+
if (improvements.cicd) {
|
|
760
|
+
enhanced.stack.cicd = improvements.cicd;
|
|
761
|
+
}
|
|
762
|
+
if (improvements.runtime) {
|
|
763
|
+
enhanced.stack.runtime = improvements.runtime;
|
|
764
|
+
}
|
|
765
|
+
if (improvements.hosting) {
|
|
766
|
+
enhanced.stack.hosting = improvements.hosting;
|
|
767
|
+
}
|
|
768
|
+
if (improvements.api_type) {
|
|
769
|
+
enhanced.stack.api_type = improvements.api_type;
|
|
770
|
+
}
|
|
771
|
+
if (improvements.mainLanguage) {
|
|
772
|
+
enhanced.stack.language = improvements.mainLanguage;
|
|
773
|
+
}
|
|
774
|
+
// Apply human context improvements (6 W's - CRITICAL FOR AI UNDERSTANDING)
|
|
775
|
+
if (improvements.who) {
|
|
776
|
+
enhanced.human_context.who = improvements.who;
|
|
777
|
+
}
|
|
778
|
+
if (improvements.what) {
|
|
779
|
+
enhanced.human_context.what = improvements.what;
|
|
780
|
+
}
|
|
781
|
+
if (improvements.why) {
|
|
782
|
+
enhanced.human_context.why = improvements.why;
|
|
783
|
+
}
|
|
784
|
+
if (improvements.where) {
|
|
785
|
+
enhanced.human_context.where = improvements.where;
|
|
786
|
+
}
|
|
787
|
+
if (improvements.when) {
|
|
788
|
+
enhanced.human_context.when = improvements.when;
|
|
789
|
+
}
|
|
790
|
+
if (improvements.how) {
|
|
791
|
+
enhanced.human_context.how = improvements.how;
|
|
792
|
+
}
|
|
793
|
+
// Apply instant context improvements
|
|
794
|
+
if (improvements.keyFiles) {
|
|
795
|
+
enhanced.instant_context.key_files = improvements.keyFiles;
|
|
796
|
+
}
|
|
797
|
+
// Add metadata
|
|
798
|
+
enhanced.meta = enhanced.meta || {};
|
|
799
|
+
enhanced.meta.last_enhanced = new Date().toISOString();
|
|
800
|
+
enhanced.meta.enhanced_by = 'faf-real-enhance';
|
|
801
|
+
return enhanced;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Helper functions for detection
|
|
805
|
+
*/
|
|
806
|
+
function detectFrameworks(deps) {
|
|
807
|
+
const frameworks = [];
|
|
808
|
+
// Frontend frameworks
|
|
809
|
+
if (deps['react'])
|
|
810
|
+
frameworks.push('React');
|
|
811
|
+
if (deps['vue'])
|
|
812
|
+
frameworks.push('Vue');
|
|
813
|
+
if (deps['@angular/core'])
|
|
814
|
+
frameworks.push('Angular');
|
|
815
|
+
if (deps['svelte'])
|
|
816
|
+
frameworks.push('Svelte');
|
|
817
|
+
if (deps['solid-js'])
|
|
818
|
+
frameworks.push('SolidJS');
|
|
819
|
+
if (deps['preact'])
|
|
820
|
+
frameworks.push('Preact');
|
|
821
|
+
if (deps['@ember/core'])
|
|
822
|
+
frameworks.push('Ember');
|
|
823
|
+
// Meta-frameworks
|
|
824
|
+
if (deps['next'])
|
|
825
|
+
frameworks.push('Next.js');
|
|
826
|
+
if (deps['nuxt'])
|
|
827
|
+
frameworks.push('Nuxt');
|
|
828
|
+
if (deps['gatsby'])
|
|
829
|
+
frameworks.push('Gatsby');
|
|
830
|
+
if (deps['@remix-run/react'])
|
|
831
|
+
frameworks.push('Remix');
|
|
832
|
+
if (deps['astro'])
|
|
833
|
+
frameworks.push('Astro');
|
|
834
|
+
if (deps['@sveltekit/adapter-auto'])
|
|
835
|
+
frameworks.push('SvelteKit');
|
|
836
|
+
// Backend frameworks
|
|
837
|
+
if (deps['express'])
|
|
838
|
+
frameworks.push('Express');
|
|
839
|
+
if (deps['fastify'])
|
|
840
|
+
frameworks.push('Fastify');
|
|
841
|
+
if (deps['@nestjs/core'])
|
|
842
|
+
frameworks.push('NestJS');
|
|
843
|
+
if (deps['koa'])
|
|
844
|
+
frameworks.push('Koa');
|
|
845
|
+
if (deps['@hapi/hapi'])
|
|
846
|
+
frameworks.push('Hapi');
|
|
847
|
+
if (deps['@feathersjs/feathers'])
|
|
848
|
+
frameworks.push('Feathers');
|
|
849
|
+
if (deps['@adonisjs/core'])
|
|
850
|
+
frameworks.push('AdonisJS');
|
|
851
|
+
return frameworks;
|
|
852
|
+
}
|
|
853
|
+
function isFrontendFramework(framework) {
|
|
854
|
+
const frontend = ['React', 'Vue', 'Angular', 'Svelte', 'SolidJS', 'Preact', 'Ember',
|
|
855
|
+
'Next.js', 'Nuxt', 'Gatsby', 'Remix', 'Astro', 'SvelteKit'];
|
|
856
|
+
return frontend.includes(framework);
|
|
857
|
+
}
|
|
858
|
+
function isBackendFramework(framework) {
|
|
859
|
+
const backend = ['Express', 'Fastify', 'NestJS', 'Koa', 'Hapi', 'Feathers', 'AdonisJS'];
|
|
860
|
+
return backend.includes(framework);
|
|
861
|
+
}
|
|
862
|
+
function detectBuildTool(deps) {
|
|
863
|
+
if (deps['vite'])
|
|
864
|
+
return 'Vite';
|
|
865
|
+
if (deps['webpack'])
|
|
866
|
+
return 'Webpack';
|
|
867
|
+
if (deps['@parcel/core'] || deps['parcel'])
|
|
868
|
+
return 'Parcel';
|
|
869
|
+
if (deps['esbuild'])
|
|
870
|
+
return 'ESBuild';
|
|
871
|
+
if (deps['rollup'])
|
|
872
|
+
return 'Rollup';
|
|
873
|
+
if (deps['@swc/core'])
|
|
874
|
+
return 'SWC';
|
|
875
|
+
if (deps['turbopack'])
|
|
876
|
+
return 'Turbopack';
|
|
877
|
+
if (deps['snowpack'])
|
|
878
|
+
return 'Snowpack';
|
|
879
|
+
if (deps['@rspack/core'])
|
|
880
|
+
return 'Rspack';
|
|
881
|
+
return 'npm';
|
|
882
|
+
}
|
|
883
|
+
function detectProjectType(files) {
|
|
884
|
+
if (files.includes('package.json')) {
|
|
885
|
+
if (files.includes('tsconfig.json'))
|
|
886
|
+
return 'typescript-node';
|
|
887
|
+
return 'javascript-node';
|
|
888
|
+
}
|
|
889
|
+
if (files.includes('requirements.txt') || files.includes('setup.py')) {
|
|
890
|
+
return 'python';
|
|
891
|
+
}
|
|
892
|
+
if (files.includes('Cargo.toml'))
|
|
893
|
+
return 'rust';
|
|
894
|
+
if (files.includes('go.mod'))
|
|
895
|
+
return 'go';
|
|
896
|
+
return 'unknown';
|
|
897
|
+
}
|
|
898
|
+
function detectLanguage(files) {
|
|
899
|
+
const extensions = files.map(f => path.extname(f));
|
|
900
|
+
if (extensions.includes('.ts') || extensions.includes('.tsx'))
|
|
901
|
+
return 'TypeScript';
|
|
902
|
+
if (extensions.includes('.js') || extensions.includes('.jsx'))
|
|
903
|
+
return 'JavaScript';
|
|
904
|
+
if (extensions.includes('.py'))
|
|
905
|
+
return 'Python';
|
|
906
|
+
if (extensions.includes('.rs'))
|
|
907
|
+
return 'Rust';
|
|
908
|
+
if (extensions.includes('.go'))
|
|
909
|
+
return 'Go';
|
|
910
|
+
if (extensions.includes('.java'))
|
|
911
|
+
return 'Java';
|
|
912
|
+
return 'Unknown';
|
|
913
|
+
}
|
|
914
|
+
function isImportantFile(filename) {
|
|
915
|
+
const important = [
|
|
916
|
+
'index', 'main', 'app', 'server', 'cli',
|
|
917
|
+
'config', 'package.json', 'tsconfig.json',
|
|
918
|
+
'webpack.config', 'vite.config', 'README'
|
|
919
|
+
];
|
|
920
|
+
return important.some(i => filename.toLowerCase().includes(i));
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Extract info from README
|
|
924
|
+
*/
|
|
925
|
+
function extractFromReadme(content) {
|
|
926
|
+
const info = {};
|
|
927
|
+
// Try to get first paragraph as description
|
|
928
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
929
|
+
const descLine = lines.find(l => !l.startsWith('#') && l.length > 20);
|
|
930
|
+
if (descLine) {
|
|
931
|
+
info.description = descLine.trim();
|
|
932
|
+
}
|
|
933
|
+
// Look for "For" or "Built for" patterns
|
|
934
|
+
const forMatch = content.match(/(?:built for|for|designed for|made for)\s+([^.\n]+)/i);
|
|
935
|
+
if (forMatch) {
|
|
936
|
+
info.who = forMatch[1].trim();
|
|
937
|
+
}
|
|
938
|
+
// Look for problem statements
|
|
939
|
+
const problemMatch = content.match(/(?:solves?|fixes?|addresses?|handles?)\s+([^.\n]+)/i);
|
|
940
|
+
if (problemMatch) {
|
|
941
|
+
info.what = problemMatch[1].trim();
|
|
942
|
+
}
|
|
943
|
+
return info;
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Detect testing framework from dependencies
|
|
947
|
+
*/
|
|
948
|
+
function detectTestingFramework(deps) {
|
|
949
|
+
// Unit testing
|
|
950
|
+
if (deps['vitest'])
|
|
951
|
+
return 'Vitest';
|
|
952
|
+
if (deps['jest'])
|
|
953
|
+
return 'Jest';
|
|
954
|
+
if (deps['mocha'])
|
|
955
|
+
return 'Mocha';
|
|
956
|
+
if (deps['jasmine'])
|
|
957
|
+
return 'Jasmine';
|
|
958
|
+
if (deps['ava'])
|
|
959
|
+
return 'AVA';
|
|
960
|
+
if (deps['tape'])
|
|
961
|
+
return 'Tape';
|
|
962
|
+
if (deps['uvu'])
|
|
963
|
+
return 'uvu';
|
|
964
|
+
// E2E testing
|
|
965
|
+
if (deps['@playwright/test'] || deps['playwright'])
|
|
966
|
+
return 'Playwright';
|
|
967
|
+
if (deps['cypress'])
|
|
968
|
+
return 'Cypress';
|
|
969
|
+
if (deps['puppeteer'])
|
|
970
|
+
return 'Puppeteer';
|
|
971
|
+
if (deps['webdriverio'])
|
|
972
|
+
return 'WebdriverIO';
|
|
973
|
+
if (deps['nightwatch'])
|
|
974
|
+
return 'Nightwatch';
|
|
975
|
+
// Testing utilities
|
|
976
|
+
if (deps['@testing-library/react'])
|
|
977
|
+
return 'React Testing Library';
|
|
978
|
+
if (deps['@testing-library/vue'])
|
|
979
|
+
return 'Vue Testing Library';
|
|
980
|
+
if (deps['enzyme'])
|
|
981
|
+
return 'Enzyme';
|
|
982
|
+
return null;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Detect database from dependencies
|
|
986
|
+
*/
|
|
987
|
+
function detectDatabase(deps) {
|
|
988
|
+
// ORMs that support multiple databases
|
|
989
|
+
if (deps['@prisma/client'])
|
|
990
|
+
return 'Prisma';
|
|
991
|
+
if (deps['typeorm'])
|
|
992
|
+
return 'TypeORM';
|
|
993
|
+
if (deps['sequelize'])
|
|
994
|
+
return 'Sequelize';
|
|
995
|
+
if (deps['drizzle-orm'])
|
|
996
|
+
return 'Drizzle';
|
|
997
|
+
if (deps['kysely'])
|
|
998
|
+
return 'Kysely';
|
|
999
|
+
// Specific databases
|
|
1000
|
+
if (deps['pg'] || deps['postgres'])
|
|
1001
|
+
return 'PostgreSQL';
|
|
1002
|
+
if (deps['mysql'] || deps['mysql2'])
|
|
1003
|
+
return 'MySQL';
|
|
1004
|
+
if (deps['mongodb'] || deps['mongoose'])
|
|
1005
|
+
return 'MongoDB';
|
|
1006
|
+
if (deps['sqlite3'] || deps['better-sqlite3'])
|
|
1007
|
+
return 'SQLite';
|
|
1008
|
+
if (deps['redis'] || deps['ioredis'])
|
|
1009
|
+
return 'Redis';
|
|
1010
|
+
if (deps['@supabase/supabase-js'])
|
|
1011
|
+
return 'Supabase';
|
|
1012
|
+
if (deps['firebase'])
|
|
1013
|
+
return 'Firebase';
|
|
1014
|
+
if (deps['@planetscale/database'])
|
|
1015
|
+
return 'PlanetScale';
|
|
1016
|
+
if (deps['@neondatabase/serverless'])
|
|
1017
|
+
return 'Neon';
|
|
1018
|
+
if (deps['@vercel/postgres'])
|
|
1019
|
+
return 'Vercel Postgres';
|
|
1020
|
+
return null;
|
|
1021
|
+
}
|
|
1022
|
+
function displayImprovements(improvements) {
|
|
1023
|
+
Object.entries(improvements).forEach(([key, value]) => {
|
|
1024
|
+
console.log(chalk_1.default.gray(` • ${key}: ${value}`));
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
//# sourceMappingURL=enhance-real.js.map
|