class CodeMasterIDE { constructor() { this.files = new Map(); this.openTabs = []; this.activeTab = null; this.editor = null; this.fileCounter = 1; this.aiLearning = new AILearning(); this.primaryFile = null; this.sidebarWidth = 256; this.aiPanelWidth = 0; this.isDirty = new Set(); this.currentModalCallback = null; this.contextMenuTarget = null; // Preserve user's original content as initial files this.initialFiles = { 'index.html': ` My static Space

Welcome to your static Space!

You can modify this app directly by editing index.html in the Files and versions tab.

Also don't forget to check the Spaces documentation.

`, 'style.css': `body { padding: 2rem; font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif; } h1 { font-size: 16px; margin-top: 0; } p { color: rgb(107, 114, 128); font-size: 15px; margin-bottom: 10px; margin-top: 5px; } .card { max-width: 620px; margin: 0 auto; padding: 16px; border: 1px solid lightgray; border-radius: 16px; } .card p:last-child { margin-bottom: 0; }` }; this.init(); } init() { this.loadFiles(); this.initEditor(); this.setupEventListeners(); this.setupAI(); this.setupConsoleCapture(); this.broadcastChannel = this.setupBroadcastChannel(); // Open initial files if (this.files.size === 0) { Object.entries(this.initialFiles).forEach(([name, content]) => { this.files.set(name, { name, content, type: this.getFileType(name), path: name }); }); this.saveFiles(); } this.renderFileTree(); // Open first HTML file or first file const firstHtml = Array.from(this.files.keys()).find(f => f.endsWith('.html')); const firstFile = firstHtml || this.files.keys().next().value; if (firstFile) { this.openFile(firstFile); if (firstHtml) this.setPrimaryFile(firstHtml); } this.updatePrimaryFileSelect(); lucide.createIcons(); } setupBroadcastChannel() { if ('BroadcastChannel' in window) { try { const bc = new BroadcastChannel('codemaster_sync'); bc.onmessage = (event) => { if (event.data.type === 'pong') { console.log('Viewer connected'); } }; return bc; } catch (e) { return null; } } return null; } loadFiles() { try { const saved = localStorage.getItem('codemaster_files'); if (saved) { const parsed = JSON.parse(saved); this.files = new Map(Object.entries(parsed)); } } catch (e) { console.error('Failed to load files:', e); } } saveFiles() { try { const obj = Object.fromEntries(this.files); localStorage.setItem('codemaster_files', JSON.stringify(obj)); } catch (e) { console.error('Failed to save files:', e); } } initEditor() { require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.44.0/min/vs' }}); require(['vs/editor/editor.main'], () => { monaco.editor.defineTheme('codemaster-dark', { base: 'vs-dark', inherit: true, rules: [], colors: { 'editor.background': '#020617', 'editor.lineHighlightBackground': '#1e293b', 'editorLineNumber.foreground': '#64748b', 'editorLineNumber.activeForeground': '#94a3b8', } }); this.editor = monaco.editor.create(document.getElementById('editor-container'), { value: '', language: 'html', theme: 'codemaster-dark', automaticLayout: true, minimap: { enabled: true }, fontSize: 14, fontFamily: 'JetBrains Mono, Consolas, Monaco, monospace', wordWrap: 'on', lineNumbers: 'on', roundedSelection: false, scrollBeyondLastLine: false, renderLineHighlight: 'line', padding: { top: 16 }, bracketPairColorization: { enabled: true }, autoIndent: 'advanced', formatOnPaste: true, formatOnType: true, suggestOnTriggerCharacters: true, quickSuggestions: true, }); // AI-powered suggestions this.editor.onDidType((e) => { this.handleTyping(e); }); // Track changes this.editor.onDidChangeModelContent(() => { if (this.activeTab) { this.isDirty.add(this.activeTab); this.updateTabStatus(this.activeTab); this.aiLearning.recordEdit(this.activeTab, this.editor.getValue()); this.debouncedPreviewUpdate(); } }); // Load initial content if exists if (this.activeTab && this.files.has(this.activeTab)) { const file = this.files.get(this.activeTab); this.editor.setValue(file.content); monaco.editor.setModelLanguage(this.editor.getModel(), file.type); } }); } handleTyping(text) { const position = this.editor.getPosition(); const model = this.editor.getModel(); const lineContent = model.getLineContent(position.lineNumber); const beforeCursor = lineContent.substring(0, position.column - 1); // Get AI suggestion const suggestion = this.aiLearning.getSuggestion(beforeCursor, text, this.activeTab); if (suggestion) { this.showAISuggestion(suggestion, position); } else { this.hideAISuggestion(); } } showAISuggestion(suggestion, position) { const coords = this.editor.getScrolledVisiblePosition(position); const editorDom = document.getElementById('editor-container'); const suggestionEl = document.getElementById('ai-suggestion'); suggestionEl.style.left = (editorDom.offsetLeft + coords.left) + 'px'; suggestionEl.style.top = (editorDom.offsetTop + coords.top + 20) + 'px'; suggestionEl.textContent = 'AI: ' + suggestion.text; suggestionEl.classList.remove('hidden'); // Auto-insert on Tab if high confidence if (suggestion.confidence > 0.8) { const disposable = this.editor.onKeyDown((e) => { if (e.keyCode === monaco.KeyCode.Tab) { e.preventDefault(); this.insertSuggestion(suggestion); disposable.dispose(); } }); // Dispose after 5 seconds setTimeout(() => disposable.dispose(), 5000); } } hideAISuggestion() { document.getElementById('ai-suggestion').classList.add('hidden'); } insertSuggestion(suggestion) { const position = this.editor.getPosition(); this.editor.executeEdits('ai-suggestion', [{ range: new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column), text: suggestion.insert }]); this.hideAISuggestion(); this.aiLearning.recordAcceptance(suggestion); this.updateAIPanel(); } setupAI() { this.updateAIPanel(); setInterval(() => this.updateAIPanel(), 5000); } updateAIPanel() { const stats = this.aiLearning.getStats(); document.getElementById('patterns-count').textContent = stats.patterns; document.getElementById('confidence-bar').style.width = stats.confidence + '%'; document.getElementById('confidence-text').textContent = stats.confidence + '%'; const snippetsEl = document.getElementById('frequent-snippets'); snippetsEl.innerHTML = stats.topSnippets.map(s => `
${s.trigger}
${s.code}
Used ${s.count} times
`).join(''); const historyEl = document.getElementById('suggestions-history'); historyEl.innerHTML = stats.recentSuggestions.map(s => `
${s.time}: ${s.text}
`).join(''); } setupConsoleCapture() { const originalLog = console.log; const originalError = console.error; const originalWarn = console.warn; const self = this; console.log = function(...args) { self.appendToConsole('log', args); originalLog.apply(console, args); }; console.error = function(...args) { self.appendToConsole('error', args); originalError.apply(console, args); }; console.warn = function(...args) { self.appendToConsole('warn', args); originalWarn.apply(console, args); }; window.onerror = (msg, url, line) => { this.appendToConsole('error', [msg + ' (line ' + line + ')']); }; } appendToConsole(level, args) { const output = document.getElementById('console-output'); const line = document.createElement('div'); line.className = 'console-line ' + level; const timestamp = new Date().toLocaleTimeString(); const message = args.map(arg => { if (typeof arg === 'object') { try { return JSON.stringify(arg, null, 2); } catch(e) { return String(arg); } } return String(arg); }).join(' '); line.textContent = '[' + timestamp + '] ' + message; output.appendChild(line); output.scrollTop = output.scrollHeight; // Update problem count for errors if (level === 'error') { this.updateProblemCount(); } } updateProblemCount() { const errors = document.querySelectorAll('.console-line.error').length; document.getElementById('problem-count').textContent = errors; } getFileType(filename) { const ext = filename.split('.').pop().toLowerCase(); const types = { 'html': 'html', 'htm': 'html', 'css': 'css', 'js': 'javascript', 'json': 'json', 'ts': 'typescript', 'py': 'python', 'md': 'markdown', 'xml': 'xml', 'svg': 'xml' }; return types[ext] || 'plaintext'; } getFileIcon(filename) { const ext = filename.split('.').pop().toLowerCase(); const icons = { 'html': 'file-code', 'css': 'file-code', 'js': 'file-code', 'json': 'file-json', 'md': 'file-text', 'txt': 'file-text', 'jpg': 'image', 'png': 'image', 'gif': 'image', 'svg': 'image' }; return icons[ext] || 'file'; } renderFileTree() { const tree = document.getElementById('file-tree'); tree.innerHTML = ''; const sortedFiles = Array.from(this.files.keys()).sort(); sortedFiles.forEach(filename => { const item = document.createElement('div'); item.className = 'file-tree-item flex items-center gap-2 px-2 py-1.5 rounded text-sm' + (this.activeTab === filename ? ' active' : ''); item.innerHTML = ` ${filename} `; item.onclick = () => this.openFile(filename); item.oncontextmenu = (e) => this.showContextMenu(e, filename); tree.appendChild(item); }); lucide.createIcons(); } getFileIconColor(filename) { const ext = filename.split('.').pop().toLowerCase(); const colors = { 'html': 'text-orange-400', 'css': 'text-blue-400', 'js': 'text-yellow-400', 'json': 'text-green-400' }; return colors[ext] || 'text-slate-400'; } openFile(filename) { // Save current content if dirty if (this.activeTab && this.isDirty.has(this.activeTab)) { this.saveCurrentFile(); } // Update UI document.querySelectorAll('.file-tree-item').forEach(el => { el.classList.remove('active'); if (el.textContent.trim() === filename) { el.classList.add('active'); } }); // Add to tabs if not open if (!this.openTabs.includes(filename)) { this.openTabs.push(filename); this.renderTabs(); } this.activeTab = filename; this.updateTabStatus(filename); // Load content const file = this.files.get(filename); if (file && this.editor) { this.editor.setValue(file.content); monaco.editor.setModelLanguage(this.editor.getModel(), file.type); } this.renderTabs(); } renderTabs() { const tabsContainer = document.getElementById('tabs'); tabsContainer.innerHTML = ''; this.openTabs.forEach(filename => { const tab = document.createElement('div'); const isModified = this.isDirty.has(filename); tab.className = 'tab' + (this.activeTab === filename ? ' active' : '') + (isModified ? ' modified' : ''); tab.innerHTML = ` ${filename} `; tab.onclick = () => this.openFile(filename); tabsContainer.appendChild(tab); }); lucide.createIcons(); } updateTabStatus(filename) { this.renderTabs(); } closeTab(filename) { const index = this.openTabs.indexOf(filename); this.openTabs = this.openTabs.filter(f => f !== filename); if (this.isDirty.has(filename)) { this.saveFile(filename); } if (this.activeTab === filename) { this.activeTab = this.openTabs[Math.max(0, index - 1)] || null; if (this.activeTab) { this.openFile(this.activeTab); } else { this.editor.setValue(''); } } this.renderTabs(); } saveCurrentFile() { if (this.activeTab && this.editor) { const content = this.editor.getValue(); const file = this.files.get(this.activeTab); if (file) { file.content = content; this.files.set(this.activeTab, file); this.isDirty.delete(this.activeTab); this.saveFiles(); this.updateTabStatus(this.activeTab); this.syncToRemote(); } } } saveFile(filename) { if (this.editor && this.activeTab === filename) { this.saveCurrentFile(); } } saveAll() { this.openTabs.forEach(tab => { if (this.isDirty.has(tab)) { this.saveFile(tab); } }); this.showNotification('All files saved'); } setPrimaryFile(filename) { this.primaryFile = filename; document.getElementById('primary-file').value = filename; this.updatePreview(); this.showNotification('Primary file set to: ' + filename); } updatePrimaryFileSelect() { const select = document.getElementById('primary-file'); const currentValue = select.value; // Clear non-placeholder options while (select.options.length > 1) { select.remove(1); } // Add HTML files Array.from(this.files.keys()) .filter(f => f.endsWith('.html')) .forEach(f => { const option = document.createElement('option'); option.value = f; option.textContent = f; if (f === currentValue || f === this.primaryFile) { option.selected = true; } select.appendChild(option); }); } updatePreview() { if (!this.primaryFile || !this.files.has(this.primaryFile)) return; const file = this.files.get(this.primaryFile); let content = file.content; // Process linked files content = this.processIncludes(content); // Update local preview const frame = document.getElementById('preview-frame'); const blob = new Blob([content], { type: 'text/html' }); const url = URL.createObjectURL(blob); frame.src = url; // Sync to remote viewers this.syncToRemote(content); } processIncludes(html) { // Replace relative paths with data URIs for linked files let processed = html; // Process CSS links const cssLinks = html.match(/href=["']([^"']+\.css)["']/g) || []; cssLinks.forEach(link => { const match = link.match(/href=["']([^"']+)["']/); if (match) { const path = match[1]; const filename = path.replace(/^\.\//, '').replace(/^\//, ''); if (this.files.has(filename)) { const file = this.files.get(filename); const dataUri = 'data:text/css;base64,' + btoa(file.content); processed = processed.replace(path, dataUri); } } }); // Process JS scripts (excluding external URLs) const jsScripts = html.match(/src=["']([^"']+\.js)["']/g) || []; jsScripts.forEach(script => { const match = script.match(/src=["']([^"']+)["']/); if (match) { const path = match[1]; if (!path.startsWith('http') && !path.startsWith('//')) { const filename = path.replace(/^\.\//, '').replace(/^\//, ''); if (this.files.has(filename)) { const file = this.files.get(filename); const dataUri = 'data:text/javascript;base64,' + btoa(file.content); processed = processed.replace(path, dataUri); } } } }); return processed; } debouncedPreviewUpdate() { clearTimeout(this.previewTimeout); this.previewTimeout = setTimeout(() => this.updatePreview(), 1000); } syncToRemote(content) { const data = { content: content || (this.files.has(this.primaryFile) ? this.processIncludes(this.files.get(this.primaryFile).content) : ''), timestamp: Date.now(), primaryFile: this.primaryFile }; // BroadcastChannel for same-origin tabs if (this.broadcastChannel) { this.broadcastChannel.postMessage({ type: 'code_update', data: data }); } // localStorage for cross-tab/cross-device on same domain try { localStorage.setItem('codemaster_preview', JSON.stringify(data)); } catch (e) { console.error('Failed to sync:', e); } } newFile() { this.showModal('New File', (name) => { if (name && !this.files.has(name)) { const type = this.getFileType(name); this.files.set(name, { name, content: '', type, path: name }); this.saveFiles(); this.renderFileTree(); this.openFile(name); this.updatePrimaryFileSelect(); } }); } newFolder() { this.showNotification('Folders are simulated - use "folder/file.ext" naming'); } deleteFile(filename) { if (confirm('Delete "' + filename + '"?')) { this.files.delete(filename); this.saveFiles(); if (this.openTabs.includes(filename)) { this.closeTab(filename); } if (this.primaryFile === filename) { this.primaryFile = null; document.getElementById('primary-file').value = ''; } this.renderFileTree(); this.updatePrimaryFileSelect(); } } renameFile(oldName) { this.showModal('Rename File', (newName) => { if (newName && newName !== oldName && !this.files.has(newName)) { const file = this.files.get(oldName); file.name = newName; file.type = this.getFileType(newName); this.files.delete(oldName); this.files.set(newName, file); // Update tabs const tabIndex = this.openTabs.indexOf(oldName); if (tabIndex !== -1) { this.openTabs[tabIndex] = newName; } if (this.activeTab === oldName) { this.activeTab = newName; } if (this.primaryFile === oldName) { this.setPrimaryFile(newName); } this.saveFiles(); this.renderFileTree(); this.renderTabs(); this.updatePrimaryFileSelect(); } }, oldName); } showModal(title, callback, defaultValue = '') { document.getElementById('modal-title').textContent = title; const input = document.getElementById('modal-input'); input.value = defaultValue; input.placeholder = title === 'New File' ? 'example.html' : 'new-name.html'; document.getElementById('modal').classList.add('active'); input.focus(); input.select(); this.currentModalCallback = callback; // Enter key handler input.onkeydown = (e) => { if (e.key === 'Enter') { this.confirmModal(); } else if (e.key === 'Escape') { this.closeModal(); } }; } closeModal() { document.getElementById('modal').classList.remove('active'); this.currentModalCallback = null; } confirmModal() { const value = document.getElementById('modal-input').value.trim(); if (value && this.currentModalCallback) { this.currentModalCallback(value); } this.closeModal(); } showContextMenu(event, filename) { event.preventDefault(); this.contextMenuTarget = filename; const menu = document.getElementById('context-menu'); menu.innerHTML = `
Open
Rename
Delete
`; menu.style.left = event.pageX + 'px'; menu.style.top = event.pageY + 'px'; menu.classList.remove('hidden'); lucide.createIcons(); // Close on click outside setTimeout(() => { document.addEventListener('click', () => { menu.classList.add('hidden'); }, { once: true }); }, 0); } toggleAI() { const panel = document.getElementById('ai-panel'); const btn = document.getElementById('ai-btn'); if (panel.style.width === '300px') { panel.style.width = '0'; btn.classList.remove('bg-purple-700'); btn.classList.add('bg-purple-600'); } else { panel.style.width = '300px'; btn.classList.remove('bg-purple-600'); btn.classList.add('bg-purple-700'); this.updateAIPanel(); } } showRemotePreview() { const url = window.location.href.replace('index.html', 'viewer.html'); document.getElementById('preview-url').textContent = url; // Generate QR code const qrContainer = document.getElementById('qrcode'); qrContainer.innerHTML = ''; new QRCode(qrContainer, { text: url, width: 256, height: 256, colorDark: '#000000', colorLight: '#ffffff', correctLevel: QRCode.CorrectLevel.M }); document.getElementById('remote-modal').classList.add('active'); } closeRemoteModal() { document.getElementById('remote-modal').classList.remove('active'); } switchPanel(panel) { document.querySelectorAll('.panel-section').forEach(p => p.classList.add('hidden')); document.querySelectorAll('.panel-tab').forEach(t => t.classList.remove('active', 'text-blue-400')); document.getElementById(panel + '-panel').classList.remove('hidden'); document.querySelector('[data-panel="' + panel + '"]').classList.add('active', 'text-blue-400'); if (panel === 'preview') { this.updatePreview(); } } toggleBottomPanel() { const panel = document.getElementById('bottom-panel'); if (panel.style.height === '40px') { panel.style.height = '192px'; } else { panel.style.height = '40px'; } } startResize(elementId) { const isSidebar = elementId === 'sidebar'; const startX = event.clientX; const startWidth = isSidebar ? this.sidebarWidth : this.aiPanelWidth; const doDrag = (e) => { if (isSidebar) { this.sidebarWidth = Math.max(150, Math.min(400, startWidth + e.clientX - startX)); document.getElementById('sidebar').style.width = this.sidebarWidth + 'px'; } }; const stopDrag = () => { document.removeEventListener('mousemove', doDrag); document.removeEventListener('mouseup', stopDrag); }; document.addEventListener('mousemove', doDrag); document.addEventListener('mouseup', stopDrag); } showNotification(message) { const notif = document.createElement('div'); notif.className = 'fixed bottom-4 right-4 bg-blue-600 text-white px-4 py-2 rounded shadow-lg z-50 text-sm'; notif.textContent = message; document.body.appendChild(notif); setTimeout(() => notif.remove(), 3000); } setupEventListeners() { // Keyboard shortcuts document.addEventListener('keydown', (e) => { if (e.ctrlKey || e.metaKey) { switch(e.key.toLowerCase()) { case 's': e.preventDefault(); this.saveAll(); break; case 'n': e.preventDefault(); this.newFile(); break; } } }); // Save on before unload window.addEventListener('beforeunload', () => { if (this.isDirty.size > 0) { this.saveAll(); } }); } } class AILearning { constructor() { this.patterns = new Map(); this.snippetUsage = new Map(); this.suggestionHistory = []; this.userStyle = { namingConvention: null, preferredQuotes: null, semicolonUsage: null, indentStyle: null }; this.loadData(); } loadData() { try { const data = localStorage.getItem('codemaster_ai'); if (data) { const parsed = JSON.parse(data); this.patterns = new Map(parsed.patterns || []); this.snippetUsage = new Map(parsed.snippets || []); this.userStyle = parsed.style || this.userStyle; } } catch (e) {} } saveData() { try { const data = { patterns: Array.from(this.patterns), snippets: Array.from(this.snippetUsage), style: this.userStyle }; localStorage.setItem('codemaster_ai', JSON.stringify(data)); } catch (e) {} } recordEdit(filename, content) { // Analyze content for patterns this.analyzePatterns(content); // Track snippet usage this.trackSnippets(content); // Debounced save clearTimeout(this.saveTimeout); this.saveTimeout = setTimeout(() => this.saveData(), 5000); } analyzePatterns(content) { // Detect naming convention const camelCase = content.match(/[a-z]+[A-Z][a-zA-Z]+/g) || []; const snake_case = content.match(/[a-z]+_[a-z_]+/g) || []; const PascalCase = content.match(/[A-Z][a-z]+[A-Z][a-zA-Z]+/g) || []; if (camelCase.length > snake_case.length && camelCase.length > PascalCase.length) { this.userStyle.namingConvention = 'camelCase'; } else if (snake_case.length > camelCase.length) { this.userStyle.namingConvention = 'snake_case'; } // Detect quote preference const singleQuotes = (content.match(/'/g) || []).length; const doubleQuotes = (content.match(/"/g) || []).length; this.userStyle.preferredQuotes = doubleQuotes > singleQuotes ? 'double' : 'single'; // Detect semicolon usage const lines = content.split('\n'); const linesWithSemicolon = lines.filter(l => l.trim().endsWith(';')).length; this.userStyle.semicolonUsage = linesWithSemicolon > lines.length * 0.3; // Detect indent style const spaces = content.match(/^ +/gm) || []; const tabs = content.match(/^\t+/gm) || []; this.userStyle.indentStyle = spaces.length > tabs.length ? 'spaces' : 'tabs'; } trackSnippets(content) { // Common patterns to track const patterns = [ { regex: /console\.log\([^)]+\)/g, name: 'console.log' }, { regex: /document\.getElementById\([^)]+\)/g, name: 'getElementById' }, { regex: /document\.querySelector\([^)]+\)/g, name: 'querySelector' }, { regex: /function\s+\w+\s*\([^)]*\)\s*{/g, name: 'function declaration' }, { regex: /const\s+\w+\s*=/g, name: 'const declaration' }, { regex: /let\s+\w+\s*=/g, name: 'let declaration' }, { regex: /if\s*\([^)]+\)\s*{/g, name: 'if statement' }, { regex: /for\s*\([^)]+\)\s*{/g, name: 'for loop' } ]; patterns.forEach(p => { const matches = content.match(p.regex) || []; matches.forEach(match => { const key = p.name + ':' + match.substring(0, 20); const count = this.snippetUsage.get(key) || { count: 0, code: match.substring(0, 30) }; count.count++; this.snippetUsage.set(key, count); }); }); } getSuggestion(beforeCursor, typed, filename) { const ext = filename.split('.').pop().toLowerCase(); // Context-aware suggestions based on file type if (ext === 'html' || ext === 'htm') { if (typed === '<') { return { text: 'div', insert: 'div>', confidence: 0.9 }; } if (beforeCursor.endsWith('', insert: '>', confidence: 0.85 }; } if (beforeCursor.endsWith('

', insert: '>

', confidence: 0.85 }; } } if (ext === 'css') { if (beforeCursor.endsWith(' {')) { return { text: ' }', insert: '\n \n}', confidence: 0.9 }; } } if (ext === 'js' || ext === 'javascript') { // Learned snippet suggestions if (typed === 'c' && this.snippetUsage.has('console.log')) { const usage = this.snippetUsage.get('console.log'); if (usage.count > 2) { return { text: 'onsole.log()', insert: 'onsole.log()', confidence: Math.min(0.95, 0.7 + usage.count * 0.05) }; } } if (typed === 'f' && beforeCursor.match(/^\s*$/)) { return { text: 'unction name() {}', insert: 'unction ' + this.guessFunctionName() + '() {\n \n}', confidence: 0.8 }; } if (beforeCursor.endsWith('doc')) { return { text: 'ument.', insert: 'ument.', confidence: 0.85 }; } } // Smart closing pairs based on user's learned patterns if (this.userStyle.namingConvention === 'camelCase') { // Suggest camelCase completions } return null; } guessFunctionName() { // Could be enhanced based on context return 'myFunction'; } recordAcceptance(suggestion) { this.suggestionHistory.unshift({ text: suggestion.text, time: new Date().toLocaleTimeString() }); if (this.suggestionHistory.length > 10) { this.suggestionHistory.pop(); } } getStats() { const snippets = Array.from(this.snippetUsage.entries()) .sort((a, b) => b[1].count - a[1].count) .slice(0, 5) .map(([key, value]) => ({ trigger: key.split(':')[0], code: value.code, count: value.count })); const totalPatterns = this.patterns.size + this.snippetUsage.size; const confidence = Math.min(100, Math.floor(totalPatterns * 2)); return { patterns: totalPatterns, confidence: confidence, topSnippets: snippets, recentSuggestions: this.suggestionHistory, style: this.userStyle }; } } // Initialize const app = new CodeMasterIDE();