faf-cli
Version:
๐ฝ TURBO-CAT: The Rapid Catalytic Converter โข Project DNA โจ for ANY AI โข Fully Integrated with React, Next.js, Svelte, TypeScript, Vite & n8n โข FREE FOREVER โข 10,000+ developers โข Championship Edition
359 lines โข 15.7 kB
JavaScript
"use strict";
/**
* AI-Optimized YAML Generator v2.5.0
* Generates .faf files with instant AI onboarding structure
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.unescapeFromYaml = unescapeFromYaml;
exports.escapeForYaml = escapeForYaml;
exports.generateFafContent = generateFafContent;
// Helper function to restore markdown formatting from escaped YAML
function unescapeFromYaml(value) {
if (!value)
return value;
// Remove surrounding quotes if present
let unquoted = value;
if ((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))) {
unquoted = value.slice(1, -1);
}
// Unescape special characters
unquoted = unquoted.replace(/\\"/g, '"');
// Could optionally restore markdown if we detect patterns
// But for now, just return the clean unescaped value
return unquoted;
}
// Helper function to generate stack string
function generateStackString(data) {
const parts = [];
if (data.framework && data.framework !== 'None') {
parts.push(data.framework);
}
if (data.mainLanguage && data.mainLanguage !== 'Unknown') {
parts.push(data.mainLanguage);
}
if (data.buildTool && data.buildTool !== 'None') {
parts.push(data.buildTool);
}
if (data.hosting && data.hosting !== 'None') {
parts.push(data.hosting);
}
if (data.backend && data.backend !== 'None') {
parts.push(data.backend);
}
return parts.join('/') || 'Not specified';
}
// Helper function to determine confidence level
function getConfidenceLevel(percentage) {
if (percentage >= 90) {
return 'VERY_HIGH';
}
if (percentage >= 80) {
return 'HIGH';
}
if (percentage >= 70) {
return 'GOOD';
}
if (percentage >= 60) {
return 'MODERATE';
}
return 'LOW';
}
// Helper function to safely escape YAML values
function escapeForYaml(value) {
if (!value) {
return 'Not specified';
}
// Clean up markdown-style lists and formatting
const cleaned = value
.replace(/^[\s]*[-*]\s*/gm, '') // Remove list markers
.replace(/\*\*(.+?)\*\*/g, '$1') // Remove bold
.replace(/\*(.+?)\*/g, '$1') // Remove italic
.replace(/\n+/g, ' ') // Replace newlines with spaces
.trim();
// If it looks like JSON or already quoted, return as-is to avoid double-escaping
if (cleaned.startsWith('"') && cleaned.endsWith('"')) {
return cleaned;
}
// If it contains special characters or starts with special chars, quote it
if (cleaned.includes(':') || cleaned.includes('-') || cleaned.includes('[') ||
cleaned.includes('#') || cleaned.includes('|') || cleaned.includes('>') ||
cleaned.match(/^[\d\-[\]{}]/)) {
// Single-escape quotes only
return `"${cleaned.replace(/"/g, '\\"')}"`;
}
return cleaned;
}
// Helper function to detect key files
function detectKeyFiles(data) {
const files = [];
// Based on framework
if (data.framework?.toLowerCase().includes('svelte')) {
files.push('+page.svelte', '+layout.svelte', 'app.html');
}
else if (data.framework?.toLowerCase().includes('react')) {
files.push('App.tsx', 'index.tsx');
}
else if (data.framework?.toLowerCase().includes('vue')) {
files.push('App.vue', 'main.ts');
}
else if (data.mainLanguage?.toLowerCase().includes('python')) {
files.push('main.py', 'requirements.txt');
}
// ๐ PYTHON CONTEXT-ON-DEMAND: Add appropriate config files
if (!data.mainLanguage?.toLowerCase().includes('python')) {
// Only add JS/TS files for non-Python projects
files.push('package.json', 'tsconfig.json');
}
return files.slice(0, 5); // Max 5 files
}
// Generate project tags
function generateProjectTags(projectData) {
const autoTags = new Set();
// From project name
if (projectData.projectName) {
const cleanName = projectData.projectName.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.substring(0, 30);
if (cleanName) {
autoTags.add(cleanName);
}
}
// From tech stack
if (projectData.framework) {
autoTags.add(projectData.framework.toLowerCase().replace(/\s+/g, '-'));
}
if (projectData.mainLanguage) {
autoTags.add(projectData.mainLanguage.toLowerCase().replace(/\s+/g, '-'));
}
if (projectData.buildTool) {
autoTags.add(projectData.buildTool.toLowerCase().replace(/\s+/g, '-'));
}
if (projectData.hosting) {
autoTags.add(projectData.hosting.toLowerCase().replace(/\s+/g, '-'));
}
if (projectData.backend) {
autoTags.add(projectData.backend.toLowerCase().replace(/\s+/g, '-'));
}
// Remove empty tags
autoTags.delete('');
autoTags.delete('-');
const year = new Date().getFullYear().toString();
const smartTags = [
'.faf', // ALWAYS - Ecosystem builder!
'ai-ready', // ALWAYS - We're AI-optimized
year, // Current year for freshness
];
// Smart category detection
if (projectData.projectGoal?.toLowerCase().includes('api') || projectData.framework?.toLowerCase().includes('express')) {
smartTags.push('backend-api');
}
else if (projectData.framework?.toLowerCase().match(/react|vue|svelte|angular/)) {
smartTags.push('web-app');
}
else if (projectData.projectGoal?.toLowerCase().includes('library')) {
smartTags.push('dev-tools');
}
else {
smartTags.push('software');
}
// License/sharing detection (simplified for now)
smartTags.push('open-source'); // Default to open-source for community
return {
auto_generated: Array.from(autoTags).slice(0, 21),
smart_defaults: smartTags,
user_defined: []
};
}
/**
* Convert JavaScript object to YAML format
*/
function objectToYaml(obj, indent = 0) {
let yaml = '';
const spacing = ' '.repeat(indent);
for (const [key, value] of Object.entries(obj)) {
if (value === null || value === undefined) {
continue;
}
if (typeof value === 'object' && !Array.isArray(value)) {
yaml += `${spacing}${key}:\n`;
yaml += objectToYaml(value, indent + 1);
}
else if (Array.isArray(value)) {
yaml += `${spacing}${key}:\n`;
for (const item of value) {
// Also escape array items if they're strings
const escapedItem = typeof item === 'string' ? escapeForYaml(item) : item;
yaml += `${spacing} - ${escapedItem}\n`;
}
}
else {
// ALWAYS use escapeForYaml for strings to remove markdown and special chars
let escapedValue = value;
if (typeof value === 'string') {
escapedValue = escapeForYaml(value);
}
yaml += `${spacing}${key}: ${escapedValue}\n`;
}
}
return yaml;
}
function generateFafContent(projectData) {
// Calculate filled vs total slots for missing context
const totalSlotsCount = 21; // Base slots
const filledSlotsCount = Math.round((projectData.slotBasedPercentage / 100) * totalSlotsCount);
const missingSlots = [];
if (!projectData.targetUser) {
missingSlots.push('Target users');
}
if (!projectData.coreProblem) {
missingSlots.push('Core problem');
}
if (!projectData.timeline) {
missingSlots.push('Timeline');
}
if (!projectData.cicd || projectData.cicd === 'None') {
missingSlots.push('CI/CD pipeline');
}
if (!projectData.database || projectData.database === 'None') {
missingSlots.push('Database');
}
const fafData = {
// FAF schema version (not CLI version)
faf_version: '2.5.0',
// ๐ค AI-FIRST SCORING SYSTEM - Championship Engine with FAB-FORMATS
ai_scoring_system: '2025-09-20', // faf-engine-mk3 compiler live date
ai_score: `${projectData.fafScore}%`, // MY evaluation
ai_confidence: getConfidenceLevel(projectData.fafScore), // MY trust level
ai_value: '30_seconds_replaces_20_minutes_of_questions',
// ๐ง AI READ THIS FIRST - 5-LINE TL;DR
ai_tldr: {
project: `${projectData.projectName} - ${escapeForYaml(projectData.projectGoal) || 'Universal AI-context Infrastructure - Make Your AI Happy! ๐ค'}`,
stack: generateStackString(projectData),
quality_bar: 'ZERO_ERRORS_F1_STANDARDS',
current_focus: 'Production deployment preparation',
your_role: 'Build features with perfect context'
},
// โก INSTANT CONTEXT - Everything critical in one place
instant_context: {
what_building: projectData.projectGoal ? escapeForYaml(projectData.projectGoal) : '๐ Universal AI-context CLI - Trust-Driven Infrastructure that eliminates developer anxiety',
tech_stack: generateStackString(projectData),
main_language: projectData.mainLanguage || 'TypeScript',
deployment: projectData.hosting || 'Cloud platform',
key_files: detectKeyFiles(projectData)
},
// ๐ CONTEXT QUALITY METRICS
context_quality: {
slots_filled: `${filledSlotsCount}/${totalSlotsCount} (${projectData.slotBasedPercentage}%)`,
ai_confidence: getConfidenceLevel(projectData.slotBasedPercentage),
handoff_ready: projectData.slotBasedPercentage > 70,
missing_context: missingSlots.length > 0 ? missingSlots : ['None - fully specified!']
},
// ๐ Project Details (Progressive Disclosure)
project: {
name: projectData.projectName || 'Untitled Project',
goal: projectData.projectGoal ? escapeForYaml(projectData.projectGoal) : 'โก๏ธ Transform developer psychology from hope-driven to trust-driven AI development - 30 seconds replaces 20 minutes of questions',
main_language: projectData.mainLanguage || 'Unknown',
generated: new Date().toISOString(),
mission: '๐ Make Your AI Happy! ๐งก Trust-Driven ๐ค',
revolution: '30 seconds replaces 20 minutes of questions',
brand: 'F1-Inspired Software Engineering - Championship AI Context'
},
// ๐ง AI OPERATING INSTRUCTIONS
ai_instructions: {
priority_order: [
'1. Read THIS .faf file first',
'2. Check CLAUDE.md for session context',
projectData.mainLanguage?.toLowerCase().includes('python')
? '3. Review requirements.txt and main.py for dependencies'
: '3. Review package.json for dependencies'
],
working_style: {
code_first: true,
explanations: 'minimal',
quality_bar: 'zero_errors',
testing: 'required'
},
warnings: [
'Never modify dial components without approval',
'All TypeScript must pass strict mode',
'Test coverage required for new features'
]
},
// ๐๏ธ Technical Stack (Full Details)
stack: {
frontend: projectData.framework || 'None',
css_framework: projectData.cssFramework || 'None',
ui_library: projectData.uiLibrary || 'None',
state_management: projectData.stateManagement || 'None',
backend: projectData.backend || 'None',
runtime: projectData.server || 'None',
database: projectData.database || 'None',
build: projectData.buildTool || 'None',
package_manager: projectData.packageManager || 'npm',
api_type: projectData.apiType || 'REST API',
hosting: projectData.hosting || 'None',
cicd: projectData.cicd || 'None'
},
// โ๏ธ Development Preferences
preferences: {
quality_bar: 'zero_errors',
commit_style: 'conventional_emoji',
response_style: 'concise_code_first',
explanation_level: 'minimal',
communication: 'direct',
testing: 'required',
documentation: 'as_needed'
},
// ๐ Project State
state: {
phase: 'development',
version: '1.0.0',
focus: 'production_deployment',
status: 'green_flag',
next_milestone: 'npm_publication',
blockers: []
},
// ๐ท๏ธ Search & Discovery Tags
tags: generateProjectTags(projectData),
// ๐ฅ Human Context (The 6 W's) - ALWAYS ESCAPE to remove markdown
human_context: projectData.targetUser || projectData.coreProblem ? {
who: escapeForYaml(projectData.targetUser || 'Not specified'),
what: escapeForYaml(projectData.coreProblem || 'Not specified'),
why: escapeForYaml(projectData.missionPurpose || 'Not specified'),
where: escapeForYaml(projectData.deploymentMarket || 'Not specified'),
when: escapeForYaml(projectData.timeline || 'Not specified'),
how: escapeForYaml(projectData.approach || 'Not specified'),
additional_context: {
who: projectData.additionalWho && projectData.additionalWho.length > 0 ? projectData.additionalWho : undefined,
what: projectData.additionalWhat && projectData.additionalWhat.length > 0 ? projectData.additionalWhat : undefined,
why: projectData.additionalWhy && projectData.additionalWhy.length > 0 ? projectData.additionalWhy : undefined,
where: projectData.additionalWhere && projectData.additionalWhere.length > 0 ? projectData.additionalWhere : undefined,
when: projectData.additionalWhen && projectData.additionalWhen.length > 0 ? projectData.additionalWhen : undefined,
how: projectData.additionalHow && projectData.additionalHow.length > 0 ? projectData.additionalHow : undefined
},
context_score: projectData.projectDetailsScore || 0,
total_prd_score: (projectData.projectDetailsScore || 0) + (projectData.fafScore || 0),
success_rate: `${projectData.projectSuccessRate || 50}%`
} : undefined,
// ๐ AI Scoring Details (For Transparency)
ai_scoring_details: {
system_date: '2025-09-20', // faf-engine-mk3 Championship Engine
slot_based_percentage: projectData.slotBasedPercentage,
ai_score: projectData.fafScore,
total_slots: 21,
filled_slots: filledSlotsCount,
scoring_method: 'Honest percentage - no fake minimums',
trust_embedded: 'COUNT ONCE architecture - trust MY embedded scores'
}
};
// Use native YAML library and fix any !CI placeholder issues
const yamlContent = objectToYaml(fafData);
// Championship fix: Replace !CI placeholders with revolutionary content
const championshipContent = yamlContent
.replace(/what_building: !CI/g, 'what_building: "๐ Universal AI-context CLI - Trust-Driven Infrastructure that eliminates developer anxiety"')
.replace(/goal: !CI/g, 'goal: "โก๏ธ Transform developer psychology from hope-driven to trust-driven AI development - 30 seconds replaces 20 minutes of questions"');
return championshipContent;
}
//# sourceMappingURL=yaml-generator.js.map