// 🎸 Enhanced Maestro.ai Guitar Practice Module Builder Handler - SVG Architecture + Audio Engine Update // .vscode-extensions/cipher-autonomous-dev/src/handlers/music/maestroGuitarModuleBuilderHandler.ts import * as fs from "fs"; import * as path from "path"; import * as vscode from "vscode"; import { displayBrainSuggestions } from "../../shared/displayUtils"; import { createIndexFile, findMaestroProjectRoot, protectMaestroGuitarInstallation, shouldFolderHaveIndex, } from "../../shared/indexSyncUtils"; import { generateMusicHandlerTemplate } from "../../shared/templateGenerators"; import { getBrainInterface, isBrainConnected, shareAnalysisData, } from "../../shared/utils"; // 🧠** KEEP FOR All HANDLER FILESβ€” Brain Enhanced ** import { BrainConnector } from "../../brain/BrainConnector"; // πŸ›‘οΈ PROTECTION TEST - Quick verification console.log("πŸ”§ Testing protection..."); console.log( "πŸ“ Project:", findMaestroProjectRoot() ? "Found βœ…" : "Not found ❌" ); console.log( "πŸ›‘οΈ Protection:", protectMaestroGuitarInstallation() ? "Working βœ…" : "Failed ❌" ); // βœ… UPGRADE TO FULL v20 BRAIN LEARNING: async function performBrainLearning( action: string, success: boolean, metadata: any = {} ): Promise { console.log( `πŸš€ [v20] MaestroGuitarModuleBuilder Brain Learning ENTRY - Action: ${action}, Success: ${success}` ); // βœ… v20 Brain initialization console.log(`🧠 [v20] CRITICAL FIX: Calling initializeBrainSystem()...`); try { const { initializeBrainSystem } = await import("../../shared/utils"); const initialized = await initializeBrainSystem(); console.log( `🧠 [v20] Brain initialization result: ${initialized ? "βœ… SUCCESS" : "❌ FAILED"}` ); } catch (initError) { console.log(`🧠 [v20] Brain initialization failed: ${initError}`); } // βœ… Brain learning try { const brainInterface = getBrainInterface(); if (brainInterface) { await brainInterface.learnFromAction( action, success ? "success" : "failure", { handlerName: "MaestroGuitarModuleBuilder", version: "v20-UNIFIED", ...metadata, } ); console.log(`βœ… [v20] Brain learning SUCCESS for ${action}`); } } catch (error) { console.log(`❌ [v20] Brain learning failed: ${error}`); } } // πŸ”§ ENHANCED: Updated interfaces for rich template processing + SVG architecture interface ModuleSpec { name: string; type: "component" | "hook" | "util" | "test" | "engine" | "worklet"; // πŸ†• Added engine/worklet hasJSX: boolean; isReactComponent: boolean; path: string; template?: string; starterCode?: string; } interface SpecificationData { requirements: string[]; modules: string[]; features: string[]; constraints: string[]; starterTemplates: Array<{ code: string; language: string; name?: string }>; componentSpecs: Array<{ name: string; description: string; type: string }>; richTemplates: Map; processedSpecs?: string[]; createFiles?: Array<{ path: string; type: string; description?: string }>; // ← NEW for Test #3A } interface MaestroModule { name: string; path: string; dependencies: string[]; complexity: "low" | "medium" | "high"; priority: number; hasWebAudio: boolean; hasCanvas: boolean; hasSVG: boolean; // πŸ†• SVG architecture support description: string; moduleType: "component" | "hook" | "util" | "test" | "engine" | "worklet"; // πŸ†• Added engine/worklet templateSource?: "spec" | "starter" | "rich" | "generated"; isUpdate?: boolean; } interface BuildPlan { modules: MaestroModule[]; buildOrder: string[]; estimatedTime: number; dependencies: string[]; conflicts: string[]; processedSpecs: string[]; } interface ModuleTemplate { name: string; content: string; imports: string[]; exports: string[]; tests?: string; extension: string; source: "spec" | "starter" | "rich" | "generated"; } export class MaestroGuitarModuleBuilder { private brainConnector: BrainConnector; private outputChannel: vscode.OutputChannel; private workspaceRoot: string; private maestroInputFolder: string; private brainDataPath?: string; constructor() { this.brainConnector = new BrainConnector(); this.outputChannel = vscode.window.createOutputChannel( "Cipher Maestro Guitar Builder" ); const maestroRoot = findMaestroProjectRoot(); this.workspaceRoot = maestroRoot || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || ""; this.maestroInputFolder = path.join(this.workspaceRoot, "maestro-ai-input"); if (maestroRoot) { const workspaceFolder = vscode.workspace.workspaceFolders?.find( (folder) => folder.uri.fsPath === path.dirname(maestroRoot) ); if (workspaceFolder) { this.brainDataPath = path.join( workspaceFolder.uri.fsPath, "..", "brain" ); } } console.log("🎸 Maestro Guitar Module Builder initialized"); console.log(`πŸ“ Workspace Root: ${this.workspaceRoot}`); console.log(`πŸ“¦ Input Folder: ${this.maestroInputFolder}`); if (this.brainDataPath) { console.log(`🧠 Brain Path: ${this.brainDataPath}`); } } private getFileExtension(moduleSpec: ModuleSpec): string { const { type, hasJSX, isReactComponent } = moduleSpec; // πŸ†• New file types for audio architecture if (type === "engine" || type === "worklet") { return ".ts"; } if (isReactComponent || hasJSX) { return ".tsx"; } if (type === "hook" && moduleSpec.name.startsWith("use")) { return ".tsx"; } if (type === "test") { return hasJSX ? ".test.tsx" : ".test.ts"; } return ".ts"; } private analyzeModuleContent(module: MaestroModule): { hasJSX: boolean; isReactComponent: boolean; hasSVG: boolean; // πŸ†• SVG detection } { const { name, moduleType, description } = module; if (moduleType === "component") { // 🎨 SVG-first approach for tab components (Songsterr discovery!) const hasSVG = name.toLowerCase().includes("tab") || name.toLowerCase().includes("fret") || description.toLowerCase().includes("svg") || description.toLowerCase().includes("interactive"); return { hasJSX: true, isReactComponent: true, hasSVG }; } if (moduleType === "hook" && name.startsWith("use")) { return { hasJSX: true, isReactComponent: false, hasSVG: false }; } // πŸ†• Audio engines and worklets don't use JSX if (moduleType === "engine" || moduleType === "worklet") { return { hasJSX: false, isReactComponent: false, hasSVG: false }; } const componentPatterns = [ /Component$/, /Page$/, /Modal$/, /Button$/, /Display$/, /Controller$/, /Overlay$/, /Isolator$/, /Diagram$/, ]; const isReactComponent = componentPatterns.some((pattern) => pattern.test(name) ); return { hasJSX: isReactComponent, isReactComponent, hasSVG: false, }; } public async buildMaestroGuitarModules( specPath?: string ): Promise { try { // πŸ”” Starting notification vscode.window.showInformationMessage( "🎸 Maestro.ai Guitar Practice Module Builder starting...", { modal: false } ); this.outputChannel.appendLine( `🎸 Starting Maestro.ai Guitar Practice module generation with SVG architecture...` ); console.log("🎸 === MAESTRO MODULE BUILDER START (SVG + AUDIO) ==="); const brainConnected = isBrainConnected(); console.log(`🧠 Brain connection status: ${brainConnected}`); if (brainConnected) { console.log("🧠 Brain connected - applying intelligence"); vscode.window.showInformationMessage("🧠 Brain intelligence active!"); (this.brainConnector as any).learnFromAction( "maestro_guitar_build_start", "success", { specPath, inputFolder: this.maestroInputFolder, svgArchitecture: true, } ); } else { console.log("🧠 Brain not connected - proceeding without intelligence"); try { const brainInterface = getBrainInterface(); console.log( `🧠 Alternative brain check: ${brainInterface ? "Available" : "Not available"}` ); } catch (error) { console.log(`🧠 Brain interface error: ${error}`); } } const protectionResult = protectMaestroGuitarInstallation(); this.outputChannel.appendLine( `πŸ›‘οΈ Protection applied: ${protectionResult ? "βœ… Active" : "❌ Failed"}` ); console.log(`πŸ›‘οΈ Protection result: ${protectionResult}`); // πŸ”” Analyzing specs notification vscode.window.showInformationMessage("πŸ“‹ Analyzing specifications and templates..."); const specs = await this.analyzeSpecifications(specPath); console.log( `πŸ“‹ Analyzed specs - found ${specs.starterTemplates.length} code blocks, ${specs.richTemplates.size} rich templates` ); const buildPlan = await this.createBuildPlan(specs); console.log( `πŸ—οΈ Build plan created - ${buildPlan.modules.length} modules to build` ); // πŸ”” Build execution notification if (buildPlan.modules.length > 0) { vscode.window.showInformationMessage( `πŸ”¨ Building ${buildPlan.modules.length} modules with SVG + Audio architecture...` ); } await this.executeBuildPlan(buildPlan); console.log("βœ… Build plan execution completed"); // βœ… v20 Brain Learning: Build plan execution success await performBrainLearning("build-plan-execution", true, { templatesFound: specs.starterTemplates.length, richTemplatesFound: specs.richTemplates.size, }); // 🎯 NEW: Create additional files if specified (Test #3A) if (specs.createFiles && specs.createFiles.length > 0) { // πŸ”” File creation notification vscode.window.showInformationMessage( `πŸ“ Creating ${specs.createFiles.length} additional files...` ); const maestroRoot = findMaestroProjectRoot(); if (maestroRoot) { await this.createNewFiles(specs.createFiles, maestroRoot); console.log( `πŸ“ Created ${specs.createFiles.length} additional files` ); // πŸ”” Files created notification vscode.window.showInformationMessage( `βœ… Created ${specs.createFiles.length} new files successfully!` ); // βœ… v20 Brain Learning: File creation success await performBrainLearning("file-creation", true, { filesCreated: specs.createFiles.length, }); } } if (buildPlan.processedSpecs.length > 0) { await this.cleanupProcessedFiles(buildPlan.processedSpecs); console.log( `🧹 Cleaned up ${buildPlan.processedSpecs.length} processed spec files` ); } else { console.log(`🧹 No spec files to clean up`); } if (isBrainConnected()) { (this.brainConnector as any).learnFromAction( "maestro_guitar_build_complete", "success", buildPlan ); await shareAnalysisData("maestro_guitar_build_complete", buildPlan); } await this.displayBuildResults(buildPlan, specs.createFiles); // πŸ”” Success notification with summary const totalFiles = buildPlan.modules.length + (specs.createFiles?.length || 0); vscode.window.showInformationMessage( `🎸 Maestro.ai Build Complete! βœ… ${totalFiles} files created with SVG + Audio architecture`, "View Results" ).then(selection => { if (selection === "View Results") { this.outputChannel.show(); } }); console.log("🎸 === MAESTRO MODULE BUILDER COMPLETE (SVG + AUDIO) ==="); return buildPlan; } catch (error) { this.outputChannel.appendLine( `❌ Error building Maestro.ai guitar modules: ${error}` ); console.error("❌ Maestro module builder error:", error); // πŸ”” Error notification vscode.window.showErrorMessage( `❌ Maestro.ai Build Failed: ${error instanceof Error ? error.message : String(error)}`, "View Logs" ).then(selection => { if (selection === "View Logs") { this.outputChannel.show(); } }); if (isBrainConnected()) { (this.brainConnector as any).learnFromAction( "maestro_guitar_build_error", "failure", { error: error instanceof Error ? error.message : String(error) } ); } throw error; } } private async analyzeSpecifications( specPath?: string ): Promise { const specs: SpecificationData = { requirements: [], modules: [], features: [], constraints: [], starterTemplates: [], componentSpecs: [], richTemplates: new Map(), processedSpecs: [], }; try { console.log("πŸ” Analyzing specifications..."); console.log(`πŸ“‚ Input folder: ${this.maestroInputFolder}`); console.log( `πŸ“‚ Folder exists: ${fs.existsSync(this.maestroInputFolder)}` ); const brainConnected = isBrainConnected(); console.log(`🧠 Brain connection check result: ${brainConnected}`); const specFiles = await this.findSpecificationFiles(specPath); console.log(`πŸ“„ Found ${specFiles.length} specification files`); if (specFiles.length > 0) { console.log( `πŸ“‹ Spec files: ${specFiles.map((f) => path.basename(f)).join(", ")}` ); } else { console.log( `⚠️ No spec files found - checking input folder contents...` ); if (fs.existsSync(this.maestroInputFolder)) { const allFiles = fs.readdirSync(this.maestroInputFolder); console.log(`πŸ“ Input folder contents: ${allFiles.join(", ")}`); } } for (const file of specFiles) { console.log(`πŸ“– Processing spec file: ${path.basename(file)}`); const content = await fs.promises.readFile(file, "utf8"); console.log(`πŸ“„ File content length: ${content.length} characters`); await this.parseSpecification(content, specs, file); } await this.loadRichTemplates(specs); if (isBrainConnected()) { (this.brainConnector as any).learnFromAction( "spec_analysis", "success", { specsCount: specFiles.length, starterTemplates: specs.starterTemplates.length, richTemplates: specs.richTemplates.size, } ); } specs.processedSpecs = specFiles; } catch (error) { this.outputChannel.appendLine( `⚠️ Warning: Could not fully analyze specifications: ${error}` ); console.warn("⚠️ Spec analysis warning:", error); } return specs; } private async findSpecificationFiles(specPath?: string): Promise { const specFiles: string[] = []; if (specPath && fs.existsSync(specPath)) { specFiles.push(specPath); console.log(`πŸ“Ž Using provided spec file: ${specPath}`); } const searchPaths = [ this.maestroInputFolder, path.join(this.maestroInputFolder, "component-specs"), path.join(this.maestroInputFolder, "feature-requirements"), path.join(this.maestroInputFolder, "integration-plans"), ]; for (const searchPath of searchPaths) { if (fs.existsSync(searchPath)) { console.log(`πŸ” Scanning: ${searchPath}`); try { const files = await fs.promises.readdir(searchPath); for (const file of files) { const fullPath = path.join(searchPath, file); const stats = await fs.promises.stat(fullPath); if (stats.isFile() && this.isSpecificationFile(file)) { specFiles.push(fullPath); console.log(`πŸ“„ Found spec: ${file}`); } } } catch (error) { console.warn(`⚠️ Could not scan ${searchPath}:`, error); } } } return [...new Set(specFiles)]; } private isSpecificationFile(fileName: string): boolean { const lower = fileName.toLowerCase(); return ( lower.endsWith(".md") || lower.endsWith(".txt") || lower.includes("spec") || lower.includes("requirement") || lower.includes("guitar") || lower.includes("practice") || lower.includes("component") ); } private async parseSpecification( content: string, specs: SpecificationData, filePath: string ): Promise { console.log(`πŸ“– Parsing specification from: ${path.basename(filePath)}`); const codeBlockPattern = /```(?:typescript|tsx|javascript|jsx|ts|js)?\n([\s\S]*?)```/g; let match; let codeBlockCount = 0; while ((match = codeBlockPattern.exec(content)) !== null) { const code = match[1].trim(); if (code.length > 50) { const language = this.detectCodeLanguage(code); const name = this.extractComponentName(code) || `component_${codeBlockCount}`; specs.starterTemplates.push({ code, language, name, }); codeBlockCount++; console.log(`πŸ“ Extracted code block: ${name} (${language})`); } } const componentPattern = /##?\s*Component:\s*(.+?)\n([\s\S]*?)(?=\n##|\n#|$)/gi; while ((match = componentPattern.exec(content)) !== null) { const name = match[1].trim(); const description = match[2].trim(); const type = this.detectComponentTypeFromDescription(description); specs.componentSpecs.push({ name, description, type }); console.log(`🎯 Found component spec: ${name} (${type})`); if ( name.toLowerCase().includes("test") || name.toLowerCase().startsWith("test") ) { specs.starterTemplates.push({ code: `// Component: ${name}\n// ${description}`, language: "tsx", name: name, }); console.log(`πŸ§ͺ Added test component: ${name}`); } } const updatePattern = /##?\s*Update:\s*(.+?)\n([\s\S]*?)(?=\n##|\n#|$)/gi; while ((match = updatePattern.exec(content)) !== null) { const name = match[1].trim(); const description = match[2].trim(); const type = this.detectComponentTypeFromDescription(description); specs.componentSpecs.push({ name, description: `UPDATE_FLAG:${description}`, type, }); console.log(`πŸ”„ Found UPDATE spec: ${name} (${type})`); specs.starterTemplates.push({ code: `// UPDATE: ${name}\n// ${description}`, language: "tsx", name: name, }); console.log(`πŸ”„ Added update template: ${name}`); } // 🎯 NEW: Parse Create Files sections (Test #3A) const createFilesPattern = /##?\s*Create Files?:\s*\n([\s\S]*?)(?=\n##|\n#|$)/i; const createFilesMatch = content.match(createFilesPattern); if (createFilesMatch) { const fileLines = createFilesMatch[1] .split("\n") .filter((line) => line.trim().startsWith("-")) .map((line) => line.trim().replace(/^-\s*/, "")); for (const fileLine of fileLines) { const [filePath, ...descParts] = fileLine.split(" - "); const description = descParts.join(" - ") || ""; const fileType = this.detectFileTypeFromPath(filePath.trim()); if (!specs.createFiles) specs.createFiles = []; specs.createFiles.push({ path: filePath.trim(), type: fileType, description: description.trim(), }); console.log( `πŸ“ Found file to create: ${filePath.trim()} (${fileType})` ); } } const requirementPattern = /##?\s*Requirements?\s*\n([\s\S]*?)(?=\n##|\n#|$)/i; const requirementMatch = content.match(requirementPattern); if (requirementMatch) { const requirements = requirementMatch[1] .split("\n") .filter( (line) => line.trim().startsWith("-") || line.trim().startsWith("*") ) .map((line) => line.trim().replace(/^[-*]\s*/, "")); specs.requirements.push(...requirements); console.log(`πŸ“‹ Extracted ${requirements.length} requirements`); } const modulePattern = /guitar-[\w-]+|practice-[\w-]+|vocal-[\w-]+|audio-[\w-]+/g; const modules = content.match(modulePattern) || []; specs.modules.push(...modules); console.log(`πŸ—οΈ Found ${modules.length} module references`); const featurePattern = /##?\s*Features?\s*\n([\s\S]*?)(?=\n##|\n#|$)/i; const featureMatch = content.match(featurePattern); if (featureMatch) { const features = featureMatch[1] .split("\n") .filter( (line) => line.trim().startsWith("-") || line.trim().startsWith("*") ) .map((line) => line.trim().replace(/^[-*]\s*/, "")); specs.features.push(...features); console.log(`✨ Extracted ${features.length} features`); } } // 🎯 ENHANCED: Support methods for Test #3A + new audio architecture private detectFileTypeFromPath(filePath: string): string { const extension = path.extname(filePath); const fileName = path.basename(filePath, extension); const pathLower = filePath.toLowerCase(); // πŸ†• Audio engine detection if ( pathLower.includes("/engines/") || fileName.toLowerCase().includes("engine") ) { return "engine"; } // πŸ†• Audio worklet detection if ( pathLower.includes("/worklets/") || fileName.toLowerCase().includes("worklet") ) { return "worklet"; } // 🎡 PARSER CLASSIFICATION - Core modules, not utilities if ( pathLower.includes("/parsers/") || fileName.toLowerCase().includes("parser") ) { return "parser"; // Treat as testable core modules } if (extension === ".tsx") { if (fileName.includes("test") || fileName.includes("Test")) { return "test"; } return "component"; } if (extension === ".ts") { if (fileName.includes("util") || filePath.includes("/utils/")) { return "util"; } if (filePath.includes("/data/") || fileName.includes("data")) { return "data"; } return "module"; } return "file"; } private async createNewFiles( createFiles: Array<{ path: string; type: string; description?: string }>, maestroRoot: string ): Promise { if (!createFiles || createFiles.length === 0) return; console.log(`πŸ“ Creating ${createFiles.length} new files...`); for (const fileSpec of createFiles) { try { const fullPath = path.join(maestroRoot, fileSpec.path); const dirPath = path.dirname(fullPath); if (!fs.existsSync(dirPath)) { await fs.promises.mkdir(dirPath, { recursive: true }); console.log( `πŸ“ Created directory: ${path.relative(maestroRoot, dirPath)}` ); } const content = await this.generateFileContent(fileSpec); await fs.promises.writeFile(fullPath, content); console.log(`πŸ“„ Created file: ${fileSpec.path}`); // πŸ”§ IMPROVED: Let indexSyncUtils.ts decide folder patterns automatically const fileName = path.basename( fileSpec.path, path.extname(fileSpec.path) ); await this.updateIndexFile( dirPath, fileName, path.extname(fileSpec.path) ); } catch (error) { console.error(`❌ Failed to create ${fileSpec.path}:`, error); } } } // πŸ”§ ENHANCED: generateFileContent method with SVG + audio support private async generateFileContent(fileSpec: { path: string; type: string; description?: string; }): Promise { const fileName = path.basename(fileSpec.path, path.extname(fileSpec.path)); const description = fileSpec.description || `Generated ${fileSpec.type}`; // βœ… Special handling for guitar-tabs (already working) if (fileSpec.type === "data" && fileName.includes("guitar-tabs")) { return this.generateGuitarTabsData(); } // 🎨 NEW: SVG-based TabPlayer template (Songsterr discovery!) if (fileSpec.type === "component" && fileName === "TabPlayer") { return this.generateSVGTabPlayerTemplate(); } // πŸ†• Audio engine template if (fileSpec.type === "engine") { return this.generateAudioEngineTemplate(fileName, description); } // πŸ†• Audio worklet template if (fileSpec.type === "worklet") { return this.generateAudioWorkletTemplate(fileName, description); } // πŸ†• Tone.js hook template if (fileSpec.type === "hook" && fileName.toLowerCase().includes("audio")) { return this.generateToneHookTemplate(fileName, description); } // πŸ”§ NEW: Proper test file template if (fileSpec.type === "test") { const componentName = fileName.replace(".test", ""); return this.generateTestFileTemplate(componentName, description); } // πŸ”§ NEW: Proper utility file template if (fileSpec.type === "util") { return this.generateUtilityFileTemplate(fileName, description); } // πŸ”§ NEW: Proper component file template if (fileSpec.type === "component") { return this.generateComponentFileTemplate(fileName, description); } // πŸ”§ NEW: Proper data file template if (fileSpec.type === "data") { return this.generateDataFileTemplate(fileName, description); } // βœ… Default fallback (improved) return this.generateDefaultFileTemplate( fileName, description, fileSpec.type ); } private generateGuitarTabsData(): string { return `// 🎸 Guitar Tabs Data - Sample tablature data // Generated by Cipher Maestro Builder export interface GuitarTab { id: string; title: string; artist: string; tuning: string[]; bpm: number; timeSignature: string; tabs: TabMeasure[]; } export interface TabMeasure { strings: string[]; // 6 strings, high E to low E timing: number[]; // Beat timing for each note } export const sampleTabs: GuitarTab[] = [ { id: 'wonderwall-intro', title: 'Wonderwall (Intro)', artist: 'Oasis', tuning: ['E', 'B', 'G', 'D', 'A', 'E'], bpm: 87, timeSignature: '4/4', tabs: [ { strings: ['3-2-0---', '3-3-3---', '0-0-0---', '0-0-0---', '2-2-2---', '3-3-3---'], timing: [1, 1.5, 2, 2.5, 3, 3.5] } ] } ]; export const guitarTabsData = { tabs: sampleTabs, getTabs: () => sampleTabs, getTabById: (id: string) => sampleTabs.find(tab => tab.id === id), addTab: (tab: GuitarTab) => sampleTabs.push(tab) }; export default guitarTabsData;`; } // 🎨 NEW: SVG-based TabPlayer template (Songsterr inspiration!) private generateSVGTabPlayerTemplate(): string { return `'use client'; import React, { useState, useRef, useEffect } from 'react'; interface GuitarTab { id: string; title: string; artist: string; tuning: string[]; bpm: number; timeSignature: string; tabs: TabMeasure[]; } interface TabMeasure { strings: string[]; timing: number[]; } interface TabPlayerProps { tabData?: GuitarTab; className?: string; onTabChange?: (position: number) => void; } export const TabPlayer: React.FC = ({ tabData, className = "", onTabChange }) => { const [currentPosition, setCurrentPosition] = useState(0); const [isPlaying, setIsPlaying] = useState(false); const [currentBeat, setCurrentBeat] = useState(0); const svgRef = useRef(null); const handlePlay = () => { setIsPlaying(!isPlaying); onTabChange?.(currentPosition); }; const handleFretClick = (stringIndex: number, fretPosition: number) => { console.log(\`Clicked string \${stringIndex}, fret \${fretPosition}\`); onTabChange?.(fretPosition); }; if (!tabData) { return (

No tab data available

); } return (

🎼 {tabData.title} - {tabData.artist}

BPM: {tabData.bpm} | Time: {tabData.timeSignature}

Beat: {currentBeat + 1}
{/* 🎨 SVG-based Interactive Tablature (Songsterr-inspired) */}
{/* String Lines */} {Array.from({ length: 6 }, (_, stringIndex) => ( ))} {/* Beat Markers */} {Array.from({ length: 16 }, (_, beatIndex) => ( ))} {/* Fret Numbers/Notes */} {tabData.tabs.map((measure, measureIndex) => measure.strings.map((stringNotes, stringIndex) => stringNotes.split('').map((note, noteIndex) => { if (note !== '-' && note !== ' ') { const xPos = 100 + noteIndex * 40; const yPos = 50 + stringIndex * 40; return ( {/* Interactive Fret Circle */} handleFretClick(stringIndex, parseInt(note))} style={{ cursor: 'pointer' }} /> {/* Fret Number */} handleFretClick(stringIndex, parseInt(note))} style={{ cursor: 'pointer', userSelect: 'none' }} > {note} ); } return null; }) ) )} {/* Playback Cursor */} {isPlaying && ( )} {/* String Labels */} {['E', 'B', 'G', 'D', 'A', 'E'].map((tuning, index) => ( {tuning} ))}

🎸 Interactive SVG Tablature - Click fret positions to hear notes

Tuning: {tabData.tuning.join(' - ')}

); }; export default TabPlayer;`; } // πŸ†• Audio Engine Template Generator private generateAudioEngineTemplate( fileName: string, description: string ): string { const className = fileName.replace(/Engine$/, "") + "Engine"; return `// 🎡 ${className} - ${description} // Generated by Cipher Maestro Builder - Audio Engine Architecture export interface ${className}Config { sampleRate: number; bufferSize: number; channels: number; } export interface ${className}State { isPlaying: boolean; currentTime: number; volume: number; tempo: number; } export class ${className} { private audioContext: AudioContext | null = null; private config: ${className}Config; private state: ${className}State; private gainNode: GainNode | null = null; constructor(config: Partial<${className}Config> = {}) { this.config = { sampleRate: 44100, bufferSize: 4096, channels: 2, ...config }; this.state = { isPlaying: false, currentTime: 0, volume: 1.0, tempo: 120 }; this.initialize(); } async initialize(): Promise { try { this.audioContext = new (window.AudioContext || (window as any).webkitAudioContext)({ sampleRate: this.config.sampleRate }); this.gainNode = this.audioContext.createGain(); this.gainNode.connect(this.audioContext.destination); console.log(\`\${className} initialized with sample rate: \${this.config.sampleRate}Hz\`); } catch (error) { console.error(\`Failed to initialize \${className}:\`, error); throw error; } } async start(): Promise { if (!this.audioContext) { await this.initialize(); } if (this.audioContext?.state === 'suspended') { await this.audioContext.resume(); } this.state.isPlaying = true; console.log(\`\${className} started\`); } stop(): void { this.state.isPlaying = false; this.state.currentTime = 0; console.log(\`\${className} stopped\`); } setVolume(volume: number): void { if (this.gainNode) { this.gainNode.gain.setValueAtTime(Math.max(0, Math.min(1, volume)), this.audioContext!.currentTime); this.state.volume = volume; } } setTempo(tempo: number): void { this.state.tempo = Math.max(60, Math.min(200, tempo)); console.log(\`Tempo set to: \${this.state.tempo} BPM\`); } getState(): ${className}State { return { ...this.state }; } getCurrentTime(): number { return this.audioContext?.currentTime || 0; } dispose(): void { if (this.audioContext) { this.audioContext.close(); this.audioContext = null; } console.log(\`\${className} disposed\`); } } export default ${className};`; } // πŸ†• Audio Worklet Template Generator private generateAudioWorkletTemplate( fileName: string, description: string ): string { const className = fileName.replace(/Worklet$/, "") + "Worklet"; return `// 🎚️ ${className} - ${description} // Generated by Cipher Maestro Builder - Audio Worklet for Low-Latency Processing // Worklet Processor (runs in AudioWorkletGlobalScope) class ${className}Processor extends AudioWorkletProcessor { private sampleRate: number; private currentSample: number = 0; constructor() { super(); this.sampleRate = 44100; // Will be overridden by actual sample rate this.port.onmessage = (event) => { const { type, data } = event.data; this.handleMessage(type, data); }; } handleMessage(type: string, data: any): void { switch (type) { case 'SET_SAMPLE_RATE': this.sampleRate = data; break; case 'RESET': this.currentSample = 0; break; default: console.warn(\`Unknown message type: \${type}\`); } } process( inputs: Float32Array[][], outputs: Float32Array[][], parameters: Record ): boolean { const input = inputs[0]; const output = outputs[0]; if (input && input.length > 0) { const inputChannel = input[0]; const outputChannel = output[0]; // Process audio samples for (let i = 0; i < inputChannel.length; i++) { // Example processing: simple pass-through with gain const gain = parameters.gain ? parameters.gain[i] : 1.0; outputChannel[i] = inputChannel[i] * gain; this.currentSample++; } // Send periodic updates to main thread if (this.currentSample % (this.sampleRate * 0.1) === 0) { this.port.postMessage({ type: 'SAMPLE_UPDATE', currentSample: this.currentSample, timestamp: this.currentSample / this.sampleRate }); } } return true; // Keep processor alive } } // Register the processor registerProcessor('${fileName.toLowerCase().replace(/worklet$/, "")}-processor', ${className}Processor); // Main Thread Interface export class ${className} { private audioContext: AudioContext | null = null; private workletNode: AudioWorkletNode | null = null; private isInitialized: boolean = false; async initialize(audioContext: AudioContext): Promise { if (this.isInitialized) return; this.audioContext = audioContext; try { // Add the worklet module await audioContext.audioWorklet.addModule( URL.createObjectURL(new Blob([ \`(\${${className}Processor.toString()})()\` ], { type: 'application/javascript' })) ); // Create the worklet node this.workletNode = new AudioWorkletNode( audioContext, '${fileName.toLowerCase().replace(/worklet$/, "")}-processor', { numberOfInputs: 1, numberOfOutputs: 1, channelCount: 2, processorOptions: { sampleRate: audioContext.sampleRate } } ); // Set up message handling this.workletNode.port.onmessage = (event) => { this.handleWorkletMessage(event.data); }; this.isInitialized = true; console.log(\`\${className} initialized successfully\`); } catch (error) { console.error(\`Failed to initialize \${className}:\`, error); throw error; } } private handleWorkletMessage(data: any): void { const { type, ...payload } = data; switch (type) { case 'SAMPLE_UPDATE': // Handle sample updates from worklet break; default: console.log(\`Worklet message:\`, data); } } connect(destination: AudioNode): void { if (this.workletNode) { this.workletNode.connect(destination); } } disconnect(): void { if (this.workletNode) { this.workletNode.disconnect(); } } setParameter(name: string, value: number): void { if (this.workletNode) { const param = (this.workletNode.parameters as any).get(name); if (param) { param.setValueAtTime(value, this.audioContext!.currentTime); } } } sendMessage(type: string, data?: any): void { if (this.workletNode) { this.workletNode.port.postMessage({ type, data }); } } dispose(): void { this.disconnect(); this.workletNode = null; this.isInitialized = false; console.log(\`\${className} disposed\`); } } export default ${className};`; } // πŸ†• Tone.js Hook Template Generator private generateToneHookTemplate( hookName: string, description: string ): string { return `// 🎹 ${hookName} - ${description} // Generated by Cipher Maestro Builder - Tone.js Integration Hook import { useEffect, useRef, useState, useCallback } from 'react'; import * as Tone from 'tone'; export interface ${hookName}Options { autoStart?: boolean; volume?: number; effects?: string[]; } export interface ${hookName}State { isPlaying: boolean; isLoaded: boolean; currentTime: string; volume: number; } export const ${hookName} = (options: ${hookName}Options = {}) => { const [state, setState] = useState<${hookName}State>({ isPlaying: false, isLoaded: false, currentTime: '0:0:0', volume: options.volume || 0.8 }); const toneRef = useRef(null); const transportRef = useRef(Tone.Transport); useEffect(() => { const initializeTone = async () => { try { // Ensure Tone.js is started if (Tone.context.state !== 'running') { await Tone.start(); } // Initialize your Tone.js components here // Example: Synthesizer, Player, Effects, etc. setState(prev => ({ ...prev, isLoaded: true })); if (options.autoStart) { handleStart(); } } catch (error) { console.error('Failed to initialize Tone.js:', error); } }; initializeTone(); // Cleanup on unmount return () => { if (toneRef.current) { toneRef.current.dispose(); } Tone.Transport.stop(); Tone.Transport.cancel(); }; }, [options.autoStart]); // Update transport position useEffect(() => { const updatePosition = () => { setState(prev => ({ ...prev, currentTime: Tone.Transport.position.toString() })); }; const intervalId = setInterval(updatePosition, 100); return () => clearInterval(intervalId); }, [state.isPlaying]); const start = useCallback(async () => { try { if (Tone.context.state !== 'running') { await Tone.start(); } Tone.Transport.start(); setState(prev => ({ ...prev, isPlaying: true })); } catch (error) { console.error('Failed to start transport:', error); } }, []); const stop = useCallback(() => { Tone.Transport.stop(); setState(prev => ({ ...prev, isPlaying: false })); }, []); const pause = useCallback(() => { Tone.Transport.pause(); setState(prev => ({ ...prev, isPlaying: false })); }, []); const reset = useCallback(() => { Tone.Transport.stop(); Tone.Transport.position = 0; setState(prev => ({ ...prev, isPlaying: false, currentTime: '0:0:0' })); }, []); const setVolume = useCallback((volume: number) => { const clampedVolume = Math.max(0, Math.min(1, volume)); Tone.Destination.volume.value = Tone.gainToDb(clampedVolume); setState(prev => ({ ...prev, volume: clampedVolume })); }, []); const setBPM = useCallback((bpm: number) => { Tone.Transport.bpm.value = Math.max(60, Math.min(200, bpm)); }, []); const configure = useCallback((newOptions: Partial<${hookName}Options>) => { if (newOptions.volume !== undefined) { setVolume(newOptions.volume); } // Handle other configuration options }, [setVolume]); const handleStart = start; return { ...state, start, stop, pause, reset, setVolume, setBPM, configure, }; }; export default ${hookName}; `; } // πŸ”§ NEW: Proper test file template generator private generateTestFileTemplate( componentName: string, description: string ): string { const componentLower = componentName.toLowerCase(); return `import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import { ${componentName} } from './${componentName}'; // πŸ§ͺ Tests for ${componentName} // Generated by Cipher Maestro Builder describe('${componentName}', () => { test('renders without crashing', () => { render(<${componentName} />); expect(screen.getByTestId('${componentLower}')).toBeInTheDocument(); }); test('displays component correctly', () => { render(<${componentName} />); expect(screen.getByText(/${componentName}/)).toBeInTheDocument(); }); test('handles props correctly', () => { const mockOnAction = jest.fn(); render(<${componentName} onAction={mockOnAction} />); // Add component-specific tests here }); test('applies custom className', () => { const customClass = 'custom-test-class'; render(<${componentName} className={customClass} />); const element = screen.getByTestId('${componentLower}'); expect(element).toHaveClass(customClass); }); }); `; } // πŸ”§ NEW: Proper utility file template generator private generateUtilityFileTemplate( fileName: string, description: string ): string { // Convert kebab-case to camelCase for variable names const camelCaseVar = fileName .split("-") .map((word, index) => index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1) ) .join(""); const capitalizedName = camelCaseVar.charAt(0).toUpperCase() + camelCaseVar.slice(1); return `// πŸ”§ ${camelCaseVar} - ${description} // Generated by Cipher Maestro Builder export interface ${capitalizedName}Options { // Configuration options for ${camelCaseVar} } export interface ${capitalizedName}Result { // Result type for ${camelCaseVar} operations success: boolean; data?: any; error?: string; } export const ${camelCaseVar} = { /** * Process data using ${camelCaseVar} */ process: (input: string, options?: ${capitalizedName}Options): ${capitalizedName}Result => { try { // Implementation here return { success: true, data: input }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error' }; } }, /** * Validate input for ${camelCaseVar} */ validate: (input: string): boolean => { return typeof input === 'string' && input.length > 0; } }; export default ${camelCaseVar}; `; } // πŸ”§ NEW: Proper component file template generator private generateComponentFileTemplate( fileName: string, description: string ): string { return `'use client'; import React, { useState } from 'react'; interface ${fileName}Props { className?: string; onAction?: (action: string) => void; } /** * ${fileName} - ${description} * Generated by Cipher Maestro Builder */ export const ${fileName}: React.FC<${fileName}Props> = ({ className = "", onAction }) => { const [isActive, setIsActive] = useState(false); const handleAction = () => { setIsActive(!isActive); onAction?.('toggle'); }; return (

🎸 ${fileName}

{isActive ? 'Active' : 'Inactive'}

${description}

); }; export default ${fileName}; `; } // πŸ”§ NEW: Proper data file template generator private generateDataFileTemplate( fileName: string, description: string ): string { const camelCaseVar = fileName .split("-") .map((word, index) => index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1) ) .join(""); const capitalizedName = camelCaseVar.charAt(0).toUpperCase() + camelCaseVar.slice(1); return `// πŸ“Š ${camelCaseVar} - ${description} // Generated by Cipher Maestro Builder export interface ${capitalizedName}Data { id: string; name: string; // Add specific data structure here } export const ${camelCaseVar}Data: ${capitalizedName}Data[] = [ // Add sample data here ]; export const ${camelCaseVar} = { data: ${camelCaseVar}Data, getAll: () => ${camelCaseVar}Data, getById: (id: string) => ${camelCaseVar}Data.find(item => item.id === id), add: (item: ${capitalizedName}Data) => ${camelCaseVar}Data.push(item) }; export default ${camelCaseVar}; `; } // πŸ”§ ENHANCED: Default template generator with new file types private generateDefaultFileTemplate( fileName: string, description: string, fileType: string ): string { const camelCaseVar = fileName .split("-") .map((word, index) => index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1) ) .join(""); return `// 🎸 ${camelCaseVar} - ${description} // Generated by Cipher Maestro Builder export const ${camelCaseVar} = { // ${fileType} implementation info: '${description}', initialize: () => { console.log('${camelCaseVar} initialized'); } }; export default ${camelCaseVar}; `; } // Rest of the existing working methods from Test #2... private async loadRichTemplates(specs: SpecificationData): Promise { console.log("🎨 Loading rich component templates..."); const hasSpecs = specs.starterTemplates.length > 0 || specs.componentSpecs.length > 0 || specs.requirements.length > 0; if (!hasSpecs) { console.log("πŸ“¦ No specifications found, adding default rich templates"); this.addDefaultRichTemplates(specs); } else { console.log( `βœ… Found specifications (${specs.starterTemplates.length} templates, ${specs.componentSpecs.length} specs) - skipping default rich templates` ); } } private addDefaultRichTemplates(specs: SpecificationData): void { const defaultTemplates = new Map([ [ "GuitarPracticeGenerator", "// Guitar Practice Generator\nexport const GuitarPracticeGenerator = () => null;", ], [ "VoicePracticeComponent", "// Voice Practice Component\nexport const VoicePracticeComponent = () => null;", ], [ "SVGTabDisplayComponent", // 🎨 Updated to SVG "// SVG Tab Display Component\nexport const SVGTabDisplayComponent = () => null;", ], [ "AudioControllerComponent", "// Audio Controller Component\nexport const AudioControllerComponent = () => null;", ], ]); for (const [name, template] of defaultTemplates) { if (!specs.richTemplates.has(name)) { specs.richTemplates.set(name, template); console.log(`🎨 Added default rich template: ${name}`); } } } private async createBuildPlan(specs: SpecificationData): Promise { console.log("πŸ—οΈ Creating enhanced build plan..."); const modules: MaestroModule[] = []; for (const starterTemplate of specs.starterTemplates) { if (starterTemplate.name) { const module = this.createModuleFromStarterCode( starterTemplate, "starter" ); if (module) { modules.push(module); console.log( `πŸ“ Created module from starter: ${starterTemplate.name}` ); } } } for (const componentSpec of specs.componentSpecs) { const module = this.createModuleFromComponentSpec(componentSpec, "spec"); if (module) { modules.push(module); console.log(`🎯 Created module from spec: ${componentSpec.name}`); } } if (modules.length === 0) { console.log("πŸ“¦ No specification modules found, using rich templates"); for (const [templateName, template] of specs.richTemplates) { const module = this.createModuleFromTemplate( templateName, template, "rich" ); if (module) modules.push(module); } } else { console.log( `βœ… Found ${modules.length} modules from specifications, skipping rich template fallback` ); } if (modules.length === 0) { console.log("πŸ“¦ No templates or specs found, using default module set"); modules.push(...this.getDefaultModules()); } const uniqueModules = this.removeDuplicateModules(modules); console.log(`πŸ—οΈ Build plan: ${uniqueModules.length} unique modules`); const buildOrder = this.calculateBuildOrder(uniqueModules); const buildPlan: BuildPlan = { modules: uniqueModules, buildOrder, estimatedTime: uniqueModules.length * 15, dependencies: this.extractAllDependencies(uniqueModules), conflicts: await this.checkForConflicts(uniqueModules), processedSpecs: specs.processedSpecs || [], }; console.log( `πŸ“Š Build plan complete: ${buildPlan.modules.length} modules, ${buildPlan.dependencies.length} dependencies` ); return buildPlan; } private removeDuplicateModules(modules: MaestroModule[]): MaestroModule[] { const moduleMap = new Map(); console.log(`πŸ” Deduplicating ${modules.length} modules:`); modules.forEach((m, i) => console.log( ` ${i}: ${m.name} (${m.templateSource}, isUpdate: ${m.isUpdate})` ) ); for (const module of modules) { const existing = moduleMap.get(module.name); if (!existing) { moduleMap.set(module.name, module); console.log(`βœ… Added first ${module.name} (${module.templateSource})`); } else { const shouldReplace = this.shouldReplaceModule(existing, module); if (shouldReplace) { moduleMap.set(module.name, module); console.log( `πŸ”„ Replaced ${module.name}: ${existing.templateSource} β†’ ${module.templateSource} (isUpdate: ${existing.isUpdate} β†’ ${module.isUpdate})` ); } else { console.log( `⏭️ Kept existing ${module.name}: ${existing.templateSource} over ${module.templateSource}` ); } } } console.log(`🎯 Final modules:`); Array.from(moduleMap.values()).forEach((m) => console.log( ` ${m.name}: ${m.templateSource}, isUpdate: ${m.isUpdate}, desc: "${m.description.substring(0, 50)}..."` ) ); return Array.from(moduleMap.values()); } private shouldReplaceModule( existing: MaestroModule, candidate: MaestroModule ): boolean { const priorityOrder = { spec: 4, starter: 3, rich: 2, generated: 1 }; const existingPriority = priorityOrder[existing.templateSource || "generated"] || 0; const candidatePriority = priorityOrder[candidate.templateSource || "generated"] || 0; if (candidatePriority > existingPriority) { return true; } if ( candidatePriority === existingPriority && candidate.isUpdate && !existing.isUpdate ) { return true; } return false; } private createModuleFromStarterCode( starterTemplate: { code: string; language: string; name?: string }, source: "starter" ): MaestroModule | null { if (!starterTemplate.name) return null; const module = this.createModuleFromTemplate( starterTemplate.name, starterTemplate.code, source ); if (module && starterTemplate.code.includes("UPDATE:")) { module.isUpdate = true; console.log( `πŸ“ Starter template ${starterTemplate.name} marked as update` ); } console.log( `πŸ“ Created starter module ${starterTemplate.name}: isUpdate=${module?.isUpdate}, description="${module?.description}"` ); return module; } private createModuleFromComponentSpec( componentSpec: { name: string; description: string; type: string }, source: "spec" ): MaestroModule | null { try { const moduleType = componentSpec.type as | "component" | "hook" | "util" | "test" | "engine" // πŸ†• Added | "worklet"; // πŸ†• Added const isUpdate = componentSpec.description.startsWith("UPDATE_FLAG:"); const cleanDescription = isUpdate ? componentSpec.description.replace("UPDATE_FLAG:", "") : componentSpec.description; console.log( `🎯 Creating module ${componentSpec.name}: isUpdate=${isUpdate}, description="${cleanDescription}"` ); return { name: this.sanitizeModuleName(componentSpec.name), path: this.generateModulePath(componentSpec.name, moduleType), dependencies: this.extractDependenciesFromDescription(cleanDescription), complexity: "medium", priority: componentSpec.name.toLowerCase().includes("test") ? 1 : 2, hasWebAudio: cleanDescription.toLowerCase().includes("audio"), hasCanvas: cleanDescription.toLowerCase().includes("display") || cleanDescription.toLowerCase().includes("visual"), hasSVG: cleanDescription.toLowerCase().includes("svg") || cleanDescription.toLowerCase().includes("tab") || cleanDescription.toLowerCase().includes("interactive"), // 🎨 SVG detection description: cleanDescription, moduleType, templateSource: source, isUpdate: isUpdate, }; } catch (error) { console.warn( `⚠️ Could not create module from component spec ${componentSpec.name}:`, error ); return null; } } private createModuleFromTemplate( name: string, template: string, source: "rich" | "starter" ): MaestroModule | null { try { const moduleType = this.detectModuleTypeFromTemplate(template); const complexity = template.length > 2000 ? "high" : template.length > 1000 ? "medium" : "low"; return { name: this.sanitizeModuleName(name), path: this.generateModulePath(name, moduleType), dependencies: this.extractDependenciesFromTemplate(template), complexity, priority: source === "rich" ? 1 : 2, hasWebAudio: template.includes("Web Audio") || template.includes("AudioContext"), hasCanvas: template.includes("canvas") || template.includes("Canvas"), hasSVG: template.includes("SVG") || template.includes("svg") || name.toLowerCase().includes("tab"), // 🎨 SVG detection description: `${name} - Generated from ${source} template`, moduleType, templateSource: source, isUpdate: false, }; } catch (error) { console.warn(`⚠️ Could not create module from template ${name}:`, error); return null; } } // Additional working methods... private async cleanupProcessedFiles(processedSpecs: string[]): Promise { if (processedSpecs.length === 0) return; console.log( `🧹 Cleaning up ${processedSpecs.length} processed spec files...` ); for (const specFile of processedSpecs) { try { const dir = path.dirname(specFile); const processedDir = path.join(dir, "processed"); if (!fs.existsSync(processedDir)) { await fs.promises.mkdir(processedDir, { recursive: true }); console.log(`πŸ“ Created processed directory: ${processedDir}`); } const fileName = path.basename(specFile); const processedPath = path.join(processedDir, fileName); await fs.promises.rename(specFile, processedPath); this.outputChannel.appendLine(`πŸ“ Moved to processed: ${fileName}`); console.log(`πŸ“ Moved to processed: ${fileName} -> ${processedPath}`); } catch (error) { console.warn(`⚠️ Could not move ${specFile} to processed:`, error); this.outputChannel.appendLine( `⚠️ Could not move ${path.basename(specFile)} to processed: ${error}` ); } } } private calculateBuildOrder(modules: MaestroModule[]): string[] { const buildOrder: string[] = []; const built = new Set(); const remaining = [...modules]; while (remaining.length > 0) { const canBuild = remaining.filter((module) => module.dependencies.every( (dep) => built.has(dep) || !modules.some((m) => m.name === dep) ) ); if (canBuild.length === 0) { const next = remaining.sort((a, b) => a.priority - b.priority)[0]; buildOrder.push(next.name); built.add(next.name); remaining.splice(remaining.indexOf(next), 1); } else { const next = canBuild.sort((a, b) => a.priority - b.priority)[0]; buildOrder.push(next.name); built.add(next.name); remaining.splice(remaining.indexOf(next), 1); } } return buildOrder; } private extractAllDependencies(modules: MaestroModule[]): string[] { const deps = new Set(); modules.forEach((module) => module.dependencies.forEach((dep) => deps.add(dep)) ); return Array.from(deps); } private async checkForConflicts(modules: MaestroModule[]): Promise { const conflicts: string[] = []; const maestroRoot = findMaestroProjectRoot(); if (!maestroRoot) { conflicts.push("Maestro.ai project root not found"); return conflicts; } for (const module of modules) { const extension = this.getFileExtension({ name: module.name, type: module.moduleType, hasJSX: this.analyzeModuleContent(module).hasJSX, isReactComponent: this.analyzeModuleContent(module).isReactComponent, path: module.path, }); const fullPath = path.join(maestroRoot, `${module.path}${extension}`); if (fs.existsSync(fullPath)) { conflicts.push(`File already exists: ${module.path}${extension}`); } } return conflicts; } private async executeBuildPlan(buildPlan: BuildPlan): Promise { this.outputChannel.appendLine( `πŸš€ Executing build plan for ${buildPlan.modules.length} modules...` ); console.log( `πŸš€ Executing build plan for ${buildPlan.modules.length} modules` ); const maestroRoot = findMaestroProjectRoot(); if (!maestroRoot) { throw new Error("Maestro.ai project root not found - cannot proceed"); } for (const moduleName of buildPlan.buildOrder) { const module = buildPlan.modules.find((m) => m.name === moduleName); if (module) { console.log(`πŸ”¨ Building module: ${moduleName}`); await this.buildModule(module, maestroRoot); } } } private async buildModule( module: MaestroModule, maestroRoot: string ): Promise { try { this.outputChannel.appendLine(`πŸ”¨ Building ${module.name}...`); console.log( `πŸ”¨ Building ${module.name} from ${module.templateSource} source` ); // πŸ”” Individual module progress notification vscode.window.showInformationMessage( `πŸ”¨ Building ${module.name} (${module.moduleType})...`, { modal: false } ); const fullPath = path.join(maestroRoot, module.path); const template = await this.generateModuleTemplate(module); const finalFilePath = `${fullPath}${template.extension}`; const isUpdate = module.isUpdate || false; const fileExists = fs.existsSync(finalFilePath); if (isUpdate && fileExists) { console.log(`πŸ”„ UPDATE MODE: Backing up existing ${module.name}`); vscode.window.showInformationMessage(`πŸ”„ Updating ${module.name} with new features...`); const { protectFileModification } = await import( "../../shared/indexSyncUtils" ); const backupSuccess = protectFileModification(finalFilePath); if (backupSuccess) { console.log(`πŸ’Ύ Backup created for ${module.name}`); this.outputChannel.appendLine(`πŸ’Ύ Backup created for ${module.name}`); } else { console.warn( `⚠️ Backup failed for ${module.name}, proceeding anyway` ); } const existingContent = await fs.promises.readFile( finalFilePath, "utf8" ); const mergedContent = await this.mergeUpdateWithExisting( existingContent, template.content, module ); template.content = mergedContent; console.log(`πŸ”„ Generated enhanced ${module.name} with new features`); } else if (fileExists && !isUpdate) { console.log( `⚠️ File exists but not an update - creating backup anyway` ); const { protectFileModification } = await import( "../../shared/indexSyncUtils" ); protectFileModification(finalFilePath); } const dirPath = path.dirname(fullPath); try { await vscode.workspace.fs.createDirectory(vscode.Uri.file(dirPath)); } catch {} await fs.promises.writeFile(finalFilePath, template.content); this.outputChannel.appendLine( `βœ… ${module.name} ${isUpdate ? "updated" : "built"} successfully at: ${finalFilePath}` ); console.log( `βœ… Module ${isUpdate ? "updated" : "built"}: ${finalFilePath}` ); // πŸ”” Module completion notification with details const moduleTypeIcon = module.moduleType === 'engine' ? '🎡' : module.moduleType === 'worklet' ? '🎚️' : module.hasSVG ? '🎨' : 'βš›οΈ'; vscode.window.showInformationMessage( `βœ… ${moduleTypeIcon} ${module.name} ${isUpdate ? 'updated' : 'created'} successfully!`, { modal: false } ); await this.updateIndexFile(dirPath, module.name, template.extension); if (template.tests) { const testExtension = template.extension === ".tsx" ? ".test.tsx" : ".test.ts"; const testFilePath = `${fullPath}${testExtension}`; if (isUpdate && fs.existsSync(testFilePath)) { const { protectFileModification } = await import( "../../shared/indexSyncUtils" ); protectFileModification(testFilePath); const existingTests = await fs.promises.readFile( testFilePath, "utf8" ); const enhancedTests = await this.enhanceExistingTests( existingTests, template.tests, module ); await fs.promises.writeFile(testFilePath, enhancedTests); console.log(`πŸ§ͺ Enhanced tests for ${module.name}`); // πŸ”” Test enhancement notification vscode.window.showInformationMessage( `πŸ§ͺ Enhanced tests for ${module.name}`, { modal: false } ); } else { await fs.promises.writeFile(testFilePath, template.tests); console.log(`πŸ§ͺ Created tests for ${module.name}`); // πŸ”” Test creation notification vscode.window.showInformationMessage( `πŸ§ͺ Created tests for ${module.name}`, { modal: false } ); } } if (isBrainConnected()) { (this.brainConnector as any).learnFromAction( isUpdate ? "module_updated" : "module_built", "success", { moduleName: module.name, complexity: module.complexity, path: module.path, extension: template.extension, finalPath: finalFilePath, templateSource: module.templateSource, isUpdate, fileExisted: fileExists, hasSVG: module.hasSVG, // 🎨 Track SVG usage moduleType: module.moduleType, } ); } } catch (error) { this.outputChannel.appendLine( `❌ Error building ${module.name}: ${error}` ); console.error(`❌ Error building ${module.name}:`, error); // πŸ”” Module error notification vscode.window.showErrorMessage( `❌ Failed to build ${module.name}: ${error instanceof Error ? error.message : String(error)}`, "View Logs" ).then(selection => { if (selection === "View Logs") { this.outputChannel.show(); } }); if (isBrainConnected()) { (this.brainConnector as any).learnFromAction( "module_build_error", "failure", { moduleName: module.name, error: error instanceof Error ? error.message : String(error), } ); } throw error; } } private async generateModuleTemplate( module: MaestroModule ): Promise { let content = ""; let imports: string[] = []; let exports: string[] = []; let tests = ""; const moduleSpec: ModuleSpec = { name: module.name, type: module.moduleType, hasJSX: false, isReactComponent: false, path: module.path, }; const analysis = this.analyzeModuleContent(module); moduleSpec.hasJSX = analysis.hasJSX; moduleSpec.isReactComponent = analysis.isReactComponent; const extension = this.getFileExtension(moduleSpec); this.outputChannel.appendLine( `πŸ” ${module.name}: Type=${module.moduleType}, JSX=${moduleSpec.hasJSX}, Extension=${extension}, Source=${module.templateSource}, SVG=${analysis.hasSVG}` ); // πŸ†• Handle new audio architecture types if (module.moduleType === "engine") { content = this.generateAudioEngineTemplate( module.name, module.description ); imports = ["web-audio-api"]; exports = [module.name]; tests = ""; } else if (module.moduleType === "worklet") { content = this.generateAudioWorkletTemplate( module.name, module.description ); imports = ["web-audio-api"]; exports = [module.name]; tests = ""; } else if (module.templateSource === "rich") { content = await this.generateFromRichTemplate(module); imports = this.extractImportsFromContent(content); exports = this.extractExportsFromContent(content); tests = this.generateTestsFromTemplate(content); } else if (module.templateSource === "starter") { content = await this.generateFromStarterCode(module); imports = module.dependencies; exports = [module.name]; tests = this.generateBasicTests(module); } else { content = await this.generateDefaultTemplate(module); imports = module.dependencies; exports = [module.name]; tests = this.generateBasicTests(module); } return { name: module.name, content, imports, exports, tests, extension, source: module.templateSource || "generated", }; } private async generateFromRichTemplate( module: MaestroModule ): Promise { return `'use client'; import React, { useState, useRef, useEffect } from 'react'; // 🎸 ${module.name} - Rich Template Component // Generated from rich template source interface ${module.name}Props { className?: string; onAction?: (action: string) => void; } /** * 🎸 ${module.description} */ export const ${module.name}: React.FC<${module.name}Props> = ({ className = "", onAction }) => { const [isActive, setIsActive] = useState(false); const [status, setStatus] = useState<'idle' | 'active' | 'complete'>('idle'); const componentRef = useRef(null); useEffect(() => { console.log('${module.name} initialized'); }, []); const handleAction = (action: string) => { setIsActive(!isActive); setStatus(status === 'idle' ? 'active' : 'idle'); onAction?.(action); }; return (

🎸 ${module.name}

Status: {status}
{isActive ? (

🎡 ${module.name} is now active!

) : (

Click Start to begin using ${module.name}

)}
); }; export default ${module.name};`; } private async generateFromStarterCode( module: MaestroModule ): Promise { if (isBrainConnected()) { console.log(`🧠 Using Dual Brain to enhance ${module.name}`); } // 🎨 Check if this should be an SVG component const shouldUseSVG = module.hasSVG || module.name.toLowerCase().includes("tab") || module.name.toLowerCase().includes("fret"); if (shouldUseSVG) { return this.generateSVGTabPlayerTemplate(); } return `'use client'; import React, { useState, useRef, useEffect } from 'react'; // 🧠 ${module.name} - Enhanced by Dual Brain // Generated from starter specification interface ${module.name}Props { className?: string; onAction?: (action: string) => void; } /** * 🎸 ${module.description || `${module.name} component for guitar practice`} */ export const ${module.name}: React.FC<${module.name}Props> = ({ className = "", onAction }) => { const [isActive, setIsActive] = useState(false); const [status, setStatus] = useState<'idle' | 'ready' | 'practicing'>('idle'); const componentRef = useRef(null); useEffect(() => { console.log('${module.name} initialized'); setStatus('ready'); }, []); const handleStart = () => { setIsActive(true); setStatus('practicing'); onAction?.('start'); }; const handleStop = () => { setIsActive(false); setStatus('ready'); onAction?.('stop'); }; return (

🎸 ${module.name}

Status: {status}
{!isActive ? ( ) : ( )}
{isActive ? (

🎡 ${module.name} is now active!

Practice session in progress...

) : (

Ready to start ${module.name}

Click the start button to begin your practice session.

)}
); }; export default ${module.name};`; } private async generateDefaultTemplate( module: MaestroModule ): Promise { return generateMusicHandlerTemplate(module.name); } private extractImportsFromContent(content: string): string[] { const importPattern = /import.*from\s+['"]([^'"]+)['"]/g; const imports: string[] = []; let match; while ((match = importPattern.exec(content)) !== null) { imports.push(match[1]); } return imports; } private extractExportsFromContent(content: string): string[] { const exportPattern = /export\s+(?:default\s+)?(?:function\s+|const\s+|class\s+)?(\w+)/g; const exports: string[] = []; let match; while ((match = exportPattern.exec(content)) !== null) { exports.push(match[1]); } return exports; } private generateTestsFromTemplate(content: string): string { const componentMatch = content.match(/export\s+(?:const|function)\s+(\w+)/); const componentName = componentMatch ? componentMatch[1] : "Component"; return `import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import { ${componentName} } from './${componentName}'; // 🎸 Tests for ${componentName} describe('${componentName}', () => { test('renders without crashing', () => { render(<${componentName} />); expect(screen.getByText(/${componentName}/i)).toBeInTheDocument(); }); test('handles user interaction', () => { const mockAction = jest.fn(); render(<${componentName} onAction={mockAction} />); const button = screen.getByRole('button'); fireEvent.click(button); expect(mockAction).toHaveBeenCalled(); }); test('applies custom className', () => { const customClass = 'custom-test-class'; render(<${componentName} className={customClass} />); const element = screen.getByText(/${componentName}/i).closest('div'); expect(element).toHaveClass(customClass); }); });`; } private generateBasicTests(module: MaestroModule): string { return `import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import { ${module.name} } from './${module.name}'; // 🎸 Tests for ${module.name} // Module type: ${module.moduleType} describe('${module.name}', () => { test('renders without crashing', () => { render(<${module.name} />); expect(screen.getByTestId('${module.name.toLowerCase()}')).toBeInTheDocument(); }); test('displays component name', () => { render(<${module.name} />); expect(screen.getByText('🎸 ${module.name}')).toBeInTheDocument(); }); test('handles start/stop actions', () => { const mockAction = jest.fn(); render(<${module.name} onAction={mockAction} />); const startButton = screen.getByText(/start ${module.name}/i); fireEvent.click(startButton); expect(mockAction).toHaveBeenCalledWith('start'); expect(screen.getByText(/stop ${module.name}/i)).toBeInTheDocument(); }); test('applies custom className', () => { const customClass = 'custom-test-class'; render(<${module.name} className={customClass} />); const element = screen.getByTestId('${module.name.toLowerCase()}'); expect(element).toHaveClass(customClass); }); });`; } // Working Test #2 merge functionality private async mergeUpdateWithExisting( existingContent: string, updateTemplate: string, module: MaestroModule ): Promise { console.log(`πŸ”„ Merging updates for ${module.name}`); const updateDescription = module.description; const newFeatures = this.extractFeaturesFromDescription(updateDescription); if (newFeatures.length === 0) { console.warn(`⚠️ No features found to merge for ${module.name}`); let mergedContent = existingContent; if (!mergedContent.includes("with NEW FEATURES")) { mergedContent = mergedContent.replace( /\/\/ 🧠 (.+?) - Enhanced by Dual Brain/, `// 🧠 ${module.name} - Enhanced by Dual Brain with NEW FEATURES` ); } return mergedContent; } let mergedContent = existingContent; if (!mergedContent.includes("with NEW FEATURES")) { mergedContent = mergedContent.replace( /\/\/ 🧠 (.+?) - Enhanced by Dual Brain/, `// 🧠 ${module.name} - Enhanced by Dual Brain with NEW FEATURES` ); } mergedContent = mergedContent.replace( /\/\*\*[\s\S]*?\*\//, `/** * 🎸 ${module.name} - ENHANCED with new features * Original: Generated from starter template * Updates: ${newFeatures.join(", ")} */` ); if ( newFeatures.some( (f) => f.toLowerCase().includes("progression") || f.toLowerCase().includes("metronome") || f.toLowerCase().includes("progress") ) ) { mergedContent = this.addNewStateVariables(mergedContent, module.name); } if ( newFeatures.some( (f) => f.toLowerCase().includes("loop") || f.toLowerCase().includes("effects") || f.toLowerCase().includes("recording") ) ) { mergedContent = this.addAudioFeatureStates(mergedContent, module.name); } mergedContent = this.addNewMethods(mergedContent, newFeatures, module.name); mergedContent = this.enhanceComponentJSX( mergedContent, newFeatures, module.name ); console.log( `βœ… Merged ${newFeatures.length} new features into ${module.name}` ); return mergedContent; } private extractFeaturesFromDescription(description: string): string[] { const features: string[] = []; const lines = description.split("\n"); console.log(`πŸ” Parsing description for features:`, description); for (const line of lines) { const trimmedLine = line.trim(); if (trimmedLine.startsWith("-") || trimmedLine.startsWith("*")) { const feature = trimmedLine.replace(/^[-*]\s*/, "").trim(); if (feature.length > 0) { features.push(feature); console.log(`πŸ“ Found feature: "${feature}"`); } } } console.log(`βœ… Extracted ${features.length} features:`, features); return features; } private addNewStateVariables(content: string, componentName: string): string { const useStateRegex = /const \[([^\]]+)\] = useState\([^)]*\);/g; const matches = Array.from(content.matchAll(useStateRegex)); if (matches.length > 0) { const lastMatch = matches[matches.length - 1]; const insertIndex = lastMatch.index! + lastMatch[0].length; const newStates = ` const [chordProgression, setChordProgression] = useState(['C', 'G', 'Am', 'F']); const [metronomeActive, setMetronomeActive] = useState(false); const [practiceProgress, setPracticeProgress] = useState(0); const [currentChord, setCurrentChord] = useState(0);`; return ( content.slice(0, insertIndex) + newStates + content.slice(insertIndex) ); } console.warn(`⚠️ Could not find useState pattern in ${componentName}`); return content; } private addAudioFeatureStates( content: string, componentName: string ): string { const useStateRegex = /const \[([^\]]+)\] = useState\([^)]*\);/g; const matches = Array.from(content.matchAll(useStateRegex)); if (matches.length > 0) { const lastMatch = matches[matches.length - 1]; const insertIndex = lastMatch.index! + lastMatch[0].length; const newStates = ` const [loopActive, setLoopActive] = useState(false); const [loopStart, setLoopStart] = useState(0); const [loopEnd, setLoopEnd] = useState(30); const [reverbLevel, setReverbLevel] = useState(0); const [delayLevel, setDelayLevel] = useState(0); const [isRecording, setIsRecording] = useState(false);`; return ( content.slice(0, insertIndex) + newStates + content.slice(insertIndex) ); } console.warn(`⚠️ Could not find useState pattern in ${componentName}`); return content; } private addNewMethods( content: string, features: string[], componentName: string ): string { const returnIndex = content.indexOf("return ("); if (returnIndex === -1) { console.warn(`⚠️ Could not find return statement in ${componentName}`); return content; } let newMethods = ""; if (features.some((f) => f.toLowerCase().includes("chord"))) { newMethods += ` const handleChordProgression = () => { const nextChord = (currentChord + 1) % chordProgression.length; setCurrentChord(nextChord); console.log(\`Playing chord: \${chordProgression[nextChord]}\`); onAction?.(\`chord-\${chordProgression[nextChord]}\`); }; const generateNewProgression = () => { const chords = ['C', 'G', 'Am', 'F', 'Dm', 'Em', 'A', 'D']; const newProgression = Array.from({length: 4}, () => chords[Math.floor(Math.random() * chords.length)] ); setChordProgression(newProgression); setCurrentChord(0); };`; } if (features.some((f) => f.toLowerCase().includes("metronome"))) { newMethods += ` const toggleMetronome = () => { setMetronomeActive(!metronomeActive); console.log(\`Metronome: \${!metronomeActive ? 'ON' : 'OFF'}\`); onAction?.(\`metronome-\${!metronomeActive ? 'on' : 'off'}\`); };`; } if (features.some((f) => f.toLowerCase().includes("progress"))) { newMethods += ` const updateProgress = () => { const newProgress = Math.min(practiceProgress + 10, 100); setPracticeProgress(newProgress); console.log(\`Progress: \${newProgress}%\`); };`; } if (features.some((f) => f.toLowerCase().includes("loop"))) { newMethods += ` const toggleLoop = () => { setLoopActive(!loopActive); console.log(\`Loop: \${!loopActive ? 'ON' : 'OFF'} (\${loopStart}s - \${loopEnd}s)\`); onAction?.(\`loop-\${!loopActive ? 'on' : 'off'}\`); };`; } if (features.some((f) => f.toLowerCase().includes("effects"))) { newMethods += ` const adjustReverb = (level: number) => { setReverbLevel(level); console.log(\`Reverb: \${level}%\`); onAction?.(\`reverb-\${level}\`); }; const adjustDelay = (level: number) => { setDelayLevel(level); console.log(\`Delay: \${level}%\`); onAction?.(\`delay-\${level}\`); };`; } if (features.some((f) => f.toLowerCase().includes("recording"))) { newMethods += ` const toggleRecording = () => { setIsRecording(!isRecording); console.log(\`Recording: \${!isRecording ? 'STARTED' : 'STOPPED'}\`); onAction?.(\`record-\${!isRecording ? 'start' : 'stop'}\`); };`; } if (newMethods) { return ( content.slice(0, returnIndex) + newMethods + "\n\n " + content.slice(returnIndex) ); } return content; } private enhanceComponentJSX( content: string, features: string[], componentName: string ): string { const componentContentIndex = content.indexOf( '
' ); const endOfContentIndex = content.indexOf( "
", componentContentIndex + 1 ); if (componentContentIndex === -1 || endOfContentIndex === -1) { console.warn( `⚠️ Could not find component-content div in ${componentName}` ); return content; } let newControls = ""; if (features.some((f) => f.toLowerCase().includes("chord"))) { newControls += `

🎸 Chord Progression

{chordProgression.map((chord, index) => ( {chord} ))}
`; } if (features.some((f) => f.toLowerCase().includes("metronome"))) { newControls += `

πŸ₯ Metronome

`; } if (features.some((f) => f.toLowerCase().includes("progress"))) { newControls += `

πŸ“Š Progress

{practiceProgress}% Complete

`; } if (features.some((f) => f.toLowerCase().includes("loop"))) { newControls += `

πŸ” Loop Control

`; } if (features.some((f) => f.toLowerCase().includes("effects"))) { newControls += `

πŸŽ›οΈ Audio Effects

adjustReverb(parseInt(e.target.value))} />
adjustDelay(parseInt(e.target.value))} />
`; } if (features.some((f) => f.toLowerCase().includes("recording"))) { newControls += `

πŸŽ™οΈ Recording

{isRecording &&

πŸ”΄ Recording in progress...

}
`; } if (newControls) { return ( content.slice(0, endOfContentIndex) + newControls + "\n " + content.slice(endOfContentIndex) ); } return content; } private async enhanceExistingTests( existingTests: string, newTestTemplate: string, module: MaestroModule ): Promise { console.log(`πŸ§ͺ Enhancing tests for ${module.name}`); const features = this.extractFeaturesFromDescription(module.description); let enhancedTests = existingTests; const insertPosition = enhancedTests.lastIndexOf("});"); if (insertPosition > -1) { let newTests = ""; if (features.some((f) => f.toLowerCase().includes("chord"))) { newTests += ` test('handles chord progression', () => { const mockAction = jest.fn(); render(<${module.name} onAction={mockAction} />); const chordButton = screen.getByText(/next chord/i); fireEvent.click(chordButton); expect(mockAction).toHaveBeenCalledWith(expect.stringMatching(/chord-/)); }); test('generates new chord progression', () => { render(<${module.name} />); const generateButton = screen.getByText(/new progression/i); fireEvent.click(generateButton); expect(screen.getByText(/chord progression/i)).toBeInTheDocument(); });`; } if (features.some((f) => f.toLowerCase().includes("metronome"))) { newTests += ` test('toggles metronome', () => { const mockAction = jest.fn(); render(<${module.name} onAction={mockAction} />); const metronomeButton = screen.getByText(/start metronome/i); fireEvent.click(metronomeButton); expect(mockAction).toHaveBeenCalledWith('metronome-on'); expect(screen.getByText(/stop metronome/i)).toBeInTheDocument(); });`; } if (features.some((f) => f.toLowerCase().includes("loop"))) { newTests += ` test('controls audio loop', () => { const mockAction = jest.fn(); render(<${module.name} onAction={mockAction} />); const loopButton = screen.getByText(/start loop/i); fireEvent.click(loopButton); expect(mockAction).toHaveBeenCalledWith('loop-on'); expect(screen.getByText(/stop loop/i)).toBeInTheDocument(); });`; } if (features.some((f) => f.toLowerCase().includes("effects"))) { newTests += ` test('adjusts audio effects', () => { const mockAction = jest.fn(); render(<${module.name} onAction={mockAction} />); const reverbSlider = screen.getByLabelText(/reverb/i); fireEvent.change(reverbSlider, { target: { value: '50' } }); expect(mockAction).toHaveBeenCalledWith('reverb-50'); });`; } if (features.some((f) => f.toLowerCase().includes("recording"))) { newTests += ` test('handles recording toggle', () => { const mockAction = jest.fn(); render(<${module.name} onAction={mockAction} />); const recordButton = screen.getByText(/start recording/i); fireEvent.click(recordButton); expect(mockAction).toHaveBeenCalledWith('record-start'); expect(screen.getByText(/recording in progress/i)).toBeInTheDocument(); });`; } enhancedTests = enhancedTests.slice(0, insertPosition) + newTests + "\n" + enhancedTests.slice(insertPosition); } return enhancedTests; } // πŸ†• ENHANCED: Utility methods for new architecture private sanitizeModuleName(name: string): string { return name.replace(/[^a-zA-Z0-9]/g, "").replace(/^[0-9]/, ""); } // πŸ†• ENHANCED: generateModulePath with new folder structures private generateModulePath(name: string, type: string): string { const sanitized = this.sanitizeModuleName(name); if ( name.toLowerCase().includes("test") || sanitized.toLowerCase().startsWith("test") ) { return `src/modules/test-components/${sanitized}`; } // πŸ†• Audio engine routing if (type === "engine") { return `src/audio/engines/${sanitized}`; } // πŸ†• Audio worklet routing if (type === "worklet") { return `src/audio/worklets/${sanitized}`; } switch (type) { case "component": // 🎸 Enhanced guitar component routing if (name.toLowerCase().includes("guitar")) { if ( name.toLowerCase().includes("tab") || name.toLowerCase().includes("display") ) { return `src/components/guitar/display/${sanitized}`; } if ( name.toLowerCase().includes("fret") || name.toLowerCase().includes("chord") ) { return `src/components/guitar/fretboard/${sanitized}`; } return `src/components/guitar/${sanitized}`; } // 🎡 Enhanced audio component routing if (name.toLowerCase().includes("audio")) { if ( name.toLowerCase().includes("control") || name.toLowerCase().includes("button") || name.toLowerCase().includes("slider") ) { return `src/components/audio/controls/${sanitized}`; } if ( name.toLowerCase().includes("track") || name.toLowerCase().includes("mixer") || name.toLowerCase().includes("instrument") ) { return `src/components/audio/tracks/${sanitized}`; } if ( name.toLowerCase().includes("visual") || name.toLowerCase().includes("display") || name.toLowerCase().includes("spectrum") ) { return `src/components/audio/display/${sanitized}`; } if ( name.toLowerCase().includes("effect") || name.toLowerCase().includes("reverb") || name.toLowerCase().includes("eq") ) { return `src/components/audio/effects/${sanitized}`; } return `src/components/audio/${sanitized}`; } // 🎀 Vocal component routing if ( name.toLowerCase().includes("vocal") || name.toLowerCase().includes("voice") ) { return `src/components/vocal/${sanitized}`; } return `src/components/${sanitized}`; case "hook": // 🎣 Enhanced hook routing if ( name.toLowerCase().includes("audio") || name.toLowerCase().includes("tone") || name.toLowerCase().includes("playback") ) { return `src/hooks/audio/${sanitized}`; } if ( name.toLowerCase().includes("guitar") || name.toLowerCase().includes("fret") || name.toLowerCase().includes("chord") ) { return `src/hooks/guitar/${sanitized}`; } return `src/hooks/${sanitized}/${sanitized}`; case "util": // πŸ”§ Enhanced utility routing if (name.toLowerCase().includes("audio")) { return `src/audio/utils/${sanitized}`; } return `src/utils/${sanitized}`; default: return `src/components/${sanitized}`; } } // πŸ†• ENHANCED: Module type detection with new types private detectModuleTypeFromTemplate( template: string ): "component" | "hook" | "util" | "test" | "engine" | "worklet" { if ( template.includes("AudioWorkletProcessor") || template.includes("registerProcessor") ) return "worklet"; if ( template.includes("AudioContext") && template.includes("class") && template.includes("Engine") ) return "engine"; if (template.includes("React.FC") || template.includes("useState")) return "component"; if (template.includes("use") && template.includes("Hook")) return "hook"; if (template.includes("export function") && !template.includes("React")) return "util"; return "component"; } private extractDependenciesFromTemplate(template: string): string[] { const deps: string[] = []; if (template.includes("React")) deps.push("react"); if (template.includes("useState") || template.includes("useEffect")) deps.push("react"); if (template.includes("Canvas") || template.includes("canvas")) deps.push("canvas"); if (template.includes("Web Audio") || template.includes("AudioContext")) deps.push("web-audio-api"); if (template.includes("SVG") || template.includes("svg")) deps.push("svg"); // 🎨 SVG dependency if (template.includes("Tone") || template.includes("tone")) deps.push("tone"); // 🎹 Tone.js dependency return [...new Set(deps)]; } private extractDependenciesFromDescription(description: string): string[] { const deps: string[] = ["react"]; const lower = description.toLowerCase(); if (lower.includes("audio") || lower.includes("sound")) deps.push("web-audio-api"); if ( lower.includes("display") || lower.includes("visual") || lower.includes("canvas") ) deps.push("canvas"); if ( lower.includes("svg") || lower.includes("interactive") || lower.includes("tab") ) deps.push("svg"); // 🎨 SVG dependency if (lower.includes("chord") || lower.includes("guitar")) deps.push("guitar-js"); if (lower.includes("timer") || lower.includes("metronome")) deps.push("timing"); if (lower.includes("tone") || lower.includes("synthesizer")) deps.push("tone"); // 🎹 Tone.js dependency return [...new Set(deps)]; } // πŸ†• ENHANCED: Default modules with SVG and audio architecture private getDefaultModules(): MaestroModule[] { return [ { name: "SVGTabDisplay", // 🎨 Changed from canvas to SVG path: "src/components/guitar/display/SVGTabDisplay", dependencies: ["react", "svg"], complexity: "high", priority: 1, hasWebAudio: false, hasCanvas: false, hasSVG: true, // 🎨 SVG-based description: "Interactive SVG guitar tablature display with clickable fret positions (Songsterr-inspired)", moduleType: "component", templateSource: "generated", isUpdate: false, }, { name: "AudioSyncEngine", // πŸ†• Audio engine path: "src/audio/engines/AudioSyncEngine", dependencies: ["web-audio-api"], complexity: "high", priority: 2, hasWebAudio: true, hasCanvas: false, hasSVG: false, description: "Audio-visual synchronization engine for real-time playback cursor tracking", moduleType: "engine", templateSource: "generated", isUpdate: false, }, { name: "MaestroAudioWorklet", // πŸ†• Audio worklet path: "src/audio/worklets/MaestroAudioWorklet", dependencies: ["web-audio-api"], complexity: "high", priority: 3, hasWebAudio: true, hasCanvas: false, hasSVG: false, description: "Low-latency audio processing worklet for real-time audio effects", moduleType: "worklet", templateSource: "generated", isUpdate: false, }, { name: "useAudioSync", // πŸ†• Tone.js hook path: "src/hooks/audio/useAudioSync", dependencies: ["react", "tone"], complexity: "medium", priority: 4, hasWebAudio: true, hasCanvas: false, hasSVG: false, description: "Tone.js hook for audio-visual synchronization and cursor tracking", moduleType: "hook", templateSource: "generated", isUpdate: false, }, ]; } // πŸ”§ IMPROVED: Use indexSyncUtils.ts comprehensive logic private async updateIndexFile( dirPath: string, moduleName: string, extension: string ): Promise { try { // Get all TypeScript files in the directory (excluding index.ts and test files) const tsFiles = fs .readdirSync(dirPath) .filter( (file) => (file.endsWith(".ts") || file.endsWith(".tsx")) && file !== "index.ts" ) .filter( (file) => !file.endsWith(".test.ts") && !file.endsWith(".test.tsx") ); // πŸ”§ USE comprehensive logic from indexSyncUtils.ts const shouldHaveIndex = shouldFolderHaveIndex(dirPath, tsFiles.length); if (!shouldHaveIndex) { const folderName = path.basename(dirPath); console.log(`⏭️ Skipped ${folderName}/ (utility folder)`); return; } // πŸ”§ USE shared createIndexFile function with comprehensive template const success = createIndexFile(dirPath, tsFiles); if (success) { console.log( `πŸ“„ Updated index.ts in ${path.basename(dirPath)}/` ); } else { console.warn( `⚠️ Failed to create index.ts in ${path.basename(dirPath)}/` ); } } catch (error) { console.warn(`⚠️ Error updating index file in ${dirPath}:`, error); } } // πŸ”§ ENHANCED: Missing utility methods private detectCodeLanguage(code: string): string { if (code.includes("React") || code.includes("useState")) return "tsx"; if (code.includes("export") && code.includes("function")) return "ts"; if (code.includes("import") && code.includes("from")) return "ts"; if (code.includes("interface") || code.includes("type")) return "ts"; return "tsx"; } private extractComponentName(code: string): string | null { const componentMatch = code.match(/(?:export\s+(?:const|function)\s+|class\s+)(\w+)/); return componentMatch ? componentMatch[1] : null; } private detectComponentTypeFromDescription(description: string): string { const lower = description.toLowerCase(); if (lower.includes("test") || lower.includes("spec")) return "test"; if (lower.includes("hook") || lower.includes("use")) return "hook"; if (lower.includes("util") || lower.includes("helper")) return "util"; if (lower.includes("engine") || lower.includes("audio context")) return "engine"; if (lower.includes("worklet") || lower.includes("processor")) return "worklet"; return "component"; } private async displayBuildResults(buildPlan: BuildPlan, createdFiles?: Array<{ path: string; type: string; description?: string }>): Promise { // Also log to output channel this.outputChannel.appendLine("\n🎯 === BUILD RESULTS ==="); this.outputChannel.appendLine(`βœ… Successfully built ${buildPlan.modules.length} modules`); // Create VS Code webview panel for beautiful results display const panel = vscode.window.createWebviewPanel( 'maestroResults', '🎸 Maestro Build Results', vscode.ViewColumn.One, { enableScripts: true, retainContextWhenHidden: true } ); // Calculate dynamic stats const completedModules = buildPlan.modules.length; const svgModuleCount = buildPlan.modules.filter(m => m.hasSVG).length; const audioEngineCount = buildPlan.modules.filter(m => m.moduleType === 'engine').length; const workletCount = buildPlan.modules.filter(m => m.moduleType === 'worklet').length; const starterTemplateCount = buildPlan.modules.filter(m => m.templateSource === 'starter').length; const totalCreatedFiles = (createdFiles?.length || 0) + completedModules; // Generate created files section HTML const createdFilesSection = createdFiles && createdFiles.length > 0 ? `

πŸ“ Created Files

    ${createdFiles.map(file => `
  • ${path.basename(file.path)} (${file.type})
    ${file.description || 'Generated file'}
    Path: ${file.path}
  • `).join("")}
` : ''; // Generate dynamic next steps based on what was actually built const nextSteps = this.generateDynamicNextSteps(buildPlan, createdFiles); panel.webview.html = `

🎸 Maestro.ai Guitar Practice Modules Built Successfully - SVG + Audio Architecture!

🎨 SVG-Based Notation Architecture

SVG components support individual interactive elements, ideal for real-time tab rendering and playback.

Each note, fret, and cursor is treated as a manipulable DOM element for full control.

🎯 Enhanced Build System Active!

βœ… SVG TabPlayer with interactive fret positions

βœ… Audio Engine architecture and Tone.js hooks

βœ… Folder structure: audio/, guitar/, controls/, etc.

βœ… File backup & protection logic

${completedModules}

Total Modules

${svgModuleCount}

SVG Components

${audioEngineCount}

Audio Engines

${workletCount}

Audio Worklets

${starterTemplateCount}

Brain Enhanced

${totalCreatedFiles}

Total Files

${createdFilesSection}

βœ… Created Practice Modules

    ${buildPlan.modules.map(module => `
  • ${module.name} (.ts${module.moduleType === 'component' || module.moduleType === 'hook' ? 'x' : ''}) ${module.hasSVG ? '[SVG]' : ''} ${module.moduleType === 'engine' ? '[ENGINE]' : ''} ${module.moduleType === 'worklet' ? '[WORKLET]' : ''} ${module.isUpdate ? '[UPDATED]' : ''}
    ${module.description}
    Path: ${module.path}
    Source: ${module.templateSource || "generated"}
  • `).join("")}

πŸš€ Cipher's Smart Next Steps

${nextSteps.map(step => `

${step}

`).join("")}
`; // Display brain suggestions if connected if (isBrainConnected()) { displayBrainSuggestions([ "Consider adding audio synchronization features", "SVG-based tab display is optimal for performance", "Worklet architecture enables low-latency audio processing" ]); } console.log("🎯 Build results displayed in webview panel"); } private generateDynamicNextSteps(buildPlan: BuildPlan, createdFiles?: Array<{ path: string; type: string; description?: string }>): string[] { const steps: string[] = []; // Analysis-based suggestions const hasEngines = buildPlan.modules.some(m => m.moduleType === 'engine'); const hasWorklets = buildPlan.modules.some(m => m.moduleType === 'worklet'); const hasSVG = buildPlan.modules.some(m => m.hasSVG); const hasCreatedFiles = createdFiles && createdFiles.length > 0; const hasScrollingTab = buildPlan.modules.some(m => m.name.includes('Scrolling')); const hasUpdates = buildPlan.modules.some(m => m.isUpdate); if (hasCreatedFiles) { steps.push("1. πŸ”— Wire new files together with components and modules"); steps.push("2. πŸ“ Update app/svg-tabs/page.tsx to test new functionality"); } if (hasEngines && hasWorklets) { steps.push("3. 🎡 Connect audio engines with worklets for low-latency processing"); } else if (hasEngines) { steps.push("3. ⚑ Initialize audio engines and test audio context"); } if (hasSVG) { steps.push("4. 🎨 Test SVG tab display with interactive fret positions"); steps.push("5. πŸ”„ Integrate SVG components with audio synchronization"); } if (hasScrollingTab) { steps.push("6. πŸ“œ Implement ScrollingTabDisplay with smooth 60fps animation"); steps.push("7. 🎯 Add viewport buffering and playback cursor tracking"); } if (buildPlan.dependencies.length > 0) { steps.push(`8. πŸ“¦ Install dependencies: ${buildPlan.dependencies.join(", ")}`); } if (hasUpdates) { steps.push("9. πŸ§ͺ Test updated components with new enhanced features"); } // Add architectural improvements steps.push("10. πŸ—οΈ Review file structure and optimize imports"); steps.push("11. βœ… Run tests to validate component functionality"); return steps; } } // Export the handler function for backwards compatibility export const maestroGuitarModuleBuilderHandler = async (...args: unknown[]): Promise => { const specPath = args[0] as string | undefined; const builder = new MaestroGuitarModuleBuilder(); return await builder.buildMaestroGuitarModules(specPath); }; // Export default for convenience export default MaestroGuitarModuleBuilder;