New skills covering 10 categories: **Security & Audit**: 007 (STRIDE/PASTA/OWASP), cred-omega (secrets management) **AI Personas**: Karpathy, Hinton, Sutskever, LeCun (4 sub-skills), Altman, Musk, Gates, Jobs, Buffett **Multi-agent Orchestration**: agent-orchestrator, task-intelligence, multi-advisor **Code Analysis**: matematico-tao (Terence Tao-inspired mathematical code analysis) **Social & Messaging**: Instagram Graph API, Telegram Bot, WhatsApp Cloud API, social-orchestrator **Image Generation**: AI Studio (Gemini), Stability AI, ComfyUI Gateway, image-studio router **Brazilian Domain**: 6 auction specialist modules, 2 legal advisors, auctioneers data scraper **Product & Growth**: design, invention, monetization, analytics, growth engine **DevOps & LLM Ops**: Docker/CI-CD/AWS, RAG/embeddings/fine-tuning **Skill Governance**: installer, sentinel auditor, context management Each skill includes: - Standardized YAML frontmatter (name, description, risk, source, tags, tools) - Structured sections (Overview, When to Use, How it Works, Best Practices) - Python scripts and reference documentation where applicable - Cross-platform compatibility (Claude Code, Antigravity, Cursor, Gemini CLI, Codex CLI) Co-authored-by: ProgramadorBrasil <214873561+ProgramadorBrasil@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
165 lines
6.2 KiB
Python
165 lines
6.2 KiB
Python
"""
|
|
Analyzer de performance.
|
|
|
|
Verifica: chamadas API sequenciais, caching, N+1 queries,
|
|
connection reuse, retry/backoff, timeouts.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
from typing import Any, Dict, List, Tuple
|
|
|
|
|
|
def analyze(skill_data: Dict[str, Any]) -> Tuple[float, List[Dict[str, Any]]]:
|
|
"""Analisa performance de uma skill. Retorna (score, findings)."""
|
|
score = 100.0
|
|
findings: List[Dict[str, Any]] = []
|
|
skill_name = skill_data["name"]
|
|
skill_path = Path(skill_data["path"])
|
|
|
|
has_retry = False
|
|
has_timeout = False
|
|
has_caching = False
|
|
has_connection_pool = False
|
|
has_async = False
|
|
has_concurrency = False
|
|
|
|
api_call_files = []
|
|
|
|
for rel_path in skill_data.get("python_files", []):
|
|
filepath = skill_path / rel_path
|
|
if not filepath.exists():
|
|
continue
|
|
try:
|
|
source = filepath.read_text(encoding="utf-8", errors="replace")
|
|
except OSError:
|
|
continue
|
|
|
|
# Detectar patterns de performance
|
|
if re.search(r'(?:retry|backoff|MAX_RETRIES|RETRY_BACKOFF)', source, re.I):
|
|
has_retry = True
|
|
if re.search(r'(?:timeout|REQUEST_TIMEOUT)', source, re.I):
|
|
has_timeout = True
|
|
if re.search(r'(?:cache|lru_cache|functools\.cache|_cache)', source, re.I):
|
|
has_caching = True
|
|
if re.search(r'(?:session|Session\(\)|httpx\.Client)', source, re.I):
|
|
has_connection_pool = True
|
|
if re.search(r'(?:async\s+def|asyncio|aiohttp|httpx\.AsyncClient)', source):
|
|
has_async = True
|
|
if re.search(r'(?:concurrent|ThreadPool|ProcessPool|asyncio\.gather|--concurrency)', source, re.I):
|
|
has_concurrency = True
|
|
|
|
# Contar chamadas API (requests.get/post, httpx, etc)
|
|
api_calls = len(re.findall(
|
|
r'(?:requests\.\w+|httpx\.\w+|self\.\w*(?:get|post|put|delete|patch))\s*\(',
|
|
source
|
|
))
|
|
if api_calls > 0:
|
|
api_call_files.append((rel_path, api_calls))
|
|
|
|
# Detectar N+1 patterns (loop com query SQL dentro)
|
|
# Analise linha-a-linha para evitar backtracking em regex DOTALL
|
|
lines = source.splitlines()
|
|
in_for_loop = False
|
|
for line_text in lines:
|
|
stripped = line_text.strip()
|
|
if stripped.startswith("for ") and stripped.endswith(":"):
|
|
in_for_loop = True
|
|
elif in_for_loop and stripped and not stripped[0].isspace() and not line_text[0].isspace():
|
|
in_for_loop = False
|
|
elif in_for_loop and re.search(r'(?:SELECT|\.execute)\s*\(', stripped):
|
|
findings.append({
|
|
"skill_name": skill_name,
|
|
"dimension": "performance",
|
|
"severity": "medium",
|
|
"category": "n_plus_1",
|
|
"title": f"Possivel N+1 query em {rel_path}",
|
|
"description": "Loop com query SQL pode causar muitas chamadas ao banco",
|
|
"file_path": rel_path,
|
|
"recommendation": "Carregar dados em batch antes do loop",
|
|
"effort": "medium",
|
|
"impact": "high",
|
|
})
|
|
score -= 8
|
|
break
|
|
|
|
# Criar conexao dentro de loop (analise simples)
|
|
has_connect_in_loop = False
|
|
in_for_loop = False
|
|
for line_text in lines:
|
|
stripped = line_text.strip()
|
|
if stripped.startswith("for ") and stripped.endswith(":"):
|
|
in_for_loop = True
|
|
elif in_for_loop and stripped and not line_text[0].isspace():
|
|
in_for_loop = False
|
|
elif in_for_loop and "_connect()" in stripped:
|
|
has_connect_in_loop = True
|
|
break
|
|
|
|
if has_connect_in_loop:
|
|
findings.append({
|
|
"skill_name": skill_name,
|
|
"dimension": "performance",
|
|
"severity": "medium",
|
|
"category": "connection_per_iteration",
|
|
"title": f"Conexao criada dentro de loop em {rel_path}",
|
|
"file_path": rel_path,
|
|
"recommendation": "Mover _connect() para fora do loop, reutilizar conexao",
|
|
"effort": "low",
|
|
"impact": "high",
|
|
})
|
|
score -= 5
|
|
|
|
# Verificar ausencia de boas praticas
|
|
if not has_retry and api_call_files:
|
|
findings.append({
|
|
"skill_name": skill_name,
|
|
"dimension": "performance",
|
|
"severity": "medium",
|
|
"category": "no_retry",
|
|
"title": "Sem retry/backoff para chamadas API",
|
|
"description": f"Encontradas chamadas API em {len(api_call_files)} arquivo(s) sem mecanismo de retry",
|
|
"recommendation": "Implementar retry com exponential backoff (ex: tenacity, ou manual)",
|
|
"effort": "medium",
|
|
"impact": "high",
|
|
})
|
|
score -= 10
|
|
|
|
if not has_timeout and api_call_files:
|
|
findings.append({
|
|
"skill_name": skill_name,
|
|
"dimension": "performance",
|
|
"severity": "medium",
|
|
"category": "no_timeout",
|
|
"title": "Sem timeout configurado para chamadas HTTP",
|
|
"recommendation": "Adicionar timeout= em todas as chamadas requests/httpx",
|
|
"effort": "low",
|
|
"impact": "medium",
|
|
})
|
|
score -= 5
|
|
|
|
if not has_connection_pool and len(api_call_files) > 2:
|
|
findings.append({
|
|
"skill_name": skill_name,
|
|
"dimension": "performance",
|
|
"severity": "low",
|
|
"category": "no_connection_reuse",
|
|
"title": "Sem reuso de conexoes HTTP",
|
|
"description": "Multiplos arquivos fazem chamadas HTTP sem Session/Client compartilhado",
|
|
"recommendation": "Usar requests.Session() ou httpx.Client() para reutilizar conexoes",
|
|
"effort": "low",
|
|
"impact": "medium",
|
|
})
|
|
score -= 3
|
|
|
|
# Bonus
|
|
if has_retry:
|
|
score = min(100.0, score + 5)
|
|
if has_async or has_concurrency:
|
|
score = min(100.0, score + 5)
|
|
if has_caching:
|
|
score = min(100.0, score + 3)
|
|
|
|
return max(0.0, min(100.0, score)), findings
|