feat: Auto-detect repository paths for any app

- Add detect_git_repo_path() function to find repos in /data/repositories
- Add detect_app_in_docker() to find containers by name
- Planner now receives detected context automatically
- Supports BotVPS, TrackSteel, and any repo in /data/repositories
- Uses 'docker compose' (space) syntax

Example: 'faz deploy do tracksteel' will detect TrackSteel repo path automatically
This commit is contained in:
Marcos
2026-03-22 15:30:15 -03:00
parent 7579e62d9b
commit 19ac2b55d4

View File

@@ -5,6 +5,7 @@
import json
import re
import os
from typing import Dict, List, Optional
from llm_providers import (
call_planner, call_executor, get_planner_llm, get_executor_llm,
@@ -20,24 +21,22 @@ from credential_manager import sync_credentials, get_services_status
PLANNER_SYSTEM_PROMPT = """Você é o PLANNER AGENT do BotVPS.
Seu trabalho é decompor tarefas em passos executáveis CORRETOS.
### CAMINHO DO REPOSITÓRIO:
O repositório BotVPS está em: /data/applications/bw1erd9ww5121i1fsh420bcj
O repositório Git está em: /data/repositories/0/5/5adtracksteel/AdmTrackSteel
### REPOSITORIOS CONHECIDOS:
- BotVPS: /data/applications/bw1erd9ww5121i1fsh420bcj
- TrackSteel: /data/repositories/0/5/5adtracksteel/AdmTrackSteel
{CONTEXT_INFO}
### REGRAS CRÍTICAS DE COMANDOS:
1. USE SEMPRE "docker compose" (COM ESPAÇO), NUNCA "docker-compose" (COM HÍFEN)
2. Para git, use o caminho ABSOLUTO completo do repositório
3. Para docker compose, use "cd /caminho && docker compose up -d"
4. Se não souber o caminho, use: find /data/repositories -name '*.git' -type d
### EXEMPLOS DE COMANDOS CORRETOS:
✅ CORRETO: cd /data/applications/bw1erd9ww5121i1fsh420bcj && git pull origin master
❌ ERRADO: git -C /BotVPS pull
✅ CORRETO: cd /data/applications/bw1erd9ww5121i1fsh420bcj && docker compose up -d --build
❌ ERRADO: docker-compose up -d
✅ CORRETO: cd /data/applications/bw1erd9ww5121i1fsh420bcj && docker compose down
❌ ERRADO: docker-compose down
✅ CORRETO: cd /repo/path && git pull origin master
✅ CORRETO: cd /repo/path && docker compose up -d --build
✅ CORRETO: docker restart nome-do-container
### NÍVEIS DE PERIGO:
- SAFE: listar, ver status, ler logs
@@ -104,6 +103,78 @@ def _format_tools_for_prompt() -> str:
lines.append(f"- {name}: {info['desc']} [{info['danger']}]")
return "\n".join(lines)
def detect_git_repo_path(task: str) -> str:
"""
Detecta automaticamente o caminho do repositório Git baseado na tarefa.
Retorna o caminho do repositório mais provável.
"""
from tools_v2 import run_bash
# Normaliza o texto da tarefa
task_lower = task.lower()
# Lista de repositórios conhecidos no host
known_repos = [
"/data/repositories/0/5/5adtracksteel/AdmTrackSteel",
"/data/repositories/0/5/5adtracksteel/BotVPS",
"/data/applications/bw1erd9ww5121i1fsh420bcj",
"/data/coolify",
"/root",
"/app"
]
# Tenta detectar pelo nome mencionado na tarefa
if "tracksteel" in task_lower or "tracksteel" in task_lower:
return "/data/repositories/0/5/5adtracksteel/AdmTrackSteel"
if "botvps" in task_lower or "bot vps" in task_lower:
return "/data/applications/bw1erd9ww5121i1fsh420bcj"
if "coolify" in task_lower:
return "/data/coolify"
# Tenta encontrar repositório git válido
for repo_path in known_repos:
result = run_bash(f"test -d {repo_path}/.git && echo 'FOUND:{repo_path}' || true")
if result.get("success") and "FOUND:" in result.get("output", ""):
return result["output"].split("FOUND:")[1].strip()
# Procura em /data/repositories por repositórios git
result = run_bash("find /data/repositories -name '*.git' -type d 2>/dev/null | head -10")
if result.get("success") and result.get("output"):
# Retorna o primeiro repositório encontrado
first_repo = result["output"].split("\n")[0].replace("/.git", "")
return first_repo
# Fallback: retorna /app se existir
if os.path.exists("/app/.git"):
return "/app"
return "/"
def detect_app_in_docker(task: str) -> str:
"""
Detecta qual container/app o usuário quer interagir baseado na tarefa.
"""
from tools_v2 import run_bash
task_lower = task.lower()
# Lista containers e tenta match
result = run_bash("docker ps --format '{{.Names}}' 2>/dev/null")
if result.get("success"):
containers = result["output"].lower()
if "tracksteel" in task_lower:
if "tracksteel" in containers:
return "tracksteel"
if "botvps" in task_lower or "antigravity" in task_lower:
if "vps" in containers:
return "vps-ai-agent"
if "coolify" in task_lower:
if "coolify" in containers:
return "coolify"
return ""
def _parse_json_response(text: str) -> Optional[Dict]:
"""Extrai JSON da resposta do LLM."""
# Tenta encontrar JSON no texto
@@ -152,7 +223,22 @@ def plan_task(task: str) -> Dict:
provider, model = get_planner_llm()
print(f"[PLANNER] Using: {provider}/{model}")
# Detecta automaticamente informações do contexto
detected_repo = detect_git_repo_path(task)
detected_app = detect_app_in_docker(task)
print(f"[CONTEXT] Repo: {detected_repo}, App: {detected_app}")
# Contexto adicional para o planner
context_info = f"""
### CONTEXTO DETECTADO:
- Repositório mais provável: {detected_repo}
- Aplicação mais provável: {detected_app}
- Para descobrir o repositório correto, use: find /data/repositories -name '*.git' -type d 2>/dev/null
"""
system_prompt = PLANNER_SYSTEM_PROMPT.replace("{TOOLS_LIST}", _format_tools_for_prompt())
system_prompt = system_prompt.replace("{CONTEXT_INFO}", context_info)
response = call_planner(task, system_prompt)
print(f"[RESPONSE] Planner response:\n{response[:500]}...")