// CLI Command System for AeThex Studio export interface CLICommand { name: string; description: string; usage: string; aliases?: string[]; execute: (args: string[], context: CLIContext) => Promise; } export interface CLIContext { currentCode: string; currentFile?: string; files: any[]; setCode?: (code: string) => void; addLog?: (message: string, type?: 'log' | 'warn' | 'error' | 'info') => void; } export interface CLIResult { success: boolean; output: string; type?: 'log' | 'warn' | 'error' | 'info'; } // Built-in CLI commands export const commands: Record = { help: { name: 'help', description: 'Display available commands', usage: 'help [command]', execute: async (args) => { if (args.length > 0) { const cmd = commands[args[0]] || Object.values(commands).find(c => c.aliases?.includes(args[0])); if (cmd) { return { success: true, output: `${cmd.name} - ${cmd.description}\nUsage: ${cmd.usage}${cmd.aliases ? `\nAliases: ${cmd.aliases.join(', ')}` : ''}`, type: 'info', }; } return { success: false, output: `Command not found: ${args[0]}`, type: 'error', }; } const commandList = Object.values(commands) .map(cmd => ` ${cmd.name.padEnd(15)} - ${cmd.description}`) .join('\n'); return { success: true, output: `Available Commands:\n${commandList}\n\nType 'help ' for more info`, type: 'info', }; }, }, clear: { name: 'clear', description: 'Clear the terminal', usage: 'clear', aliases: ['cls'], execute: async () => { return { success: true, output: '__CLEAR__', type: 'info', }; }, }, run: { name: 'run', description: 'Execute current Lua script', usage: 'run', aliases: ['execute', 'exec'], execute: async (args, context) => { if (!context.currentCode || context.currentCode.trim() === '') { return { success: false, output: 'No code to execute', type: 'error', }; } try { // Simulate script execution return { success: true, output: `Executing script...\n${context.currentFile || 'Untitled'}\n\nScript executed successfully (simulated)`, type: 'info', }; } catch (error) { return { success: false, output: `Execution failed: ${error}`, type: 'error', }; } }, }, check: { name: 'check', description: 'Check current script for syntax errors', usage: 'check', aliases: ['lint', 'validate'], execute: async (args, context) => { if (!context.currentCode || context.currentCode.trim() === '') { return { success: false, output: 'No code to check', type: 'warn', }; } // Simple Lua syntax checks const issues: string[] = []; const lines = context.currentCode.split('\n'); lines.forEach((line, i) => { // Check for common syntax issues if (line.includes('end)') && !line.includes('function')) { issues.push(`Line ${i + 1}: Possible syntax error - 'end)' found`); } if ((line.match(/\(/g) || []).length !== (line.match(/\)/g) || []).length) { issues.push(`Line ${i + 1}: Unbalanced parentheses`); } }); if (issues.length === 0) { return { success: true, output: `✓ No syntax errors found (${lines.length} lines checked)`, type: 'info', }; } return { success: false, output: `Found ${issues.length} potential issue(s):\n${issues.join('\n')}`, type: 'warn', }; }, }, count: { name: 'count', description: 'Count lines, words, or characters in current script', usage: 'count [lines|words|chars]', execute: async (args, context) => { if (!context.currentCode) { return { success: false, output: 'No code to count', type: 'error', }; } const lines = context.currentCode.split('\n').length; const words = context.currentCode.split(/\s+/).filter(w => w.length > 0).length; const chars = context.currentCode.length; const type = args[0]?.toLowerCase(); switch (type) { case 'lines': return { success: true, output: `Lines: ${lines}`, type: 'info' }; case 'words': return { success: true, output: `Words: ${words}`, type: 'info' }; case 'chars': case 'characters': return { success: true, output: `Characters: ${chars}`, type: 'info' }; default: return { success: true, output: `Lines: ${lines} | Words: ${words} | Characters: ${chars}`, type: 'info', }; } }, }, api: { name: 'api', description: 'Search Roblox API documentation', usage: 'api ', execute: async (args) => { if (args.length === 0) { return { success: false, output: 'Usage: api \nExample: api Players, api Workspace', type: 'warn', }; } const query = args.join(' '); const commonAPIs = { 'Players': 'Service for managing player instances', 'Workspace': 'Container for 3D objects in the game', 'ReplicatedStorage': 'Storage for replicated objects', 'ServerStorage': 'Server-only storage', 'Instance': 'Base class for all Roblox objects', 'Part': 'Basic building block', 'Script': 'Server-side Lua code', 'LocalScript': 'Client-side Lua code', }; const match = Object.keys(commonAPIs).find( key => key.toLowerCase() === query.toLowerCase() ); if (match) { return { success: true, output: `${match}: ${commonAPIs[match as keyof typeof commonAPIs]}\n\nDocs: https://create.roblox.com/docs/reference/engine/classes/${match}`, type: 'info', }; } return { success: true, output: `Search: https://create.roblox.com/docs/reference/engine/classes/${query}`, type: 'info', }; }, }, template: { name: 'template', description: 'List or load code templates', usage: 'template [list|]', execute: async (args, context) => { if (args.length === 0 || args[0] === 'list') { return { success: true, output: `Available templates: - basic : Basic Roblox script structure - playeradded : PlayerAdded event handler - datastore : DataStore usage example - remote : RemoteEvent/RemoteFunction - gui : GUI scripting basics Usage: template `, type: 'info', }; } return { success: true, output: `Template '${args[0]}' - Use Templates panel (Ctrl+T) to load templates into editor`, type: 'info', }; }, }, export: { name: 'export', description: 'Export current script to file', usage: 'export [filename]', execute: async (args, context) => { const filename = args[0] || 'script.lua'; const code = context.currentCode || ''; try { const blob = new Blob([code], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename.endsWith('.lua') ? filename : `${filename}.lua`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); return { success: true, output: `Exported to ${a.download}`, type: 'info', }; } catch (error) { return { success: false, output: `Export failed: ${error}`, type: 'error', }; } }, }, echo: { name: 'echo', description: 'Print text to terminal', usage: 'echo ', execute: async (args) => { return { success: true, output: args.join(' '), type: 'log', }; }, }, info: { name: 'info', description: 'Display system information', usage: 'info', execute: async (args, context) => { return { success: true, output: `AeThex Studio v1.0.0 Environment: Browser-based IDE Platform: Roblox Lua Files: ${context.files?.length || 0} Current File: ${context.currentFile || 'Untitled'} Code Size: ${context.currentCode?.length || 0} characters`, type: 'info', }; }, }, }; export function executeCommand( input: string, context: CLIContext ): Promise { const parts = input.trim().split(/\s+/); const commandName = parts[0].toLowerCase(); const args = parts.slice(1); // Find command by name or alias const command = commands[commandName] || Object.values(commands).find(cmd => cmd.aliases?.includes(commandName) ); if (!command) { return Promise.resolve({ success: false, output: `Command not found: ${commandName}\nType 'help' for available commands`, type: 'error', }); } return command.execute(args, context); }