From f05f4a55161cfedd93ae395068f4f051e739fe64 Mon Sep 17 00:00:00 2001 From: Claude Agent Date: Thu, 1 Jan 2026 21:04:56 +0000 Subject: [PATCH] =?UTF-8?q?Reorganizare=20documenta=C8=9Bie=20=C8=99i=20ad?= =?UTF-8?q?=C4=83ugare=20scripturi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - README.md nou cu documentație completă: concept, workflow-uri, configurare SSH prin Proxmox, Tailscale, troubleshooting - CLAUDE.md simplificat - doar reguli pentru mod non-interactiv - Șters SETUP-COMPLETE.md (conținut mutat în README) - claudep.sh - script pentru task-uri în background cu logging - work.sh - actualizat - .gitignore - adăugat node_modules, Python, IDE, build outputs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .gitignore | 50 +++++ CLAUDE.md | 54 ++--- README.md | 367 ++++++++++++++++++++++++++++++++++ SETUP-COMPLETE.md | 146 -------------- claudep.sh | 255 +++++++++++++++++++++++ work.sh | 500 ++++++++++++++++++++++++++++++++++++++++------ 6 files changed, 1129 insertions(+), 243 deletions(-) create mode 100644 README.md delete mode 100644 SETUP-COMPLETE.md create mode 100755 claudep.sh diff --git a/.gitignore b/.gitignore index 3ed69f7..4df4afc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,57 @@ # Exclude project directories romfastsql/ test/ + +# Claude Code .claude-logs/ +.claude-work/ +.claude/ + +# Node.js +node_modules/ +package-lock.json +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.npm/ +.yarn/ + +# Python +__pycache__/ +*.py[cod] +*$py.class +.Python +*.egg-info/ +.eggs/ +*.egg +.venv/ +venv/ +ENV/ +.env + +# IDE & Editors +.idea/ +.vscode/ +*.swp +*.swo +*~ +.DS_Store + +# Build outputs +dist/ +build/ +*.o +*.so + +# Logs +*.log +logs/ + +# Temporary files +*.tmp +*.temp +.cache/ +tmp/ # Exclude any other project directories that might be added # Keep only workspace-level files (.sh, .md) diff --git a/CLAUDE.md b/CLAUDE.md index 7b35695..c4e52d2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,43 +1,31 @@ -# Claude Agent Workspace +# Instrucțiuni Claude Code -## Informații Agent -- **Hostname:** claude-agent -- **IP:** 10.0.20.171 -- **User:** claude -- **Git remote:** gitea.romfast.ro +## Reguli pentru Mod Non-Interactiv (claudep.sh / claude -p) -## Comenzi Utile +Când ești lansat în mod non-interactiv (pipe mode cu `claude -p`): -### Pornire sesiune agent -```bash -~/start-agent.sh -``` +1. **Director de lucru separat**: Creează un director temporar pentru fișierele de lucru: + ``` + /workspace/.claude-work/_/ + ``` + Exemplu: `/workspace/.claude-work/20240115_143022_api-research/` -### Verificare tmux sessions -```bash -tmux ls -``` +2. **NU crea fișiere direct în /workspace**: Orice fișier temporar, note, output sau rezultate trebuie să fie în directorul de lucru separat. -### Pornire Claude Code în proiect -```bash -cd /workspace/ -claude -``` +3. **Structura recomandată**: + ``` + /workspace/.claude-work// + ├── output/ # Rezultate finale + ├── temp/ # Fișiere temporare + └── notes.md # Note și concluzii + ``` -## Workflow Recomandat +4. **La final**: Dacă sunt fișiere finale relevante pentru utilizator, menționează locația lor în output. -1. Conectează-te via SSH: `ssh claude@10.0.20.171` -2. Pornește sesiunea tmux: `~/start-agent.sh` -3. Navighează în proiect: `cd /workspace/` -4. Pornește Claude: `claude` +5. **Excepție**: Modificările la fișiere existente din proiecte (cod, configurații) se fac normal, în locația lor originală. -## Git - Gitea -Repository-urile se clonează cu: -```bash -git clone git@gitea.romfast.ro:romfast/.git -``` +## Note Generale -## Note -- Această mașină este configurată pentru dezvoltare cu Claude Code - Toate proiectele ar trebui să fie în /workspace -- tmux prefix este Ctrl+A (nu Ctrl+B) +- Git remote: gitea.romfast.ro +- Vezi README.md pentru detalii despre sistem și comenzi diff --git a/README.md b/README.md new file mode 100644 index 0000000..ff76390 --- /dev/null +++ b/README.md @@ -0,0 +1,367 @@ +# Claude Agent - Cloud Development Environment + +Container LXC configurat pentru **rularea Claude Code în cloud cu sesiuni permanente tmux**. + +## Concept + +Acest sistem permite: +1. **Lansezi o sarcină pentru Claude** (interactiv sau cu `claudep.sh`) +2. **Claude lucrează în tmux** - sesiunea persistă chiar dacă te deconectezi +3. **Te reconectezi oricând** - de pe laptop, telefon, alt calculator +4. **Vezi ce a făcut Claude** - revizuiești codul, testezi, dai feedback +5. **Push în Gitea** - când ești mulțumit cu rezultatul + +Poți lansa un task dimineața, Claude lucrează toată ziua, iar seara te conectezi de pe alt calculator să vezi progresul. + +## Informații Sistem + +| Parametru | Valoare | +|-----------|---------| +| VMID | 171 | +| Hostname | claude-agent | +| IP LAN | 10.0.20.171 | +| IP Tailscale | claude-agent (sau 100.95.55.51) | +| Gateway | 10.0.20.1 | +| Host Proxmox | pveelite (10.0.20.202) | +| User | claude | +| Storage | local-zfs (32GB) | +| RAM | 4GB | +| CPU | 2 cores | + +**Data setup:** 2025-12-31 + +## Componente Instalate + +| Component | Versiune | +|-----------|----------| +| Ubuntu | 24.04 LTS | +| Node.js | v20.19.6 (via nvm) | +| Claude Code | 2.0.76 | +| tmux | 3.4 | +| Git | 2.43.0 | + +--- + +## Conectare SSH + +Poți te conecta în două moduri: + +```bash +# Din rețeaua locală +ssh claude@10.0.20.171 + +# Prin Tailscale (de oriunde) +ssh claude@claude-agent +``` + +**Notă:** Nu există parolă setată pentru userul `claude`. Accesul se face doar cu SSH key. +Vezi secțiunea "Configurare Acces SSH" pentru instalarea cheii. + +--- + +## Workflow Principal + +### Varianta 1: Sesiune Interactivă + +```bash +# 1. Conectare SSH (LAN sau Tailscale) +ssh claude@10.0.20.171 # sau +ssh claude@claude-agent # prin Tailscale + +# 2. Pornire/reatașare sesiune tmux (automat) +~/start-agent.sh + +# 3. Navighează în proiect și pornește Claude +cd /workspace/ +claude + +# 4. Lucrezi cu Claude interactiv... + +# 5. Când vrei să pleci - detașare din tmux (sesiunea rămâne activă) +Ctrl+A, d + +# 6. Mai târziu - reconectare la sesiune (start-agent.sh reatașează automat) +ssh claude@claude-agent +~/start-agent.sh +``` + +### Varianta 2: Task în Background + +Două scripturi disponibile: + +**`work.sh`** - Te întreabă interactiv ce proiect și ce task: +```bash +ssh claude@claude-agent +/workspace/work.sh +# Răspunzi la întrebări despre proiect și task +``` + +**`claudep.sh`** - Rulează în directorul curent, creează fișiere independent: +```bash +ssh claude@claude-agent +cd /workspace/ # Navighează în proiect +/workspace/claudep.sh "Implementează autentificare JWT" + +# SAU din /workspace (fișierele se creează în .claude-work/) +cd /workspace +/workspace/claudep.sh "Cercetează cele mai bune practici pentru API design" +``` + +**Monitorizare și rezultate:** +```bash +# Urmărește progresul în timp real +tail -f /workspace/.claude-logs/claude_*_progress.log + +# Vezi rezultatele finale +cat /workspace/.claude-logs/claude_*_progress.log +``` + +### Varianta 3: VS Code Remote + +Cea mai convenabilă metodă pentru lucru prelungit - editezi cod, vezi terminal, totul într-un singur loc. + +1. **Configurează accesul SSH** (vezi secțiunea de mai jos) +2. **Instalează extensia** "Remote - SSH" în VS Code +3. **Conectare:** `Ctrl+Shift+P` → `Remote-SSH: Connect to Host...` → `claude-agent` +4. **Deschide terminal** în VS Code (`Ctrl+``) +5. **Atașează la sesiunea Claude:** `~/start-agent.sh` +6. **Lucrezi** - editezi fișiere în VS Code, interacționezi cu Claude în terminal + +--- + +## Configurare Acces SSH (Prima dată) + +**Problema:** Nu există parolă setată pentru userul `claude` în LXC. Accesul se face prin SSH key. + +### Pas 1: Generează SSH key pe calculatorul tău (dacă nu ai) + +```bash +# Pe calculatorul tău (Windows PowerShell, Mac/Linux Terminal) +ssh-keygen -t ed25519 -C "your-email@example.com" + +# Afișează cheia publică +cat ~/.ssh/id_ed25519.pub +# SAU pe Windows: +type %USERPROFILE%\.ssh\id_ed25519.pub +``` + +Copiază cheia publică (linia care începe cu `ssh-ed25519 ...`). + +### Pas 2: Adaugă cheia în LXC prin Proxmox + +Conectează-te la host-ul Proxmox și adaugă cheia în container: + +```bash +# 1. SSH pe Proxmox host +ssh root@10.0.20.202 # pveelite + +# 2. Intră în containerul LXC (VMID 171) +pct enter 171 + +# 3. Adaugă cheia publică SSH +echo "ssh-ed25519 AAAA...cheia_ta_aici... your-email@example.com" >> /home/claude/.ssh/authorized_keys + +# 4. Verifică permisiunile (ar trebui să fie deja corecte) +chown claude:claude /home/claude/.ssh/authorized_keys +chmod 600 /home/claude/.ssh/authorized_keys + +# 5. Ieși din container +exit + +# 6. Ieși din Proxmox +exit +``` + +**Alternativ** (fără a intra în container): +```bash +# De pe Proxmox host, într-o singură comandă: +ssh root@10.0.20.202 + +pct exec 171 -- bash -c 'echo "ssh-ed25519 AAAA...cheia_ta... email" >> /home/claude/.ssh/authorized_keys' +``` + +### Pas 3: Configurează SSH pe calculatorul tău + +Adaugă în `~/.ssh/config` (sau `%USERPROFILE%\.ssh\config` pe Windows): + +``` +# Acces prin Tailscale (recomandat - funcționează de oriunde) +Host claude-agent + HostName claude-agent + User claude + IdentityFile ~/.ssh/id_ed25519 + ForwardAgent yes + +# Acces prin LAN (doar din rețeaua locală) +Host claude-agent-lan + HostName 10.0.20.171 + User claude + IdentityFile ~/.ssh/id_ed25519 + ForwardAgent yes +``` + +### Pas 4: Testează conexiunea + +```bash +ssh claude@claude-agent +# Ar trebui să te conectezi fără parolă +``` + +--- + +## Comenzi Utile + +### tmux (Sesiuni Permanente) +```bash +~/start-agent.sh # Pornește SAU reatașează sesiune "agent" (automat) +tmux ls # Lista sesiuni active +tmux new -s # Sesiune nouă cu alt nume +Ctrl+A, d # Detașare (sesiunea continuă în background) +Ctrl+A, c # Fereastră nouă în sesiune +Ctrl+A, n # Fereastră următoare +Ctrl+A, p # Fereastră anterioară +Ctrl+A, [ # Mod scroll (q pentru ieșire) +``` + +**Notă:** Prefix-ul tmux este `Ctrl+A` (nu `Ctrl+B` ca default). + +### Claude Code +```bash +claude # Pornire interactivă +claude -p "prompt" # Mod non-interactiv (pipe mode) +``` + +### Git - Gitea +```bash +git clone git@gitea.romfast.ro:romfast/.git +git push origin main +ssh -T git@gitea.romfast.ro # Test conexiune SSH +``` + +--- + +## SSH Key pentru Gitea + +Această cheie este deja generată pe server. Trebuie adăugată în Gitea: + +1. Mergi la https://gitea.romfast.ro +2. Settings → SSH/GPG Keys → Add Key +3. Paste: +``` +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKrxEqh5L1SRrZ4f6j04mLaNdr6LJf+xb9EKBvwegeXS claude-agent@romfast.ro +``` + +--- + +## Structura Directoare + +``` +/home/claude/ +├── .ssh/ +│ ├── authorized_keys # Chei SSH pentru acces (adaugă cheia ta aici) +│ ├── gitea_ed25519 # Key privat pentru Gitea +│ ├── gitea_ed25519.pub # Key public pentru Gitea +│ └── config # SSH config pentru Gitea +├── .nvm/ # Node Version Manager +├── .claude/ +│ └── settings.json # Claude Code permissions +├── .tmux.conf # Configurare tmux (prefix Ctrl+A) +└── start-agent.sh # Script helper - pornește/reatașează tmux + +/workspace/ # Director pentru proiecte +├── CLAUDE.md # Instrucțiuni pentru Claude Code +├── README.md # Acest fișier +├── claudep.sh # Task în background (directorul curent) +├── work.sh # Task interactiv (întreabă proiectul) +├── .claude-work/ # Fișiere temporare create de claude -p +├── .claude-logs/ # Log-uri pentru task-uri în background +└── / # Proiectele tale (clone din Gitea) +``` + +--- + +## Scripturi Disponibile + +| Script | Descriere | +|--------|-----------| +| `~/start-agent.sh` | Pornește sesiune tmux "agent" sau reatașează dacă există | +| `/workspace/work.sh` | Lansează task - te întreabă interactiv proiectul și descrierea | +| `/workspace/claudep.sh` | Lansează task în directorul curent, cu logging | + +--- + +## Troubleshooting + +### Nu mă pot conecta SSH (Permission denied) +```bash +# Verifică dacă ai cheia SSH instalată +ssh -v claude@claude-agent + +# Dacă nu ai acces, trebuie să adaugi cheia prin Proxmox: +ssh root@10.0.20.202 +pct enter 171 +# ... vezi secțiunea "Configurare Acces SSH" +``` + +### Claude Code nu pornește +```bash +source ~/.nvm/nvm.sh # Încarcă Node.js +which claude # Verifică dacă e în PATH +claude --version # Test +``` + +### tmux - sesiunea nu există +```bash +tmux ls # Vezi ce sesiuni există +~/start-agent.sh # Creează/reatașează sesiune "agent" +``` + +### Git clone eșuează +```bash +ssh -T git@gitea.romfast.ro # Test conexiune +# Dacă eșuează: verifică că ai adăugat SSH key în Gitea (vezi secțiunea dedicată) +``` + +### Claude pare blocat / nu răspunde +```bash +# În tmux, verifică dacă Claude așteaptă input +# Dacă da, răspunde sau Ctrl+C pentru a opri + +# Pentru task-uri în background, verifică log-ul: +tail -f /workspace/.claude-logs/claude_*_progress.log +``` + +### Tailscale nu rezolvă hostname-ul +```bash +# Folosește IP-ul Tailscale direct +tailscale ip claude-agent # Pe alt device din Tailscale +ssh claude@ + +# Sau folosește IP-ul LAN dacă ești în rețeaua locală +ssh claude@10.0.20.171 +``` + +--- + +## Quick Reference + +```bash +# Conectare și pornire sesiune (Tailscale) +ssh claude@claude-agent && ~/start-agent.sh + +# Conectare și pornire sesiune (LAN) +ssh claude@10.0.20.171 && ~/start-agent.sh + +# Lansare task interactiv (te întreabă proiectul) +ssh claude@claude-agent -t "/workspace/work.sh" + +# Lansare task în background pentru un proiect +ssh claude@claude-agent -t "cd /workspace/ && /workspace/claudep.sh 'descriere task'" + +# Verificare log-uri +ssh claude@claude-agent "tail -50 /workspace/.claude-logs/claude_*_progress.log" +``` + +--- + +*Setup realizat cu Claude Code* diff --git a/SETUP-COMPLETE.md b/SETUP-COMPLETE.md deleted file mode 100644 index 3eebe6f..0000000 --- a/SETUP-COMPLETE.md +++ /dev/null @@ -1,146 +0,0 @@ -# LXC Claude Agent - Setup Complete ✓ - -**Data setup:** 2025-12-31 -**Status:** Functional - -## Informații LXC - -| Parametru | Valoare | -|-----------|---------| -| VMID | 171 | -| Hostname | claude-agent | -| IP | 10.0.20.171 | -| Gateway | 10.0.20.1 | -| Host Proxmox | pveelite (10.0.20.202) | -| User | claude | -| Storage | local-zfs (32GB) | -| RAM | 4GB | -| CPU | 2 cores | - -## Componente Instalate - -| Component | Versiune | -|-----------|----------| -| Ubuntu | 24.04 LTS | -| Node.js | v20.19.6 (via nvm) | -| Claude Code | 2.0.76 | -| tmux | 3.4 | -| Git | 2.43.0 | - -## Comenzi Utile - -### Conectare SSH -```bash -ssh claude@10.0.20.171 -``` - -### Pornire sesiune tmux agent -```bash -~/start-agent.sh -``` - -### Pornire Claude Code -```bash -source ~/.nvm/nvm.sh -cd /workspace/ -claude -``` - -### Atașare la sesiune tmux existentă -```bash -tmux attach -t agent -``` - -### Detașare din tmux -``` -Ctrl+A, d -``` - -## VS Code Remote SSH Config - -Adaugă în `~/.ssh/config`: -``` -Host claude-agent - HostName 10.0.20.171 - User claude - IdentityFile ~/.ssh/id_rsa - ForwardAgent yes -``` - -Apoi în VS Code: `Remote-SSH: Connect to Host...` → `claude-agent` - -## SSH Key pentru Gitea - -**Adaugă acest key în Gitea → Settings → SSH/GPG Keys → Add Key:** - -``` -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKrxEqh5L1SRrZ4f6j04mLaNdr6LJf+xb9EKBvwegeXS claude-agent@romfast.ro -``` - -## Next Steps (Manual) - -1. **Adaugă SSH key în Gitea:** - - Mergi la https://gitea.romfast.ro - - Settings → SSH/GPG Keys → Add Key - - Paste-uiește cheia de mai sus - -2. **Prima autentificare Claude Code:** - ```bash - ssh claude@10.0.20.171 - source ~/.nvm/nvm.sh - claude - ``` - - Va cere să te autentifici cu contul Anthropic - - Urmează instrucțiunile din terminal - -3. **Test clonare repository:** - ```bash - cd /workspace - git clone git@gitea.romfast.ro:romfast/romfastsql.git - ``` - -4. **Configurare VS Code Remote (opțional):** - - Instalează extensia "Remote - SSH" în VS Code - - Adaugă configurația SSH de mai sus - - Conectează-te la claude-agent - -## Structura Directoare - -``` -/home/claude/ -├── .ssh/ -│ ├── authorized_keys # Key pentru acces SSH -│ ├── gitea_ed25519 # Key privat pentru Gitea -│ ├── gitea_ed25519.pub # Key public pentru Gitea -│ └── config # SSH config pentru Gitea -├── .nvm/ # Node Version Manager -├── .claude/ -│ └── settings.json # Claude Code permissions -├── .tmux.conf # Configurare tmux -└── start-agent.sh # Script helper tmux - -/workspace/ # Director pentru proiecte -├── CLAUDE.md # Template info agent -└── SETUP-COMPLETE.md # Acest fișier -``` - -## Troubleshooting - -### Claude Code nu pornește -```bash -source ~/.nvm/nvm.sh -which claude -``` - -### tmux nu găsește sesiunea -```bash -tmux ls -tmux new -s agent -``` - -### Git clone eșuează -- Verifică dacă ai adăugat SSH key-ul în Gitea -- Testează cu: `ssh -T git@gitea.romfast.ro` - ---- -*Setup realizat automat cu Claude Code* diff --git a/claudep.sh b/claudep.sh new file mode 100755 index 0000000..d06c77b --- /dev/null +++ b/claudep.sh @@ -0,0 +1,255 @@ +#!/bin/bash +# ============================================================================ +# claudep.sh - Claude Prompt (Non-Interactive Background Execution) +# ============================================================================ +# Utilizare: +# claudep.sh "promptul tău aici" +# claudep.sh # fără argument, te întreabă pentru prompt +# ============================================================================ + +set -e + +WORKSPACE="/workspace" +LOG_DIR="/workspace/.claude-logs" + +# Inițializare NVM pentru Node +[ -f ~/.nvm/nvm.sh ] && source ~/.nvm/nvm.sh + +# Culori pentru output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +MAGENTA='\033[0;35m' +NC='\033[0m' # No Color +BOLD='\033[1m' + +# ============================================================================ +# Funcții utilitare +# ============================================================================ + +print_header() { + echo -e "\n${BOLD}${BLUE}═══════════════════════════════════════════════════════════════${NC}" + echo -e "${BOLD}${CYAN} $1${NC}" + echo -e "${BOLD}${BLUE}═══════════════════════════════════════════════════════════════${NC}\n" +} + +print_success() { + echo -e "${GREEN}✓ $1${NC}" +} + +print_error() { + echo -e "${RED}✗ $1${NC}" +} + +print_info() { + echo -e "${YELLOW}ℹ $1${NC}" +} + +# ============================================================================ +# Obține promptul +# ============================================================================ + +get_prompt() { + if [ -n "$1" ]; then + TASK_PROMPT="$1" + else + echo -e "${CYAN}Descrie ce vrei să facă Claude:${NC}" + echo "" + read -p "> " TASK_PROMPT + + if [ -z "$TASK_PROMPT" ]; then + print_error "Trebuie să dai o descriere" + exit 1 + fi + + # Întreabă dacă vrea să adauge mai multe detalii + echo "" + read -p "Detalii adiționale (sau Enter pentru a continua): " extra + if [ -n "$extra" ]; then + TASK_PROMPT="$TASK_PROMPT. $extra" + fi + fi +} + +# ============================================================================ +# Rulează Claude în background cu log procesat +# ============================================================================ + +run_claude_background() { + local work_dir="$1" + local prompt="$2" + + # Generează nume pentru log bazat pe timestamp + local timestamp=$(date +%Y%m%d_%H%M%S) + local log_file="$LOG_DIR/claude_${timestamp}.log" + local processed_log="$LOG_DIR/claude_${timestamp}_progress.log" + local pid_file="$LOG_DIR/claude_${timestamp}.pid" + + mkdir -p "$LOG_DIR" + + echo -e "${CYAN}Director:${NC} $work_dir" + echo -e "${CYAN}Prompt:${NC} $prompt" + echo "" + + # Salvează prompt-ul într-un fișier temporar + local prompt_file=$(mktemp) + echo "$prompt" > "$prompt_file" + + # Inițializează log-ul procesat + { + echo "═══════════════════════════════════════════════════════════════" + echo " Claude Code - Task Background" + echo "═══════════════════════════════════════════════════════════════" + echo "Start: $(date '+%Y-%m-%d %H:%M:%S')" + echo "Director: $work_dir" + echo "Prompt: $prompt" + echo "PID File: $pid_file" + echo "═══════════════════════════════════════════════════════════════" + echo "" + } > "$processed_log" + + # Rulează Claude în background cu procesare a log-ului + ( + # Salvează PID-ul subshell-ului + echo "$$" > "$pid_file" + + cd "$work_dir" + local start_time=$(date +%s) + + claude -p "$(cat "$prompt_file")" \ + --output-format stream-json \ + --verbose \ + --allowedTools "Bash(git:*),Bash(npm:*),Bash(node:*),Bash(python3:*),Bash(pip3:*),Bash(pip:*),Bash(ls:*),Bash(cat:*),Bash(mkdir:*),Bash(rm:*),Bash(cp:*),Bash(mv:*),Bash(chmod:*),Bash(touch:*),Bash(find:*),Bash(grep:*),Bash(head:*),Bash(tail:*),Bash(wc:*),Bash(which:*),Bash(stat:*),Bash(file:*),Bash(pgrep:*),Bash(kill:*),Read,Write,Edit,Glob,Grep,WebSearch,WebFetch,Task,Skill,TodoWrite,LSP" \ + --max-turns 50 2>&1 | while IFS= read -r line; do + + # Parsează JSON și extrage informații relevante + if echo "$line" | jq -e . >/dev/null 2>&1; then + msg_type=$(echo "$line" | jq -r '.type // empty' 2>/dev/null) + timestamp=$(date '+%H:%M:%S') + + case "$msg_type" in + "system") + subtype=$(echo "$line" | jq -r '.subtype // empty' 2>/dev/null) + if [ "$subtype" = "init" ]; then + echo "[$timestamp] ▶ Sesiune Claude pornită" >> "$processed_log" + fi + ;; + "assistant") + # Verifică pentru tool_use - extrage detalii complete + tool_info=$(echo "$line" | jq -r ' + .message.content[]? | select(.type == "tool_use") | + {name: .name, input: .input} | + if .name == "WebFetch" then "WebFetch: \(.input.url // "?") | \(.input.prompt // "" | .[0:50])" + elif .name == "WebSearch" then "WebSearch: \(.input.query // "?")" + elif .name == "Bash" then "Bash: \(.input.command // "" | .[0:100])" + elif .name == "Read" then "Read: \(.input.file_path // "?")" + elif .name == "Write" then "Write: \(.input.file_path // "?")" + elif .name == "Edit" then "Edit: \(.input.file_path // "?")" + elif .name == "Grep" then "Grep: \(.input.pattern // "?") in \(.input.path // ".")" + elif .name == "Glob" then "Glob: \(.input.pattern // "?")" + elif .name == "Task" then "Task: \(.input.description // "?") [\(.input.subagent_type // "?")]" + elif .name == "Skill" then "Skill: \(.input.skill // "?")" + else "\(.name): \(.input | tostring | .[0:80])" + end + ' 2>/dev/null | head -1) + if [ -n "$tool_info" ]; then + echo "[$timestamp] ⚙ $tool_info" >> "$processed_log" + fi + + # Text output + content=$(echo "$line" | jq -r '.message.content[]? | select(.type == "text") | .text // empty' 2>/dev/null | head -c 300) + if [ -n "$content" ]; then + echo "[$timestamp] 💬 $content" >> "$processed_log" + fi + ;; + "user") + # Tool result - extrage detalii despre eroare sau rezumat + tool_result=$(echo "$line" | jq -r ' + .message.content[]? | select(.type == "tool_result") | + if .is_error == true then + "✗ EROARE: \(.content // "" | .[0:150])" + else + "✓ OK" + end + ' 2>/dev/null | head -1) + if [ -n "$tool_result" ]; then + echo "[$timestamp] $tool_result" >> "$processed_log" + else + # Fallback pentru alte formate de rezultat + is_error=$(echo "$line" | jq -r '.message.content[]?.is_error // false' 2>/dev/null | head -1) + if [ "$is_error" = "true" ]; then + err_content=$(echo "$line" | jq -r '.message.content[]?.content // "" | .[0:150]' 2>/dev/null | head -1) + echo "[$timestamp] ✗ EROARE: $err_content" >> "$processed_log" + else + echo "[$timestamp] ✓ OK" >> "$processed_log" + fi + fi + ;; + "result") + result_text=$(echo "$line" | jq -r '.result // empty' 2>/dev/null | head -c 500) + echo "" >> "$processed_log" + echo "[$timestamp] ════════════════════════════════════════════" >> "$processed_log" + echo "[$timestamp] ✅ TASK FINALIZAT" >> "$processed_log" + echo "[$timestamp] ════════════════════════════════════════════" >> "$processed_log" + echo "" >> "$processed_log" + echo "Rezultat:" >> "$processed_log" + echo "$result_text" >> "$processed_log" + ;; + esac + fi + done + + local exit_code=${PIPESTATUS[0]} + local end_time=$(date +%s) + local duration=$((end_time - start_time)) + + echo "" >> "$processed_log" + echo "═══════════════════════════════════════════════════════════════" >> "$processed_log" + echo "End: $(date '+%Y-%m-%d %H:%M:%S')" >> "$processed_log" + echo "Durată: ${duration}s" >> "$processed_log" + echo "Exit code: $exit_code" >> "$processed_log" + echo "═══════════════════════════════════════════════════════════════" >> "$processed_log" + + rm -f "$prompt_file" + rm -f "$pid_file" + ) & + + local bg_pid=$! + # Salvează și PID-ul procesului părinte pentru referință + echo "$bg_pid" > "$pid_file" + + echo -e "${BOLD}${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${BOLD}${BLUE}║${NC} ${GREEN}Claude rulează în background${NC} ${BOLD}${BLUE}║${NC}" + echo -e "${BOLD}${BLUE}╚════════════════════════════════════════════════════════════════╝${NC}" + echo "" + echo -e "${CYAN}PID:${NC} $bg_pid" + echo -e "${CYAN}Log progres:${NC} $processed_log" + echo "" + echo -e "${YELLOW}Comenzi utile:${NC}" + echo -e " ${BOLD}tail -f $processed_log${NC}" + echo "" +} + +# ============================================================================ +# Main +# ============================================================================ + +main() { + print_header "Claude Prompt (Background)" + + # Detectează directorul curent ca working directory + WORK_DIR=$(pwd) + + # Obține promptul din argument sau interactiv + get_prompt "$1" + + # Rulează Claude în background + run_claude_background "$WORK_DIR" "$TASK_PROMPT" + + print_success "Task lansat! Folosește tail -f pentru a urmări progresul." +} + +# Rulează main cu toate argumentele +main "$*" diff --git a/work.sh b/work.sh index 673fbe1..b2a450e 100755 --- a/work.sh +++ b/work.sh @@ -102,8 +102,8 @@ select_work_mode() { echo -e " ${BOLD}1)${NC} ${GREEN}Feature nou${NC} ${CYAN}(worktree separat)${NC}" echo -e " └─ Creează branch + worktree izolat pentru dezvoltare" echo "" - echo -e " ${BOLD}2)${NC} ${YELLOW}Task temporar${NC} ${CYAN}(fără worktree)${NC}" - echo -e " └─ Documente, analiză, rezultate temporare" + echo -e " ${BOLD}2)${NC} ${YELLOW}Task temporar${NC} ${CYAN}(background, fără worktree)${NC}" + echo -e " └─ Rulează în background, revine la meniu" echo "" echo -e " ${BOLD}3)${NC} ${BLUE}Mod interactiv${NC} ${CYAN}(claude normal)${NC}" echo -e " └─ Pornește Claude interactiv pe branch-ul curent" @@ -111,14 +111,27 @@ select_work_mode() { echo -e " ${BOLD}4)${NC} ${MAGENTA}Gestionare worktrees${NC}" echo -e " └─ Vezi, șterge worktrees existente" echo "" + echo -e " ${BOLD}5)${NC} ${CYAN}Vezi task-uri active${NC}" + echo -e " └─ Log-uri recente și procese Claude active" + echo "" + echo -e " ${BOLD}b)${NC} Înapoi la selectare proiect" + echo -e " ${BOLD}q)${NC} ${RED}Ieșire${NC}" + echo "" - read -p "Alege mod [1-4]: " mode_choice + read -p "Alege mod [1-5/b/q]: " mode_choice case $mode_choice in 1) WORK_MODE="feature" ;; 2) WORK_MODE="temp" ;; 3) WORK_MODE="interactive" ;; 4) WORK_MODE="manage" ;; + 5) WORK_MODE="status" ;; + b|B) WORK_MODE="back" ;; + q|Q) + echo "" + print_info "La revedere!" + exit 0 + ;; *) print_error "Opțiune invalidă" exit 1 @@ -221,7 +234,170 @@ create_worktree() { } # ============================================================================ -# Rulează Claude cu monitorizare progres +# Rulează Claude în background cu log procesat +# ============================================================================ + +run_claude_background() { + local work_dir="$1" + local prompt="$2" + local log_file="$3" + + # Log procesat (mesaje utile, nu JSON brut) + local processed_log="${log_file%.log}_progress.log" + # Fișier PID pentru tracking + local pid_file="${log_file%.log}.pid" + + mkdir -p "$LOG_DIR" + + print_section "Lansare Claude în background" + echo -e "${CYAN}Director:${NC} $work_dir" + echo -e "${CYAN}Prompt:${NC} $prompt" + echo "" + + # Salvează prompt-ul într-un fișier temporar + local prompt_file=$(mktemp) + echo "$prompt" > "$prompt_file" + + # Inițializează log-ul procesat + { + echo "═══════════════════════════════════════════════════════════════" + echo " Claude Code - Task Background" + echo "═══════════════════════════════════════════════════════════════" + echo "Start: $(date '+%Y-%m-%d %H:%M:%S')" + echo "Director: $work_dir" + echo "Prompt: $prompt" + echo "PID File: $pid_file" + echo "═══════════════════════════════════════════════════════════════" + echo "" + } > "$processed_log" + + # Rulează Claude în background cu procesare a log-ului + ( + # Salvează PID-ul subshell-ului + echo "$$" > "$pid_file" + + cd "$work_dir" + local start_time=$(date +%s) + + claude -p "$(cat "$prompt_file")" \ + --output-format stream-json \ + --verbose \ + --allowedTools "Bash(git:*),Bash(npm:*),Bash(node:*),Bash(python3:*),Bash(pip3:*),Bash(pip:*),Bash(ls:*),Bash(cat:*),Bash(mkdir:*),Bash(rm:*),Bash(cp:*),Bash(mv:*),Bash(chmod:*),Bash(touch:*),Bash(find:*),Bash(grep:*),Bash(head:*),Bash(tail:*),Bash(wc:*),Bash(which:*),Bash(stat:*),Bash(file:*),Bash(pgrep:*),Bash(kill:*),Read,Write,Edit,Glob,Grep,WebSearch,WebFetch,Task,Skill,TodoWrite,LSP" \ + --max-turns 50 2>&1 | while IFS= read -r line; do + + # Parsează JSON și extrage informații relevante + if echo "$line" | jq -e . >/dev/null 2>&1; then + msg_type=$(echo "$line" | jq -r '.type // empty' 2>/dev/null) + timestamp=$(date '+%H:%M:%S') + + case "$msg_type" in + "system") + subtype=$(echo "$line" | jq -r '.subtype // empty' 2>/dev/null) + if [ "$subtype" = "init" ]; then + echo "[$timestamp] ▶ Sesiune Claude pornită" >> "$processed_log" + fi + ;; + "assistant") + # Verifică pentru tool_use - extrage detalii complete + tool_info=$(echo "$line" | jq -r ' + .message.content[]? | select(.type == "tool_use") | + {name: .name, input: .input} | + if .name == "WebFetch" then "WebFetch: \(.input.url // "?") | \(.input.prompt // "" | .[0:50])" + elif .name == "WebSearch" then "WebSearch: \(.input.query // "?")" + elif .name == "Bash" then "Bash: \(.input.command // "" | .[0:100])" + elif .name == "Read" then "Read: \(.input.file_path // "?")" + elif .name == "Write" then "Write: \(.input.file_path // "?")" + elif .name == "Edit" then "Edit: \(.input.file_path // "?")" + elif .name == "Grep" then "Grep: \(.input.pattern // "?") in \(.input.path // ".")" + elif .name == "Glob" then "Glob: \(.input.pattern // "?")" + elif .name == "Task" then "Task: \(.input.description // "?") [\(.input.subagent_type // "?")]" + elif .name == "Skill" then "Skill: \(.input.skill // "?")" + else "\(.name): \(.input | tostring | .[0:80])" + end + ' 2>/dev/null | head -1) + if [ -n "$tool_info" ]; then + echo "[$timestamp] ⚙ $tool_info" >> "$processed_log" + fi + + # Text output + content=$(echo "$line" | jq -r '.message.content[]? | select(.type == "text") | .text // empty' 2>/dev/null | head -c 300) + if [ -n "$content" ]; then + echo "[$timestamp] 💬 $content" >> "$processed_log" + fi + ;; + "user") + # Tool result - extrage detalii despre eroare sau rezumat + tool_result=$(echo "$line" | jq -r ' + .message.content[]? | select(.type == "tool_result") | + if .is_error == true then + "✗ EROARE: \(.content // "" | .[0:150])" + else + "✓ OK" + end + ' 2>/dev/null | head -1) + if [ -n "$tool_result" ]; then + echo "[$timestamp] $tool_result" >> "$processed_log" + else + # Fallback pentru alte formate de rezultat + is_error=$(echo "$line" | jq -r '.message.content[]?.is_error // false' 2>/dev/null | head -1) + if [ "$is_error" = "true" ]; then + err_content=$(echo "$line" | jq -r '.message.content[]?.content // "" | .[0:150]' 2>/dev/null | head -1) + echo "[$timestamp] ✗ EROARE: $err_content" >> "$processed_log" + else + echo "[$timestamp] ✓ OK" >> "$processed_log" + fi + fi + ;; + "result") + result_text=$(echo "$line" | jq -r '.result // empty' 2>/dev/null | head -c 500) + echo "" >> "$processed_log" + echo "[$timestamp] ════════════════════════════════════════════" >> "$processed_log" + echo "[$timestamp] ✅ TASK FINALIZAT" >> "$processed_log" + echo "[$timestamp] ════════════════════════════════════════════" >> "$processed_log" + echo "" >> "$processed_log" + echo "Rezultat:" >> "$processed_log" + echo "$result_text" >> "$processed_log" + ;; + esac + fi + done + + local exit_code=${PIPESTATUS[0]} + local end_time=$(date +%s) + local duration=$((end_time - start_time)) + + echo "" >> "$processed_log" + echo "═══════════════════════════════════════════════════════════════" >> "$processed_log" + echo "End: $(date '+%Y-%m-%d %H:%M:%S')" >> "$processed_log" + echo "Durată: ${duration}s" >> "$processed_log" + echo "Exit code: $exit_code" >> "$processed_log" + echo "═══════════════════════════════════════════════════════════════" >> "$processed_log" + + rm -f "$prompt_file" + rm -f "$pid_file" + ) & + + local bg_pid=$! + # Salvează și PID-ul procesului părinte pentru referință + echo "$bg_pid" > "$pid_file" + + echo -e "${BOLD}${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${BOLD}${BLUE}║${NC} ${GREEN}Claude rulează în background${NC} ${BOLD}${BLUE}║${NC}" + echo -e "${BOLD}${BLUE}╚════════════════════════════════════════════════════════════════╝${NC}" + echo "" + echo -e "${CYAN}PID:${NC} $bg_pid" + echo -e "${CYAN}Log progres:${NC} $processed_log" + echo "" + echo -e "${YELLOW}Comenzi utile:${NC}" + echo -e " ${BOLD}tail -f $processed_log${NC} # Urmărește progresul" + echo -e " ${BOLD}ps aux | grep $bg_pid${NC} # Verifică dacă rulează" + echo "" + print_success "Revenire la meniu..." + sleep 2 +} + +# ============================================================================ +# Rulează Claude cu monitorizare progres (pentru mod feature - sincron) # ============================================================================ run_claude_with_progress() { @@ -229,11 +405,14 @@ run_claude_with_progress() { local prompt="$2" local log_file="$3" + # Log procesat (mesaje utile, nu JSON brut) + local processed_log="${log_file%.log}_progress.log" + cd "$work_dir" print_section "Lansare Claude" echo -e "${CYAN}Director:${NC} $work_dir" - echo -e "${CYAN}Log:${NC} $log_file" + echo -e "${CYAN}Log progres:${NC} $processed_log" echo -e "${CYAN}Prompt:${NC} $prompt" echo "" @@ -248,54 +427,114 @@ run_claude_with_progress() { echo -e "${BOLD}${BLUE}╚════════════════════════════════════════════════════════════════╝${NC}" echo "" + # Inițializează log-ul procesat + { + echo "═══════════════════════════════════════════════════════════════" + echo " Claude Code - Task" + echo "═══════════════════════════════════════════════════════════════" + echo "Start: $(date '+%Y-%m-%d %H:%M:%S')" + echo "Director: $work_dir" + echo "Prompt: $prompt" + echo "═══════════════════════════════════════════════════════════════" + echo "" + } > "$processed_log" + # Salvează prompt-ul într-un fișier temporar pentru a evita probleme cu escape local prompt_file=$(mktemp) echo "$prompt" > "$prompt_file" # Rulează Claude cu stream-json și procesează output-ul în timp real - # --allowedTools pre-aprobă tool-urile necesare pentru execuție automată - # --max-turns limitează iterațiile pentru siguranță claude -p "$(cat "$prompt_file")" \ --output-format stream-json \ --verbose \ - --allowedTools "Bash,Read,Edit,Write,Grep,Glob,LSP" \ - --max-turns 20 2>&1 | tee "$log_file" | while IFS= read -r line; do + --allowedTools "Bash(git:*),Bash(npm:*),Bash(node:*),Bash(python3:*),Bash(pip3:*),Bash(pip:*),Bash(ls:*),Bash(cat:*),Bash(mkdir:*),Bash(rm:*),Bash(cp:*),Bash(mv:*),Bash(chmod:*),Bash(touch:*),Bash(find:*),Bash(grep:*),Bash(head:*),Bash(tail:*),Bash(wc:*),Bash(which:*),Bash(stat:*),Bash(file:*),Bash(pgrep:*),Bash(kill:*),Read,Write,Edit,Glob,Grep,WebSearch,WebFetch,Task,Skill,TodoWrite,LSP" \ + --max-turns 50 2>&1 | while IFS= read -r line; do # Parsează JSON și extrage informații relevante if echo "$line" | jq -e . >/dev/null 2>&1; then - # Extrage tipul mesajului msg_type=$(echo "$line" | jq -r '.type // empty' 2>/dev/null) + timestamp=$(date '+%H:%M:%S') case "$msg_type" in + "system") + subtype=$(echo "$line" | jq -r '.subtype // empty' 2>/dev/null) + if [ "$subtype" = "init" ]; then + echo "[$timestamp] ▶ Sesiune Claude pornită" >> "$processed_log" + echo -e "${GREEN}▶${NC} Sesiune Claude pornită" + fi + ;; "assistant") - # Mesaj de la Claude - extrage text - content=$(echo "$line" | jq -r ' - .message.content[]? | - select(.type == "text") | - .text // empty - ' 2>/dev/null | head -c 150) + # Verifică pentru tool_use - extrage detalii complete + tool_info=$(echo "$line" | jq -r ' + .message.content[]? | select(.type == "tool_use") | + {name: .name, input: .input} | + if .name == "WebFetch" then "WebFetch: \(.input.url // "?") | \(.input.prompt // "" | .[0:50])" + elif .name == "WebSearch" then "WebSearch: \(.input.query // "?")" + elif .name == "Bash" then "Bash: \(.input.command // "" | .[0:100])" + elif .name == "Read" then "Read: \(.input.file_path // "?")" + elif .name == "Write" then "Write: \(.input.file_path // "?")" + elif .name == "Edit" then "Edit: \(.input.file_path // "?")" + elif .name == "Grep" then "Grep: \(.input.pattern // "?") in \(.input.path // ".")" + elif .name == "Glob" then "Glob: \(.input.pattern // "?")" + elif .name == "Task" then "Task: \(.input.description // "?") [\(.input.subagent_type // "?")]" + elif .name == "Skill" then "Skill: \(.input.skill // "?")" + else "\(.name): \(.input | tostring | .[0:80])" + end + ' 2>/dev/null | head -1) + if [ -n "$tool_info" ]; then + echo "[$timestamp] ⚙ $tool_info" >> "$processed_log" + echo -e "${YELLOW}⚙${NC} $tool_info" + fi + + # Text output + content=$(echo "$line" | jq -r '.message.content[]? | select(.type == "text") | .text // empty' 2>/dev/null | head -c 300) if [ -n "$content" ]; then + echo "[$timestamp] 💬 $content" >> "$processed_log" echo -e "${GREEN}◉${NC} $content" fi ;; "user") - # Tool result - echo -e "${CYAN} ↪${NC} Tool result received" + # Tool result - extrage detalii despre eroare + tool_result=$(echo "$line" | jq -r ' + .message.content[]? | select(.type == "tool_result") | + if .is_error == true then + "✗ EROARE: \(.content // "" | .[0:150])" + else + "✓ OK" + end + ' 2>/dev/null | head -1) + if [ -n "$tool_result" ]; then + echo "[$timestamp] $tool_result" >> "$processed_log" + if [[ "$tool_result" == *"EROARE"* ]]; then + echo -e "${RED} $tool_result${NC}" + else + echo -e "${CYAN} $tool_result${NC}" + fi + else + is_error=$(echo "$line" | jq -r '.message.content[]?.is_error // false' 2>/dev/null | head -1) + if [ "$is_error" = "true" ]; then + err_content=$(echo "$line" | jq -r '.message.content[]?.content // "" | .[0:150]' 2>/dev/null | head -1) + echo "[$timestamp] ✗ EROARE: $err_content" >> "$processed_log" + echo -e "${RED} ✗ EROARE: $err_content${NC}" + else + echo "[$timestamp] ✓ OK" >> "$processed_log" + echo -e "${CYAN} ✓ OK${NC}" + fi + fi ;; "result") - # Rezultat final - result_text=$(echo "$line" | jq -r '.result // empty' 2>/dev/null | head -c 200) + result_text=$(echo "$line" | jq -r '.result // empty' 2>/dev/null | head -c 500) + echo "" >> "$processed_log" + echo "[$timestamp] ════════════════════════════════════════════" >> "$processed_log" + echo "[$timestamp] ✅ TASK FINALIZAT" >> "$processed_log" + echo "[$timestamp] ════════════════════════════════════════════" >> "$processed_log" + echo "Rezultat:" >> "$processed_log" + echo "$result_text" >> "$processed_log" + echo "" - echo -e "${GREEN}✓ REZULTAT:${NC}" + echo -e "${GREEN}✓ TASK FINALIZAT${NC}" echo -e "$result_text" ;; - *) - # Verifică pentru tool_use în content - tool_name=$(echo "$line" | jq -r '.message.content[]? | select(.type == "tool_use") | .name // empty' 2>/dev/null | head -1) - if [ -n "$tool_name" ]; then - echo -e "${YELLOW}⚙${NC} Tool: ${BOLD}$tool_name${NC}" - fi - ;; esac fi done @@ -306,6 +545,16 @@ run_claude_with_progress() { rm -f "$prompt_file" + # Finalizează log-ul procesat + { + echo "" + echo "═══════════════════════════════════════════════════════════════" + echo "End: $(date '+%Y-%m-%d %H:%M:%S')" + echo "Durată: ${duration}s" + echo "Exit code: $exit_code" + echo "═══════════════════════════════════════════════════════════════" + } >> "$processed_log" + echo "" echo -e "${BOLD}${BLUE}════════════════════════════════════════════════════════════════${NC}" @@ -315,52 +564,156 @@ run_claude_with_progress() { print_error "Claude a terminat cu eroare (cod: $exit_code) în ${duration}s" fi - echo -e "${CYAN}Log salvat:${NC} $log_file" + echo -e "${CYAN}Log progres:${NC} $processed_log" echo -e "${BOLD}${BLUE}════════════════════════════════════════════════════════════════${NC}" return $exit_code } +# ============================================================================ +# Vezi task-uri active și log-uri recente +# ============================================================================ + +show_task_status() { + print_section "Task-uri active și log-uri recente" + + # Afișează procese Claude active (bazat pe fișiere PID) + echo -e "${CYAN}Task-uri background active:${NC}" + local active_count=0 + shopt -s nullglob + for pid_file in "$LOG_DIR"/*.pid; do + [ -f "$pid_file" ] || continue + local pid=$(cat "$pid_file" 2>/dev/null) + if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then + local log_name=$(basename "${pid_file%.pid}_progress.log") + echo -e " ${GREEN}●${NC} PID: $pid → $log_name" + ((active_count++)) + else + # PID invalid sau proces terminat - șterge fișierul + rm -f "$pid_file" 2>/dev/null + fi + done + if [ $active_count -eq 0 ]; then + echo -e " ${YELLOW}○${NC} Niciun task activ" + fi + echo "" + + # Afișează log-uri de progres recente + echo -e "${CYAN}Log-uri recente (ultimele 5):${NC}" + local logs=$(ls -t "$LOG_DIR"/*_progress.log 2>/dev/null | head -5) + if [ -n "$logs" ]; then + local i=1 + for log in $logs; do + local log_basename=$(basename "$log") + local pid_file="${log%_progress.log}.pid" + + # Verifică status + if [ -f "$pid_file" ]; then + local pid=$(cat "$pid_file" 2>/dev/null) + if kill -0 "$pid" 2>/dev/null; then + status="${BLUE}◐ În curs (PID: $pid)${NC}" + else + status="${RED}✗ Întrerupt${NC}" + rm -f "$pid_file" 2>/dev/null + fi + elif grep -q "TASK FINALIZAT" "$log" 2>/dev/null; then + status="${GREEN}✓ Finalizat${NC}" + elif grep -q "Exit code:" "$log" 2>/dev/null; then + exit_code=$(grep "Exit code:" "$log" | tail -1 | awk '{print $NF}') + if [ "$exit_code" = "0" ]; then + status="${GREEN}✓ Terminat OK${NC}" + else + status="${RED}✗ Terminat cu eroare ($exit_code)${NC}" + fi + else + status="${RED}✗ Întrerupt/Incomplet${NC}" + fi + + # Afișează ultima activitate + local last_activity=$(grep "^\[" "$log" 2>/dev/null | tail -1 | head -c 100) + + echo -e " ${BOLD}$i)${NC} $log_basename" + echo -e " Status: $status" + echo -e " Ultima: ${CYAN}${last_activity:-N/A}${NC}" + echo -e " Path: $log" + echo "" + ((i++)) + done + echo -e "${YELLOW}Comenzi utile:${NC}" + echo -e " tail -f # Urmărește live" + echo -e " less # Citește complet" + else + echo -e " ${YELLOW}○${NC} Nu există log-uri" + fi + echo "" + echo -e " ${BOLD}b)${NC} Înapoi la meniu" + echo -e " ${BOLD}q)${NC} ${RED}Ieșire${NC}" + echo "" + + read -p "Alege [b/q]: " status_choice + case $status_choice in + q|Q) + echo "" + print_info "La revedere!" + exit 0 + ;; + *) + # Orice altceva (inclusiv b sau Enter) - înapoi la meniu + ;; + esac +} + # ============================================================================ # Gestionare worktrees # ============================================================================ manage_worktrees() { - print_section "Worktrees existente pentru $PROJECT_NAME" + while true; do + print_section "Worktrees existente pentru $PROJECT_NAME" - cd "$PROJECT_DIR" + cd "$PROJECT_DIR" - echo -e "${CYAN}Worktrees:${NC}" - git worktree list - echo "" + echo -e "${CYAN}Worktrees:${NC}" + git worktree list + echo "" - echo -e " ${BOLD}1)${NC} Șterge un worktree" - echo -e " ${BOLD}2)${NC} Navighează la un worktree" - echo -e " ${BOLD}3)${NC} Înapoi" - echo "" + echo -e " ${BOLD}1)${NC} Șterge un worktree" + echo -e " ${BOLD}2)${NC} Navighează la un worktree" + echo -e " ${BOLD}b)${NC} Înapoi la meniu" + echo -e " ${BOLD}q)${NC} ${RED}Ieșire${NC}" + echo "" - read -p "Alege [1-3]: " manage_choice + read -p "Alege [1-2/b/q]: " manage_choice - case $manage_choice in - 1) - read -p "Path worktree de șters: " wt_path - if [ -n "$wt_path" ]; then - git worktree remove "$wt_path" --force - print_success "Worktree șters" - fi - ;; - 2) - read -p "Path worktree: " wt_path - if [ -d "$wt_path" ]; then - cd "$wt_path" - print_success "Navigat la $wt_path" - exec bash - fi - ;; - 3) - return - ;; - esac + case $manage_choice in + 1) + read -p "Path worktree de șters: " wt_path + if [ -n "$wt_path" ]; then + git worktree remove "$wt_path" --force + print_success "Worktree șters" + fi + ;; + 2) + read -p "Path worktree: " wt_path + if [ -d "$wt_path" ]; then + cd "$wt_path" + print_success "Navigat la $wt_path" + exec bash + fi + ;; + b|B) + exec "$0" + ;; + q|Q) + echo "" + print_info "La revedere!" + exit 0 + ;; + *) + print_error "Opțiune invalidă" + ;; + esac + done } # ============================================================================ @@ -373,8 +726,17 @@ main() { # 1. Selectare proiect select_project - # 2. Selectare mod de lucru - select_work_mode + # 2. Selectare mod de lucru (cu loop pentru navigare) + while true; do + select_work_mode + + # Dacă vrea înapoi, repornește scriptul + if [ "$WORK_MODE" = "back" ]; then + exec "$0" + fi + + break + done case $WORK_MODE in "feature") @@ -409,7 +771,7 @@ main() { ;; "temp") - # Mod temporar fără worktree + # Mod temporar fără worktree - rulează în background get_task_description # Folosește directorul proiectului direct @@ -418,8 +780,11 @@ main() { # Generează log file LOG_FILE="$LOG_DIR/${PROJECT_NAME}_temp_$(date +%Y%m%d_%H%M%S).log" - # Rulează Claude - run_claude_with_progress "$WORKING_DIR" "$TASK_DESCRIPTION" "$LOG_FILE" + # Rulează Claude în background și revine la meniu + run_claude_background "$WORKING_DIR" "$TASK_DESCRIPTION" "$LOG_FILE" + + # Revine la meniu + exec "$0" ;; "interactive") @@ -433,6 +798,13 @@ main() { # Gestionare worktrees manage_worktrees ;; + + "status") + # Vezi task-uri active + show_task_status + # Revine la meniu + exec "$0" + ;; esac }