Skill: nerua1/ralph-wiggum-loop (version 1.0.0)

# Ralph Wiggum - AI Loop Technique Iteracyjny system doskonalenia kodu i outputów AI. Nazwany na cześć Ralpha Wigguma z Simpsons - bo "mówi jak dziecko, ale myśli jak krytyk". ## Architektura ``` ┌─────────────┐ │ Generator │ → Tworzy początkowy output └──────┬──────┘ ▼ ┌─────────────┐ │ Krytyk │ → Szuka błędów, optymalizacji, problemów └──────┬──────┘ ▼ ┌─────────────┐ │ Naprawiacz │ → Poprawia zgłoszone problemy └──────┬──────┘ ▼ ┌─────────────┐ │ Weryfikator │ → Sprawdza czy poprawki działają └──────┬──────┘ │ ├─ Problemy? → Wraca do Krytyka (max 3 iteracje) ▼ [OUTPUT] ``` ## Wymagania - LM Studio uruchomione na `http://127.0.0.1:1234/v1` - Model preferowany: uncensored/liberated (np. dolphin, wizard-vicuna) - Python 3.9+ - curl / wget ## Instalacja ```bash # Skill jest gotowy do użycia po sklonowaniu # Sprawdź czy LM Studio działa: curl http://127.0.0.1:1234/v1/models ``` ## Użycie ### Podstawowe ```bash # Ulepsz kod z pliku ralph-loop.sh -f input.py -o output.py # Ulepsz kod inline ralph-loop.sh -c "def hello(): print('world')" # Ulepsz z promptem kontekstowym ralph-loop.sh -f input.py -p "Optymalizuj pod kątem wydajności" ``` ### Opcje | Flag | Opis | |------|------| | `-f FILE` | Plik wejściowy | | `-c CODE` | Kod inline (zamiast pliku) | | `-o FILE` | Plik wyjściowy (domyślnie: stdout) | | `-p PROMPT` | Dodatkowy kontekst/prompt | | `-i N` | Max iteracji (domyślnie: 3) | | `-m MODEL` | Nazwa modelu w LM Studio | | `-v` | Verbose - pokaż proces | | `--json` | Output w formacie JSON | ## Przykłady ### Przykład 1: Refaktoryzacja kodu ```bash ralph-loop.sh -f examples/bad_code.py -o fixed.py -v ``` ### Przykład 2: Generowanie od zera ```bash ralph-loop.sh -c "Napisz funkcję sortowania quicksort w Python" \ -o quicksort.py -p "Dodaj type hints i docstrings" ``` ### Przykład 3: Analiza tekstu ```bash ralph-loop.sh -f examples/article.txt -o analysis.json --json ``` ## Jak to działa 1. **Generator** (generator.py) - Tworzy początkowy output używając LLM - Używa promptu systemowego z kontekstem zadania 2. **Krytyk** (critic.py) - Analizuje kod pod kątem: - Błędów składniowych i logicznych - OPTYMALIZACJI (złożoność, wydajność) - BEZPIECZEŃSTWA (podatności, injection) - STYLU (PEP8, czytelność, konwencje) - DOKUMENTACJI (docstrings, komentarze) - Zwraca listę problemów w formacie JSON 3. **Naprawiacz** (część ralph-loop.sh) - Wysyła kod + listę problemów do LLM - Prosi o poprawienie wszystkich zgłoszonych problemów 4. **Weryfikator** (część ralph-loop.sh) - Sprawdza czy poprawki faktycznie rozwiązują problemy - Ocenia czy kod jest gotowy czy potrzebna kolejna iteracja 5. **Pętla** - Jeśli weryfikator znajdzie nowe problemy → wraca do Krytyka - Max 3 iteracje (konfigurowalne) ## Prompt Engineering System używa specyficznych promptów dla każdej roli: ### Prompt Generatora ``` Jesteś ekspertem programistą. Twoim zadaniem jest {task}. Stwórz najlepszy możliwy kod/tekst. Używaj najnowszych praktyk. {context} ``` ### Prompt Krytyka ``` Jesteś bezwzględnym code reviewerem. Twoim zadaniem jest znalezienie WSZYSTKICH problemów w podanym kodzie. Sprawdź: - Błędy składniowe i logiczne - Optymalizację (czasowa i pamięciowa) - Bezpieczeństwo (SQL injection, XSS, etc.) - Styl kodu (PEP8, konwencje) - Dokumentację Zwróć listę problemów w formacie JSON: { "issues": [ {"severity": "high|medium|low", "category": "...", "description": "...", "suggestion": "..."} ] } ``` ### Prompt Naprawiacza ``` Otrzymałeś kod i listę problemów do naprawy. Napraw KAŻDY problem z listy. Nie dodawaj nowych funkcji - tylko napraw. KOD: {code} PROBLEMY: {issues} Zwróć TYLKO poprawiony kod, bez dodatkowych komentarzy. ``` ## API (Python) Możesz używać modułów bezpośrednio w Pythonie: ```python from ralph_loop import Generator, Critic, Verifier gen = Generator(model="qwen2.5-coder-32b") code = gen.generate("Napisz funkcję FizzBuzz", context="Użyj list comprehension") critic = Critic() issues = critic.analyze(code) verifier = Verifier() result = verifier.verify(code, issues) ``` ## Debugowanie ```bash # Sprawdź czy LM Studio działa curl http://127.0.0.1:1234/v1/models | jq . # Testuj pojedynczy komponent python scripts/generator.py -t "Napisz hello world" python scripts/critic.py -f test.py # Verbose mode ralph-loop.sh -f input.py -vvv ``` ## Troubleshooting ### "Connection refused" - Upewnij się że LM Studio jest uruchomione - Sprawdź czy API jest włączone w ustawieniach LM Studio - Domyślny port: 1234 ### "Model not found" - Sprawdź dostępne modele: `curl http://127.0.0.1:1234/v1/models` - Użyj flagi `-m` aby wskazać konkretny model ### Słaba jakość outputu - Użyj lepszego modelu (min. 7B parametrów) - Zwiększ max iteracji: `-i 5` - Dodaj szczegółowy kontekst: `-p "Szczegółowe wymagania"` ## Autor Stworzone jako narzędzie OpenClaw. Nazwa inspirowana Ralphem Wiggumem - "I'm helping!"

path: README.md
content: # ralph-wiggum-loop

Iterative improvement loop: Generator→Critic→Fixer→Verifier via LM Studio

Install:
```bash
git clone https://github.com/nerua1/ralph-wiggum-loop ~/.claude/skills/vault/ralph-wiggum-loop
```

Then load: `/skill ralph-wiggum-loop`

---

If this saved you time: [☕ PayPal.me/nerudek](https://www.paypal.me/nerudek)


path: examples/bad_code.py
content: # Bad code example - do przetestowania Ralph Wiggum Loop

def calc(x,y):
    if x>0:
        if y>0:
            return x+y
        else:
            return x-y
    else:
        if y>0:
            return x*y
        else:
            return x/y

# Problem: brak obsługi dzielenia przez zero
# Problem: brak type hints
# Problem: brak docstring
# Problem: zagnieżdżone if-y (można uprościć)
# Problem: nieczytelna nazwa funkcji
# Problem: brak walidacji inputu

path: examples/fizzbuzz_raw.py
content: #!/usr/bin/env python3
"""
Przykład użycia Ralph Wiggum Loop do generowania kodu od zera.
"""

# Zadanie: Napisz funkcję FizzBuzz

def fizzbuzz(n):
    for i in range(1, n+1):
        if i % 3 == 0 and i % 5 == 0:
            print("FizzBuzz")
        elif i % 3 == 0:
            print("Fizz")
        elif i % 5 == 0:
            print("Buzz")
        else:
            print(i)

# Problem: brak return, tylko print
# Problem: brak type hints
# Problem: brak docstring
# Problem: nieoptymalne sprawdzanie warunków
# Problem: brak walidacji n

path: scripts/critic.py
content: #!/usr/bin/env python3
"""
Ralph Wiggum Loop - Critic Module
Bezwzględny code reviewer. Szuka WSZYSTKICH problemów w kodzie.
"""

import argparse
import json
import os
import sys
import re
from typing import List, Dict, Any, Optional

try:
    import requests
except ImportError:
    print("Error: requests module not found. Install: pip install requests")
    sys.exit(1)


class Critic:
    """Krytyk - analizuje kod pod kątem problemów."""
    
    DEFAULT_API_URL = "http://127.0.0.1:1234/v1"
    
    SYSTEM_PROMPT = """Jesteś bezwzględnym, pedantycznym code reviewerem i ekspertem od jakości oprogramowania.
Twoim zadaniem jest znalezienie WSZYSTKICH problemów w podanym kodzie.

Sprawdź dokładnie każdy z poniższych obszarów:

1. BŁĘDY (errors) - krytyczne problemy:
   - Błędy składniowe (SyntaxError, IndentationError)
   - Błędy logiczne (nieskończone pętle, błędne warunki)
   - Błędy runtime (IndexError, KeyError, TypeError, AttributeError)
   - Niezdefiniowane zmienne/funkcje
   - Nieobsłużone wyjątki
   - Błędy importów

2. OPTYMALIZACJA (optimization):
   - Złożoność czasowa (O(n²) zamiast O(n log n))
   - Złożoność pamięciowa (niepotrzebne kopie dużych struktur)
   - Nieefektywne pętle
   - Redundantne operacje
   - Brak lazy evaluation
   - Nieoptymalne użycie kolekcji

3. BEZPIECZEŃSTWO (security):
   - SQL injection (string formatting w zapytaniach SQL)
   - Command injection (os.system, subprocess z user input)
   - XSS (cross-site scripting)
   - Path traversal (../ w ścieżkach)
   - Hardcoded secrets/keys/passwords
   - Deserializacja niezaufanych danych (pickle, yaml.load)
   - SSRF (server-side request forgery)
   - Race conditions
   - Brak walidacji inputu

4. STYL I KONWENCJE (style):
   - Naruszenia PEP8 (Python)
   - Niejasne nazwy zmiennych/funkcji
   - Za długie funkcje/metody
   - Za duża złożoność cyklomatyczna
   - Niepotrzebne komentarze lub brak komentarzy
   - Niespójne formatowanie
   - Nieużywane importy/zmienne
   - Magic numbers

5. DOKUMENTACJA (documentation):
   - Brak docstrings
   - Niekompletne docstrings
   - Brak type hints
   - Niejasne nazwy parametrów
   - Brak komentarzy do złożonej logiki

6. TESTOWALNOŚĆ (testability):
   - Brak testów
   - Kod ściśle sprzężony
   - Globalny stan
   - Niepotrzebne efekty uboczne

Dla każdego problemu określ:
- severity: "high" (krytyczny), "medium" (ważny), "low" (kosmetyczny)
- category: jedna z powyższych kategorii
- line: numer linii (jeśli można określić)
- description: szczegółowy opis problemu
- suggestion: konkretna propozycja naprawy

Zwróć wynik TYLKO jako valid JSON w formacie:
{
  "issues": [
    {
      "severity": "high|medium|low",
      "category": "errors|optimization|security|style|documentation|testability",
      "line": 42,
      "description": "Opis problemu",
      "suggestion": "Jak naprawić"
    }
  ],
  "summary": {
    "total_issues": N,
    "high": N,
    "medium": N,
    "low": N,
    "assessment": "brief assessment of overall quality"
  }
}

Jeśli nie ma problemów, zwróć pustą listę issues.
Bądź SZCZEGÓŁOWY i KONKRETNY. Nie pomijaj żadnych problemów."""

    def __init__(self, api_url: str = None, model: str = None):
        self.api_url = api_url or os.getenv("LMSTUDIO_URL", self.DEFAULT_API_URL)
        self.model = model or os.getenv("LMSTUDIO_MODEL_CRITIC")
        self.session = requests.Session()
        self.session.headers.update({"Content-Type": "application/json"})
    
    def _get_available_models(self) -> list:
        """Pobiera listę dostępnych modeli."""
        try:
            response = self.session.get(f"{self.api_url}/models")
            response.raise_for_status()
            data = response.json()
            return data.get("data", [])
        except Exception:
            return []
    
    def _select_model(self) -> Optional[str]:
        """Wybiera najlepszy model do krytyki."""
        models = self._get_available_models()
        if not models:
            return None
        
        # For critic, we want a strong reasoning model
        priority = [
            "qwen2.5", "qwen3", "llama-3", "mistral", 
            "deepseek", "codellama", "dolphin"
        ]
        
        model_names = [m.get("id", "") for m in models]
        
        for keyword in priority:
            for name in model_names:
                if keyword.lower() in name.lower():
                    return name
        
        return model_names[0] if model_names else None
    
    def _extract_json(self, text: str) -> dict:
        """Ekstrahuje JSON z odpowiedzi LLM."""
        # Try direct parsing first
        try:
            return json.loads(text.strip())
        except json.JSONDecodeError:
            pass
        
        # Try extracting from markdown code blocks
        patterns = [
            r'```json\s*(.*?)\s*```',
            r'```\s*(.*?)\s*```',
            r'\{.*\}',
        ]
        
        for pattern in patterns:
            matches = re.findall(pattern, text, re.DOTALL)
            for match in matches:
                try:
                    return json.loads(match.strip())
                except json.JSONDecodeError:
                    continue
        
        raise ValueError(f"Could not extract JSON from response: {text[:500]}")
    
    def analyze(
        self, 
        code: str, 
        language: str = "python",
        context: str = "",
        temperature: float = 0.2
    ) -> Dict[str, Any]:
        """
        Analizuje kod i zwraca listę problemów.
        
        Args:
            code: Kod do analizy
            language: Język programowania
            context: Dodatkowy kontekst
            temperature: Kreatywność (niska dla konsystencji)
        
        Returns:
            Słownik z issues i summary
        """
        model = self.model or self._select_model()
        
        user_prompt = f"""Przeanalizuj poniższy kod pod kątem WSZYSTKICH problemów.

JĘZYK: {language}
{context}

KOD DO ANALIZY:
```{language}
{code}
```

Zwróć wynik jako valid JSON zgodnie z instrukcją systemową."""

        messages = [
            {"role": "system", "content": self.SYSTEM_PROMPT},
            {"role": "user", "content": user_prompt}
        ]
        
        payload = {
            "messages": messages,
            "temperature": temperature,
            "max_tokens": 8192,
            "stream": False
        }
        
        if model:
            payload["model"] = model
        
        try:
            response = self.session.post(
                f"{self.api_url}/chat/completions",
                json=payload,
                timeout=300
            )
            response.raise_for_status()
            data = response.json()
            
            content = data.get("choices", [{}])[0].get("message", {}).get("content", "")
            result = self._extract_json(content)
            
            # Validate structure
            if "issues" not in result:
                result["issues"] = []
            if "summary" not in result:
                result["summary"] = self._generate_summary(result.get("issues", []))
            
            return result
            
        except requests.exceptions.ConnectionError:
            raise ConnectionError(f"Cannot connect to LM Studio at {self.api_url}")
        except Exception as e:
            raise RuntimeError(f"Analysis failed: {e}")
    
    def _generate_summary(self, issues: List[Dict]) -> Dict[str, Any]:
        """Generuje podsumowanie na podstawie listy problemów."""
        high = sum(1 for i in issues if i.get("severity") == "high")
        medium = sum(1 for i in issues if i.get("severity") == "medium")
        low = sum(1 for i in issues if i.get("severity") == "low")
        
        if high > 0:
            assessment = "Code has critical issues that must be fixed"
        elif medium > 0:
            assessment = "Code has noticeable issues requiring attention"
        elif low > 0:
            assessment = "Code is mostly good with minor style issues"
        else:
            assessment = "Code looks good, no significant issues found"
        
        return {
            "total_issues": len(issues),
            "high": high,
            "medium": medium,
            "low": low,
            "assessment": assessment
        }
    
    def quick_check(self, code: str, language: str = "python") -> Dict[str, Any]:
        """Szybka analiza bez użycia LLM - podstawowe pattern matching."""
        issues = []
        lines = code.split('\n')
        
        # Basic Python checks
        if language.lower() == "python":
            for i, line in enumerate(lines, 1):
                # Check for print statements (should use logging)
                if re.search(r'\bprint\s*\(', line) and 'def ' not in line:
                    issues.append({
                        "severity": "low",
                        "category": "style",
                        "line": i,
                        "description": "Using print() instead of logging",
                        "suggestion": "Use logging module for production code"
                    })
                
                # Check for bare except
                if re.search(r'except\s*:', line):
                    issues.append({
                        "severity": "medium",
                        "category": "errors",
                        "line": i,
                        "description": "Bare except clause catches all exceptions including KeyboardInterrupt",
                        "suggestion": "Use 'except Exception:' or specify exact exception types"
                    })
                
                # Check for SQL injection risks
                if re.search(r'execute\s*\(.*%s', line) or re.search(r'f["\'].*SELECT.*{', line):
                    issues.append({
                        "severity": "high",
                        "category": "security",
                        "line": i,
                        "description": "Potential SQL injection vulnerability",
                        "suggestion": "Use parameterized queries with placeholders"
                    })
                
                # Check for hardcoded secrets
                if re.search(r'(password|secret|key|token)\s*=\s*["\'][^"\']+["\']', line, re.IGNORECASE):
                    if 'import' not in line and '#' not in line:
                        issues.append({
                            "severity": "high",
                            "category": "security",
                            "line": i,
                            "description": "Possible hardcoded credential",
                            "suggestion": "Use environment variables or secure vault"
                        })
        
        return {
            "issues": issues,
            "summary": self._generate_summary(issues)
        }


def main():
    parser = argparse.ArgumentParser(description="Ralph Wiggum Loop - Critic")
    parser.add_argument("-f", "--file", required=True, help="File to analyze")
    parser.add_argument("-l", "--language", default="python", help="Programming language")
    parser.add_argument("-c", "--context", default="", help="Additional context")
    parser.add_argument("--quick", action="store_true", help="Quick check without LLM")
    parser.add_argument("--model", help="Model name to use")
    parser.add_argument("--api-url", help="LM Studio API URL")
    parser.add_argument("-o", "--output", help="Output JSON file")
    parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output")
    
    args = parser.parse_args()
    
    try:
        with open(args.file, 'r', encoding='utf-8') as f:
            code = f.read()
    except Exception as e:
        print(f"Error reading file: {e}", file=sys.stderr)
        sys.exit(1)
    
    critic = Critic(api_url=args.api_url, model=args.model)
    
    try:
        if args.quick:
            result = critic.quick_check(code, args.language)
        else:
            result = critic.analyze(code, args.language, args.context)
        
        output = json.dumps(result, indent=2, ensure_ascii=False)
        
        if args.output:
            with open(args.output, 'w', encoding='utf-8') as f:
                f.write(output)
            print(f"Analysis saved to {args.output}")
        
        if args.verbose or not args.output:
            print(output)
            
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()


path: scripts/generator.py
content: #!/usr/bin/env python3
"""
Ralph Wiggum Loop - Generator Module
Tworzy początkowy output (kod, tekst, analiza) używając lokalnego LLM przez LM Studio.
"""

import argparse
import json
import os
import sys
import textwrap
from typing import Optional

try:
    import requests
except ImportError:
    print("Error: requests module not found. Install: pip install requests")
    sys.exit(1)


class Generator:
    """Generator - tworzy początkowy output używając LLM."""
    
    DEFAULT_API_URL = "http://127.0.0.1:1234/v1"
    DEFAULT_MODEL = None  # Auto-select first available
    
    SYSTEM_PROMPT = """Jesteś ekspertem programistą i inżynierem oprogramowania. 
Twoim zadaniem jest tworzenie wysokiej jakości kodu, tekstu lub analizy.

Zasady:
- Pisz czysty, czytelny kod
- Używaj najlepszych praktyk i wzorców projektowych
- Dodawaj komentarze tam gdzie to potrzebne
- Rozwiązuj problemy efektywnie i elegancko
- Jeśli kontekst zawiera konkretne wymagania - spełnij je dokładnie

Odpowiadaj tylko treścią wyjściową (kodem/tekstem/analizą), bez dodatkowych wyjaśnień.
"""

    def __init__(self, api_url: str = None, model: str = None):
        self.api_url = api_url or os.getenv("LMSTUDIO_URL", self.DEFAULT_API_URL)
        self.model = model or os.getenv("LMSTUDIO_MODEL", self.DEFAULT_MODEL)
        self.session = requests.Session()
        self.session.headers.update({
            "Content-Type": "application/json"
        })
    
    def _get_available_models(self) -> list:
        """Pobiera listę dostępnych modeli z LM Studio."""
        try:
            response = self.session.get(f"{self.api_url}/models")
            response.raise_for_status()
            data = response.json()
            return data.get("data", [])
        except Exception as e:
            print(f"Warning: Could not fetch models: {e}", file=sys.stderr)
            return []
    
    def _select_model(self) -> Optional[str]:
        """Wybiera najlepszy dostępny model."""
        models = self._get_available_models()
        if not models:
            return None
        
        # Priority order for model selection
        priority_keywords = [
            "uncensored", "liberated", "dolphin", "wizard",
            "qwen2.5-coder", "qwen3-coder", "codellama",
            "deepseek-coder", "llama-3", "mistral"
        ]
        
        model_names = [m.get("id", "") for m in models]
        
        # Try priority keywords
        for keyword in priority_keywords:
            for name in model_names:
                if keyword.lower() in name.lower():
                    return name
        
        # Default to first available
        return model_names[0]
    
    def generate(
        self, 
        task: str, 
        context: str = "",
        input_content: str = "",
        temperature: float = 0.7,
        max_tokens: int = 4096
    ) -> str:
        """
        Generuje output na podstawie zadania.
        
        Args:
            task: Opis zadania do wykonania
            context: Dodatkowy kontekst/wymagania
            input_content: Istniejąca treść do przerobienia (opcjonalnie)
            temperature: Kreatywność (0.0 - 1.0)
            max_tokens: Max długość odpowiedzi
        
        Returns:
            Wygenerowany output (kod/tekst)
        """
        model = self.model or self._select_model()
        
        # Build user prompt
        if input_content:
            user_prompt = f"""ZADANIE: {task}

KONTEKST/WYMAGANIA:
{context}

ISTNIEJĄCA TREŚĆ DO PRZERÓBKI:
```
{input_content}
```

Przerób/wypełnij zgodnie z zadaniem. Odpowiedz TYLKO gotową treścią."""
        else:
            user_prompt = f"""ZADANIE: {task}

KONTEKST/WYMAGANIA:
{context}

Stwórz rozwiązanie. Odpowiedz TYLKO gotową treścią, bez dodatkowych komentarzy."""

        messages = [
            {"role": "system", "content": self.SYSTEM_PROMPT},
            {"role": "user", "content": user_prompt}
        ]
        
        payload = {
            "messages": messages,
            "temperature": temperature,
            "max_tokens": max_tokens,
            "stream": False
        }
        
        if model:
            payload["model"] = model
        
        try:
            response = self.session.post(
                f"{self.api_url}/chat/completions",
                json=payload,
                timeout=300
            )
            response.raise_for_status()
            data = response.json()
            
            content = data.get("choices", [{}])[0].get("message", {}).get("content", "")
            return content.strip()
            
        except requests.exceptions.ConnectionError:
            raise ConnectionError(
                f"Cannot connect to LM Studio at {self.api_url}. "
                "Make sure LM Studio is running with API enabled."
            )
        except Exception as e:
            raise RuntimeError(f"Generation failed: {e}")
    
    def generate_json(
        self,
        task: str,
        context: str = "",
        input_content: str = "",
        temperature: float = 0.3
    ) -> dict:
        """Generuje output w formacie JSON."""
        json_prompt = task + "\n\nIMPORTANT: Return ONLY valid JSON, no markdown, no comments."
        content = self.generate(json_prompt, context, input_content, temperature)
        
        # Try to extract JSON from markdown code blocks
        if "```json" in content:
            content = content.split("```json")[1].split("```")[0]
        elif "```" in content:
            content = content.split("```")[1].split("```")[0]
        
        try:
            return json.loads(content.strip())
        except json.JSONDecodeError as e:
            raise ValueError(f"Invalid JSON generated: {e}\nContent: {content[:500]}")


def main():
    parser = argparse.ArgumentParser(description="Ralph Wiggum Loop - Generator")
    parser.add_argument("-t", "--task", required=True, help="Task description")
    parser.add_argument("-c", "--context", default="", help="Additional context")
    parser.add_argument("-f", "--file", help="Input file to process")
    parser.add_argument("-o", "--output", help="Output file (default: stdout)")
    parser.add_argument("--json", action="store_true", help="Output as JSON")
    parser.add_argument("--model", help="Model name to use")
    parser.add_argument("--api-url", help="LM Studio API URL")
    parser.add_argument("--temp", type=float, default=0.7, help="Temperature")
    
    args = parser.parse_args()
    
    input_content = ""
    if args.file:
        try:
            with open(args.file, 'r', encoding='utf-8') as f:
                input_content = f.read()
        except Exception as e:
            print(f"Error reading file: {e}", file=sys.stderr)
            sys.exit(1)
    
    gen = Generator(api_url=args.api_url, model=args.model)
    
    try:
        if args.json:
            result = gen.generate_json(
                args.task, args.context, input_content, args.temp
            )
            output = json.dumps(result, indent=2, ensure_ascii=False)
        else:
            result = gen.generate(
                args.task, args.context, input_content, args.temp
            )
            output = result
        
        if args.output:
            with open(args.output, 'w', encoding='utf-8') as f:
                f.write(output)
            print(f"Output saved to {args.output}")
        else:
            print(output)
            
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()


path: scripts/ralph-loop.sh
content: #!/bin/bash
#
# Ralph Wiggum - AI Loop Technique
# Iteracyjny system doskonalenia kodu
#

set -euo pipefail

# Konfiguracja
LMSTUDIO_URL="${LMSTUDIO_URL:-http://127.0.0.1:1234/v1}"
MODEL="${RALPH_MODEL:-qwen3.5-35b-a3b-uncensored-hauhaucs-aggressive}"
MAX_ITERATIONS="${RALPH_MAX_ITER:-3}"
VERBOSE=0
JSON_OUTPUT=0

# Kolory
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Parsowanie argumentów
usage() {
    echo "Użycie: $0 [-f FILE] [-c CODE] [-o FILE] [-p PROMPT] [-i N] [-m MODEL] [-v] [--json]"
    echo ""
    echo "Opcje:"
    echo "  -f FILE      Plik wejściowy z kodem"
    echo "  -c CODE      Kod inline (zamiast pliku)"
    echo "  -o FILE      Plik wyjściowy (domyślnie: stdout)"
    echo "  -p PROMPT    Dodatkowy kontekst/prompt"
    echo "  -i N         Max iteracji (domyślnie: 3)"
    echo "  -m MODEL     Nazwa modelu w LM Studio"
    echo "  -v           Verbose - pokaż proces"
    echo "  --json       Output w formacie JSON"
    echo "  -h           Pomoc"
    exit 1
}

log() {
    if [[ $VERBOSE -ge 1 ]]; then
        echo -e "${BLUE}[RALPH]${NC} $1" >&2
    fi
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1" >&2
}

log_success() {
    echo -e "${GREEN}[OK]${NC} $1" >&2
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1" >&2
}

# Sprawdź czy LM Studio działa
check_lmstudio() {
    if ! curl -s "$LMSTUDIO_URL/models" > /dev/null 2>&1; then
        log_error "LM Studio nie odpowiada na $LMSTUDIO_URL"
        log_error "Upewnij się że LM Studio jest uruchomione z włączonym API"
        exit 1
    fi
    log "LM Studio OK"
}

# Generator - tworzy początkowy output
generate() {
    local task="$1"
    local context="${2:-}"
    
    log "Generator: tworzenie outputu..."
    
    local system_prompt="Jesteś ekspertem programistą. Tworzysz najwyższej jakości kod. Używaj najnowszych praktyk, type hints, docstrings, obsługi błędów."
    
    local user_prompt="$task"
    if [[ -n "$context" ]]; then
        user_prompt="$user_prompt

Kontekst: $context"
    fi
    
    python3 "$(dirname "$0")/generator.py" -u "$LMSTUDIO_URL" -m "$MODEL" -t "$user_prompt" -s "$system_prompt"
}

# Krytyk - analizuje kod i znajduje problemy
criticize() {
    local code="$1"
    
    log "Krytyk: analiza kodu..."
    
    python3 "$(dirname "$0")/critic.py" -u "$LMSTUDIO_URL" -m "$MODEL" -c "$code"
}

# Naprawiacz - poprawia zgłoszone problemy
fix_code() {
    local code="$1"
    local issues="$2"
    
    log "Naprawiacz: poprawianie problemów..."
    
    local prompt="Otrzymałeś kod i listę problemów do naprawy. Napraw KAŻDY problem z listy. Nie dodawaj nowych funkcji - tylko napraw.

KOD:
\`\`\`python
$code
\`\`\`

PROBLEMY DO NAPRAWY:
$issues

Zwróć TYLKO poprawiony kod, bez dodatkowych komentarzy, bez markdown code blocks."

    curl -s "$LMSTUDIO_URL/chat/completions" \
        -H "Content-Type: application/json" \
        -d "{
            \"model\": \"$MODEL\",
            \"messages\": [
                {\"role\": \"system\", \"content\": \"Jesteś ekspertem programistą. Naprawiasz kod. Zwracasz tylko kod, bez wyjaśnień.\"},
                {\"role\": \"user\", \"content\": \"$prompt\"}
            ],
            \"temperature\": 0.2
        }" | jq -r '.choices[0].message.content' 2>/dev/null || echo "$code"
}

# Weryfikator - sprawdza czy poprawki działają
verify() {
    local code="$1"
    local original_issues="$2"
    
    log "Weryfikator: sprawdzanie poprawek..."
    
    # Sprawdź czy kod się kompiluje (dla Python)
    if echo "$code" | python3 -m py_compile - 2>/dev/null; then
        log "✓ Kod się kompiluje"
    else
        log_warn "✗ Błąd kompilacji"
        return 1
    fi
    
    # Sprawdź czy są nowe problemy
    local new_issues
    new_issues=$(criticize "$code")
    
    local issue_count
    issue_count=$(echo "$new_issues" | jq '.issues | length')
    
    if [[ "$issue_count" -eq 0 ]]; then
        log_success "Brak nowych problemów"
        return 0
    else
        log_warn "Znaleziono $issue_count nowych problemów"
        echo "$new_issues"
        return 1
    fi
}

# Główna pętla
main() {
    local input_file=""
    local code_inline=""
    local output_file=""
    local prompt_context=""
    
    # Parsowanie argumentów
    while [[ $# -gt 0 ]]; do
        case $1 in
            -f)
                input_file="$2"
                shift 2
                ;;
            -c)
                code_inline="$2"
                shift 2
                ;;
            -o)
                output_file="$2"
                shift 2
                ;;
            -p)
                prompt_context="$2"
                shift 2
                ;;
            -i)
                MAX_ITERATIONS="$2"
                shift 2
                ;;
            -m)
                MODEL="$2"
                shift 2
                ;;
            -v)
                VERBOSE=1
                shift
                ;;
            -vv)
                VERBOSE=2
                shift
                ;;
            --json)
                JSON_OUTPUT=1
                shift
                ;;
            -h|--help)
                usage
                ;;
            *)
                log_error "Nieznana opcja: $1"
                usage
                ;;
        esac
    done
    
    # Walidacja
    if [[ -z "$input_file" && -z "$code_inline" ]]; then
        log_error "Wymagany -f FILE lub -c CODE"
        usage
    fi
    
    # Sprawdź LM Studio
    check_lmstudio
    
    # Pobierz kod wejściowy
    local input_code
    if [[ -n "$input_file" ]]; then
        input_code=$(cat "$input_file")
        log "Wczytano kod z: $input_file"
    else
        input_code="$code_inline"
        log "Użyto kodu inline"
    fi
    
    # Pętla doskonaląca
    local current_code="$input_code"
    local iteration=0
    local all_issues="[]"
    
    while [[ $iteration -lt $MAX_ITERATIONS ]]; do
        iteration=$((iteration + 1))
        log "=== Iteracja $iteration/$MAX_ITERATIONS ==="
        
        # Krytyk
        local issues
        issues=$(criticize "$current_code")
        local issue_count
        issue_count=$(echo "$issues" | jq '.issues | length')
        
        if [[ "$issue_count" -eq 0 ]]; then
            log_success "Brak problemów do naprawy!"
            break
        fi
        
        log "Znaleziono $issue_count problemów"
        
        # Naprawiacz
        current_code=$(fix_code "$current_code" "$issues")
        
        # Weryfikator
        if verify "$current_code" "$issues"; then
            log_success "Weryfikacja OK"
            break
        else
            log_warn "Wymagana kolejna iteracja"
        fi
    done
    
    # Output
    if [[ $JSON_OUTPUT -eq 1 ]]; then
        local result
        result=$(jq -n \
            --arg code "$current_code" \
            --argjson iterations "$iteration" \
            --arg model "$MODEL" \
            '{code: $code, iterations: $iterations, model: $model}')
        
        if [[ -n "$output_file" ]]; then
            echo "$result" > "$output_file"
            log_success "Zapisano JSON do: $output_file"
        else
            echo "$result"
        fi
    else
        if [[ -n "$output_file" ]]; then
            echo "$current_code" > "$output_file"
            log_success "Zapisano kod do: $output_file"
        else
            echo "$current_code"
        fi
    fi
}

main "$@"

Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)