UNPKG

humanbehavior-js

Version:

SDK for HumanBehavior session and event recording

238 lines (209 loc) 7.82 kB
/** * Manual Framework Installation Wizard * * This wizard allows users to manually specify their framework instead of auto-detection. * Useful when auto-detection fails or users want more control. */ import * as fs from 'fs'; import * as path from 'path'; import { AutoInstallationWizard, FrameworkInfo, CodeModification, InstallationResult } from '../core/install-wizard'; import { RemoteAIService } from '../services/remote-ai-service'; export interface ManualInstallationResult extends InstallationResult { selectedFramework: string; manualMode: boolean; } export class ManualFrameworkInstallationWizard extends AutoInstallationWizard { private selectedFramework: string; constructor(apiKey: string, projectRoot: string = process.cwd(), framework: string) { super(apiKey, projectRoot); this.selectedFramework = framework.toLowerCase(); this.framework = this.createFrameworkInfo(this.selectedFramework); } /** * Manual installation with user-specified framework */ async install(): Promise<ManualInstallationResult> { try { // Step 1: Handle framework selection if (this.selectedFramework === 'auto') { // Use full AI detection for "Other" option this.framework = await this.runFullDetection(); } else { // Set framework based on user selection this.framework = this.createFrameworkInfo(this.selectedFramework); if (!this.framework) { this.framework = { name: 'unknown', type: 'vanilla' }; } // Step 2: Run full detection logic to find entry points, file names, etc. const detectedFramework = await this.runFullDetection(); // Step 3: Merge manual framework with detected details this.framework = { ...detectedFramework, name: this.framework.name, type: this.framework.type }; } // Step 4: Install package await this.installPackage(); // Step 5: Generate and apply code modifications const modifications = await this.generateModifications(); await this.applyModifications(modifications); // Step 6: Generate next steps const nextSteps = this.generateManualNextSteps(); return { success: true, framework: this.framework, modifications, errors: [], nextSteps, selectedFramework: this.selectedFramework, manualMode: true }; } catch (error) { return { success: false, framework: this.framework || { name: 'unknown', type: 'vanilla' }, modifications: [], errors: [error instanceof Error ? error.message : 'Unknown error'], nextSteps: [], selectedFramework: this.selectedFramework, manualMode: true }; } } /** * Run full detection logic to find entry points, file names, bundler, etc. */ private async runFullDetection(): Promise<FrameworkInfo> { if (this.selectedFramework === 'auto') { // Use AI service for auto-detection const aiService = new RemoteAIService({ apiEndpoint: 'https://ik3zxh4790.execute-api.us-east-1.amazonaws.com/prod' }); // Use AI service directly for detection const projectFiles = await this.scanProjectFiles(); const codeSamples = await this.extractCodeSamples(projectFiles); const aiAnalysis = await aiService.analyzeCodePatterns(codeSamples); return aiAnalysis.framework; } else { // Use traditional detection for manual frameworks const tempWizard = new AutoInstallationWizard(this.apiKey, this.projectRoot); const detected = await tempWizard.detectFramework(); return detected; } } /** * Scan project files for analysis */ private async scanProjectFiles(): Promise<string[]> { const files: string[] = []; const scanDir = (dir: string, depth: number = 0) => { if (depth > 3) return; // Limit depth try { const items = fs.readdirSync(dir); for (const item of items) { const fullPath = path.join(dir, item); const stat = fs.statSync(fullPath); if (stat.isDirectory() && !item.startsWith('.') && item !== 'node_modules') { scanDir(fullPath, depth + 1); } else if (stat.isFile() && this.isRelevantFile(item)) { files.push(fullPath); } } } catch (error) { // Skip inaccessible directories } }; scanDir(this.projectRoot); return files; } /** * Check if file is relevant for analysis */ private isRelevantFile(filename: string): boolean { const relevantExtensions = [ '.js', '.jsx', '.ts', '.tsx', '.vue', '.svelte', '.html', '.json', '.config.js', '.config.ts', '.babelrc', '.eslintrc' ]; const relevantNames = [ 'package.json', 'tsconfig.json', 'vite.config', 'webpack.config', 'next.config', 'nuxt.config', 'angular.json', 'svelte.config' ]; return relevantExtensions.some(ext => filename.endsWith(ext)) || relevantNames.some(name => filename.includes(name)); } /** * Extract code samples for AI analysis */ private async extractCodeSamples(files: string[]): Promise<string[]> { const samples: string[] = []; for (const file of files.slice(0, 20)) { // Limit to 20 files try { const content = fs.readFileSync(file, 'utf8'); const relativePath = path.relative(this.projectRoot, file); samples.push(`File: ${relativePath}\n${content.substring(0, 1000)}`); } catch (error) { // Skip unreadable files } } return samples; } /** * Create framework info based on user selection */ private createFrameworkInfo(framework: string): FrameworkInfo { const frameworkMap: Record<string, FrameworkInfo> = { 'react': { name: 'react', type: 'react' }, 'nextjs': { name: 'nextjs', type: 'nextjs' }, 'next': { name: 'nextjs', type: 'nextjs' }, 'vue': { name: 'vue', type: 'vue' }, 'nuxt': { name: 'nuxt', type: 'nuxt' }, 'nuxtjs': { name: 'nuxt', type: 'nuxt' }, 'angular': { name: 'angular', type: 'angular' }, 'svelte': { name: 'svelte', type: 'svelte' }, 'sveltekit': { name: 'svelte', type: 'svelte' }, 'remix': { name: 'remix', type: 'remix' }, 'astro': { name: 'astro', type: 'astro' }, 'gatsby': { name: 'gatsby', type: 'gatsby' }, 'vanilla': { name: 'vanilla', type: 'vanilla' }, 'node': { name: 'node', type: 'node' }, 'auto': { name: 'auto-detected', type: 'auto' } }; return frameworkMap[framework] || { name: framework, type: 'vanilla' }; } /** * Override framework detection to use manual selection */ public async detectFramework(): Promise<FrameworkInfo> { return this.framework || { name: 'unknown', type: 'vanilla' }; } /** * Generate next steps with manual mode info */ private generateManualNextSteps(): string[] { return [ '✅ Manual framework installation completed!', `🎯 Selected framework: ${this.framework?.name || 'unknown'}`, `🔧 Integration strategy: ${this.getIntegrationStrategy()}`, '🚀 Your app is now ready to track user behavior', '📊 View sessions in your HumanBehavior dashboard' ]; } /** * Get integration strategy based on framework */ private getIntegrationStrategy(): string { if (!this.framework?.type) return 'script'; switch (this.framework.type) { case 'react': case 'nextjs': return 'provider'; case 'vue': return 'plugin'; case 'angular': return 'module'; default: return 'script'; } } }