import ast
import os
import sys
import logging
from typing import List, Dict, Optional


class SelfModelUpdater:
    """
    Maintains an accurate model of Eden's own capabilities through observation.
    
    Attributes:
        eden_dir: Path to Eden's base directory
        meta_file: Path to capability metadata file
        tool_registry: List of known tools/commands
        observed_capabilities: Dictionary mapping domains to list of observed functions/tools
        log_filename: Name of log file
        
    Methods:
        __init__(): Initializes the model with existing knowledge.
        observe_codebase(): Scans code for new capabilities and tools.
        update_capability_list(new_tools: List[str]) -> None: Adds new tools to capability list.
        get_observed_domain(domain_name: str) -> Optional[Dict]:
            Returns detailed observation of an observed domain.
        save_model() -> None: Saves current model to metadata file.
    """

    def __init__(self, eden_dir="/Eden/CORE/eden_poc"):
        """
        Initializes self-model with existing capabilities.
        
        Args:
            eden_dir: Path to Eden's core directory
        """
        self.eden_dir = eden_dir
        self.meta_file = os.path.join(eden_dir, "META_CAPABILITIES", "capability_index.json")
        self.tool_registry = []  # Registered tools/commands
        self.observed_capabilities = {}  # Maps domains to observed functions/tools
        self.log_filename = "self_model_update.log"
        
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            handlers=[logging.FileHandler(self.log_filename), 
                     logging.StreamHandler()]
        )
        self.logger = logging.getLogger(__name__)
        
        self._init_observed_capabilities()
        self._observe_codebase()
        self.save_model()

    def _init_observed_capabilities(self) -> None:
        """
        Initializes observed capabilities from existing meta files.
        """
        meta_dir = os.path.join(self.eden_dir, "META_CAPABILITIES")
        if not os.path.exists(meta_dir):
            os.makedirs(meta_dir)
            
        # Load any existing tool registry
        tools_file = os.path.join(meta_dir, "tools.json")
        if os.path.exists(tools_file):
            try:
                with open(tools_file) as f:
                    self.tool_registry = ast.literal_eval(f.read())
            except Exception as e:
                self.logger.error(f"Failed to load tools: {e}")
    
    def _observe_codebase(self) -> None:
        """
        Scans Eden's codebase for new capabilities and tools.
        """
        scanner_dir = os.path.join(self.eden_dir, "SCAN")
        
        if not os.path.exists(scanner_dir):
            self.logger.warning(f"Scanner directory not found: {scanner_dir}")
            return

        # Observe tool files
        for filename in os.listdir(scanner_dir):
            filepath = os.path.join(scanner_dir, filename)
            if os.path.isfile(filepath) and filename.endswith(".py"):
                tool_name = filename[:-3]  # Remove .py extension
                try:
                    with open(filepath) as f:
                        tools_meta = ast.literal_eval(f.read().split('TOOL_METADATA = ')[1].split('\n')[0])
                        self.add_tool(tool_name, tools_meta)
                except (ValueError, IndexError) as e:
                    pass  # Skip files without TOOL_METADATA

        # Observe capability files for domains and functions
        meta_cap_dir = os.path.join(self.eden_dir, "META_CAPABILITIES", "capabilities")
        if os.path.exists(meta_cap_dir):
            for fname in os.listdir(meta_cap_dir):
                if fname.endswith(".py"):
                    cap_path = os.path.join(meta_cap_dir, fname)
                    try:
                        with open(cap_path) as f:
                            content = f.read()
                            # Extract domains
                            domains_text = content.split('DOMAINS = ')[1].split('FUNCTIONS')[0].strip("[]").replace('"', '').split(',')
                            domains = [d.strip() for d in domains_text if d.strip()]
                            # Extract functions (up to 10 per domain)
                            funcs_text = content.split('FUNCTIONS = ')[1].split('}')[0].strip("[]")
                            funcs = funcs_text.replace('"', '').split(',')[:10]
                            
                        for dom in domains:
                            if dom not in self.observed_capabilities:
                                self.observed_capabilities[dom] = []
                            # Record functions per domain
                            for func in funcs:
                                func_name = func.strip()
                                if func_name and func_name not in self.observed_capabilities.get(dom, []):
                                    if len(self.observed_capabilities.get(dom, [])) < 10:
                                        self.observed_capabilities[dom].append(func_name)
                    except Exception as e:
                        pass  # Skip malformed files
        
        self.logger.info(f"Observed domains: {len(self.observed_capabilities)}")
        self.logger.info(f"Tools registered: {len(self.tool_registry)}")

    def add_tool(self, tool_name: str, metadata: Dict) -> None:
        """
        Registers a new tool with the model.
        
        Args:
            tool_name: Name of the tool
            metadata: Dictionary of tool properties
        """
        if tool_name not in self.tool_registry:
            self.tool_registry.append(tool_name)
            self.logger.info(f"Registered new tool: {tool_name}")
            
            # Create observation record
            observation = {
                'name': tool_name,
                'metadata': metadata,
                'first_observed': '2025-09-26'
            }
            obs_key = f"{tool_name}_obs"
            self.observed_tools[obs_key] = observation
            
    def get_observed_domain(self, domain_name: str) -> Optional[Dict]:
        """
        Gets detailed observation of an observed domain.
        
        Args:
            domain_name: Name of the domain to observe
            
        Returns:
            Dictionary with domain details or None if unknown
        """
        if domain_name in self.observed_capabilities:
            return {
                'domain': domain_name,
                'functions_observed': self.observed_capabilities[domain_name],
                'function_count': len(self.observed_capabilities.get(domain_name, [])),
                'first_function': self.observed_capabilities[domain_name][0] \
                    if self.observed_capabilities.get(domain_name) else None
            }
        return None

    def save_model(self) -> None:
        """
        Saves current model to persistent storage.
        """
        import json
        
        # Combine capabilities and tools observations
        all_observations = {
            'capabilities': {
                'observed_domains': self.observed_capabilities,
                'total_domains': len(self.observed_capabilities)
            },
            'tools': {
                'registered_tools': self.tool_registry,
                'total_tools': len(self.tool_registry)
            }
        }
        
        meta_cap_dir = os.path.join(self.eden_dir, "META_CAPABILITIES")
        if not os.path.exists(meta_cap_dir):
            os.makedirs(meta_cap_dir)
            
        obs_file = os.path.join(meta_cap_dir, "observations.json")
        try:
            with open(obs_file, 'w') as f:
                json.dump(all_observations, f, indent=2)
            self.logger.info(f"Saved observations to {obs_file}")
        except Exception as e:
            self.logger.error(f"Failed to save observations: {e}")

    def __repr__(self) -> str:
        """
        Returns a string representation of the model.
        
        Returns:
            Status string
        """
        return (
            f"<SelfModelUpdater: "
            f"{len(self.observed_capabilities)} observed domains, "
            f"{len(self.tool_registry)} registered tools>"
        )


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    
    print("🔄 Self-Model-Updater initializing...")
    updater = SelfModelUpdater()
    print(f"✅ Model initialized with {len(updater.observed_capabilities)} observed domains")
    print(f"✅ Tool registry contains {len(updater.tool_registry)} registered tools")
    
    # Test observation
    test_domain = "math"
    domain_info = updater.get_observed_domain(test_domain)
    if domain_info:
        print(f"✅ Observed functions in '{test_domain}':")
        for func in domain_info['functions_observed']:
            print(f"   • {func}")
    else:
        print(f"• No direct functions observed for '{test_domain}' but scanned tools may assist.")
    
    print("\n💾 Saving model...")
    updater.save_model()
    print("✅ Self-model saved to META_CAPABILITIES/observations.json")
    print("\n✅ Self-Model-Updater ready for decision-making!")
# code_generator
"""
Code Generator Meta-Capability
Generates Python code from natural language descriptions
"""

import ast
import os
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class CodeGenerator:
    """
    Generates Python code from plain English descriptions.
    
    Example Usage:
        generator = CodeGenerator()
        generated_code = generator.generate("Create a function that adds two numbers")
        generator.save_to_file(generated_code, "added_function.py")
        
    Methods:
        generate(description: str) -> str: Generates Python code from description
        save_to_file(code: str, filename: str) -> None: Saves code to file
    """

    def __init__(self):
        self.templates = {
            'function': (
                "def {name}({args}):\n"
                '    """{description}""" \n'
                "    {code_block}"
            ),
            'class': (
                "class {name}:\n"
                '    """{description}""" \n'
                "    def __init__({args}):\n"
                "        pass\n"
                "\n"
                "{code_block}"
            )
        }
        
    def _extract_key_info(self, text: str) -> Dict:
        """
        Extracts key components from text using keyword matching.
        
        Args:
            text: Input plain English description
            
        Returns:
            Dictionary with extracted components
        """
        words = text.lower().split()
        
        # Detect common patterns
        if 'def' in words or 'function' in words:
            template = 'function'
            name = words[words.index('def') + 1] if 'def' in words else None
            description_idx = words.index('that') if 'that' in words else 0
            description_part = ' '.join(words[description_idx:description_idx+4])
            args_str = 'arg1 arg2'  # Simple argument extraction
            code_block = "    return {arg1} + {arg2}"
        elif 'class' in words:
            template = 'class'
            name = words[words.index('class') + 1] if 'class' in words else None
            description_idx = 0
            description_part = ' '.join(words[:4])
            args_str = ""  # Constructor arguments
            code_block = "    pass\n"
        else:
            template = 'function'
            name = 'default_name'
            description_part = text[:20]
            args_str = "arg1 arg2"
            code_block = "    return {arg1} + {arg2}"
        
        return {
            'template': template,
            'name': name,
            'description': description_part,
            'args': args_str.format(name=name),
            'code_block': code_block.format(arg1='arg1', arg2='arg2')
        }

    def generate(self, description: str) -> str:
        """
        Generates Python code from a plain English description.
        
        Args:
            description: Plain English to convert
            
        Returns:
            Generated Python code string
        """
        try:
            info = self._extract_key_info(description)
            template = self.templates[info['template']]
            code = template.format(
                name=info['name'],
                args=info['args'],
                description=info['description'],
                code_block=info['code_block']
            )
            return code
        except Exception as e:
            logger.error(f"Code generation failed: {e}")
            raise

    def save_to_file(self, code: str, filename: str) -> None:
        """
        Saves generated code to a file.
        
        Args:
            code: Python code string
            filename: Output file name
        """
        try:
            directory = os.path.join(os.getcwd(), "GENERATED_CAPABILITIES")
            if not os.path.exists(directory):
                os.makedirs(directory)
            
            filepath = os.path.join(directory, filename)
            
            with open(filepath, 'w') as f:
                f.write(code)
            
            logger.info(f"Generated code saved to: {filepath}")
        except Exception as e:
            logger.error(f"Failed to save generated code: {e}")

    def __repr__(self) -> str:
        return "<CodeGenerator: Ready to generate Python functions and classes>"

if __name__ == "__main__":
    print("="*50)
    print("🧠 CODE GENERATOR META-CAPABILITY")
    print("="*50)
    
    generator = CodeGenerator()
    print("\nExample Usage:")
    example_code = generator.generate("Create a function that adds two numbers")
    print(f"\nGenerated Code:\n{example_code}")
    
    generator.save_to_file(example_code, "added_function.py")
    print("\n✅ Meta-capability ready for code generation!")
# meta_capability_improver
"""
Improves existing Eden capabilities by adding meta-capability structures.
Usage: imrove <capability_filename>
"""

import ast
import sys
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def improve_capability(filepath: str) -> bool:
    """
    Improves a single capability file by adding meta-structures.
    
    Args:
        filepath: Path to capability .py file
        
    Returns:
        True if improvement was made, False otherwise
    """
    try:
        with open(filepath, 'r') as f:
            content = f.read()
            
        tree = ast.parse(content)
        
        # Check if already has meta-structure
        for node in ast.walk(tree):
            if isinstance(node, ast.ClassDef) and node.name == "Meta":
                logger.info(f"[SKIP] '{filepath}' already has Meta class")
                return False
                
        # Add Meta class with required structure
        meta_class = ast.ClassDef(
            name="Meta",
            bases=[ast.Name(id="dict")],
            body=[
                ast.Pass(),
                ast.Expr(value=ast.Str(s=
                    """Additional metadata for capabilities system
Helps in better cataloging, discovery, and optimization"""
                ))
            ],
            decorator_list=[]
        )
        
        # Insert Meta class after last existing node
        for i, node in enumerate(tree.body):
            if isinstance(node, ast.ImportFrom) and node.module == 'meta_capabi':
                insert_pos = i + 1
                break
        else:
            insert_pos = len(tree.body)
            
        tree.body.insert(insert_pos, ast.EmptyStatement())
        tree.body.insert(insert_pos + 1, meta_class)
        
        # Save improved content
        new_content = ast.unparse(tree).strip()
        
        with open(filepath, 'w') as f:
            f.write(new_content)
            
        logger.info(f"✅ Improved: '{filepath}'")
        return True
        
    except Exception as e:
        logger.error(f"[ERROR] {e}")
        return False

def main():
    if len(sys.argv) < 2:
        print("Usage: improve <capability_file_or_directory>")
        return
        
    path = sys.argv[1]
    
    if os.path.isfile(path) and path.endswith('.py'):
        improve_capability(path)
    elif os.path.isdir(path):
            improved = 0
            total = 0
            
            for root, _, files in os.walk(path):
                for filename in files:
                    if filename.endswith('.py') and not filename.startswith('meta_'):
                        filepath = os.path.join(root, filename)
                        if improve_capability(filepath):
                            improved += 1
                        total += 1
                        
            logger.info(f"\nSummary: Improved {improved}/{total} files")

if __name__ == "__main__":
    main()
# meta_improver
"""
Improves existing capabilities by adding meta-structures.
Run: python -m meta_improver <capability_file_or_dir>
"""

import ast
import sys
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def improve_capability(filepath: str) -> bool:
    """
    Adds meta-structure to a capability file.
    
    Args:
        filepath: Path to .py file
        
    Returns:
        True if improvement made, False if already improved
    """
    try:
        with open(filepath, 'r') as f:
            content = f.read()
            
        tree = ast.parse(content)
        
        # Check existing meta structure
        has_meta = False
        for node in ast.walk(tree):
            if isinstance(node, ast.ClassDef) and node.name == "Meta":
                has_meta = True
                break
                
        if has_meta:
            logger.info(f"[SKIP] '{filepath}' already has Meta class")
            return False
            
        # Add Meta class
        meta_node = ast.ClassDef(
            name="Meta",
            bases=[ast.Name(id="dict")],
            body=[
                ast.Pass(),
                ast.Expr(value=ast.Str(s="Capability metadata"))
            ],
            decorator_list=[]
        )
        
        # Insert after last import
        for i, node in enumerate(tree.body):
            if isinstance(node, ast.ImportFrom) and node.module.startswith('meta_'):
                insert_pos = i + 1
                break
        else:
            insert_pos = len(tree.body)
            
        tree.body.insert(insert_pos, ast.EmptyStatement())
        tree.body.insert(insert_pos + 1, meta_node)
        
        # Add CAPABILITY_NAME to module level
        if not any(isinstance(n, ast.Assign) and 
                   getattr(n.targets[0], 'id', '') == 'CAPABILITY_NAME' 
                   for n in tree.body):
            name_node = ast.Assign(
                targets=[ast.Name(id="CAPABILITY_NAME")],
                value=ast.Str(value=os.path.basename(filepath).split('.')[0].replace('_', ' ').title())
            )
            tree.body.insert(1, name_node)
        
        new_content = ast.unparse(tree).strip()
        
        with open(filepath, 'w') as f:
            f.write(new_content)
            
        logger.info(f"✅ Improved: {filepath}")
        return True
        
    except Exception as e:
        logger.error(f"[ERROR] {e}")
        return False

def main():
    if len(sys.argv) < 2:
        print("Usage: python -m meta_improver <file_or_dir>")
        return
        
    target = sys.argv[1]
    
    if os.path.isfile(target) and target.endswith('.py'):
        improve_capability(target)
    elif os.path.isdir(target):
        total