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>
150 lines
4.4 KiB
Python
150 lines
4.4 KiB
Python
"""
|
|
Compressão inteligente e arquivamento de sessões antigas.
|
|
Mantém o histórico enxuto sem perder informação crítica.
|
|
"""
|
|
|
|
import shutil
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
from config import SESSIONS_DIR, ARCHIVE_DIR, ARCHIVE_AFTER_SESSIONS
|
|
|
|
|
|
def should_archive(session_number: int, current_session: int) -> bool:
|
|
"""Verifica se uma sessão deve ser arquivada."""
|
|
return (current_session - session_number) > ARCHIVE_AFTER_SESSIONS
|
|
|
|
|
|
def archive_session(session_path: Path):
|
|
"""Move sessão para archive/ com resumo compacto."""
|
|
ARCHIVE_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
text = session_path.read_text(encoding="utf-8")
|
|
compressed = _compress_session(text)
|
|
|
|
archive_path = ARCHIVE_DIR / session_path.name
|
|
archive_path.write_text(compressed, encoding="utf-8")
|
|
|
|
session_path.unlink()
|
|
|
|
|
|
def _compress_session(text: str) -> str:
|
|
"""Comprime uma sessão mantendo apenas informação essencial."""
|
|
lines = text.splitlines()
|
|
compressed = []
|
|
keep_sections = {
|
|
"tópicos", "decisões", "tarefas pendentes",
|
|
"descobertas", "erros resolvidos", "convenções",
|
|
}
|
|
skip_sections = {
|
|
"métricas", "arquivos modificados", "dívida técnica",
|
|
}
|
|
|
|
current_section = ""
|
|
keeping = True
|
|
|
|
for line in lines:
|
|
# Sempre manter cabeçalho
|
|
if line.startswith("# Sessão"):
|
|
compressed.append(line)
|
|
compressed.append("")
|
|
continue
|
|
|
|
if line.startswith("## "):
|
|
section_name = line[3:].strip().lower()
|
|
if section_name in skip_sections:
|
|
keeping = False
|
|
elif section_name in keep_sections:
|
|
keeping = True
|
|
compressed.append(line)
|
|
else:
|
|
keeping = False
|
|
current_section = section_name
|
|
continue
|
|
|
|
if keeping and line.strip():
|
|
compressed.append(line)
|
|
|
|
compressed.append("")
|
|
compressed.append("*[Sessão arquivada — detalhes completos removidos]*")
|
|
return "\n".join(compressed)
|
|
|
|
|
|
def compress_archive():
|
|
"""Consolida arquivos antigos em ARCHIVE_YYYY.md."""
|
|
if not ARCHIVE_DIR.exists():
|
|
return
|
|
|
|
year = datetime.now().strftime("%Y")
|
|
archive_files = sorted(ARCHIVE_DIR.glob("session-*.md"))
|
|
|
|
if len(archive_files) < 5:
|
|
return # Não vale consolidar com poucos arquivos
|
|
|
|
consolidated_path = ARCHIVE_DIR / f"ARCHIVE_{year}.md"
|
|
consolidated_lines = [
|
|
f"# Arquivo Consolidado — {year}",
|
|
"",
|
|
]
|
|
|
|
for af in archive_files:
|
|
text = af.read_text(encoding="utf-8")
|
|
# Extrair apenas título e decisões
|
|
session_header = ""
|
|
decisions = []
|
|
in_decisions = False
|
|
|
|
for line in text.splitlines():
|
|
if line.startswith("# Sessão"):
|
|
session_header = line
|
|
elif line.startswith("## Decisões"):
|
|
in_decisions = True
|
|
elif line.startswith("## "):
|
|
in_decisions = False
|
|
elif in_decisions and line.strip().startswith("- "):
|
|
decisions.append(line.strip())
|
|
|
|
if session_header:
|
|
consolidated_lines.append(f"### {session_header.lstrip('#').strip()}")
|
|
for d in decisions:
|
|
consolidated_lines.append(f" {d}")
|
|
consolidated_lines.append("")
|
|
|
|
af.unlink()
|
|
|
|
consolidated_path.write_text("\n".join(consolidated_lines), encoding="utf-8")
|
|
|
|
|
|
def auto_maintain(current_session: int):
|
|
"""Executa arquivamento e compressão automáticos."""
|
|
if not SESSIONS_DIR.exists():
|
|
return
|
|
|
|
# Arquivar sessões antigas
|
|
for session_file in sorted(SESSIONS_DIR.glob("session-*.md")):
|
|
try:
|
|
num = int(session_file.stem.split("-")[1])
|
|
except (IndexError, ValueError):
|
|
continue
|
|
|
|
if should_archive(num, current_session):
|
|
archive_session(session_file)
|
|
|
|
# Consolidar arquivo se necessário
|
|
compress_archive()
|
|
|
|
|
|
def get_archive_summary() -> str:
|
|
"""Retorna resumo do que está arquivado."""
|
|
if not ARCHIVE_DIR.exists():
|
|
return "Nenhuma sessão arquivada."
|
|
|
|
archive_files = list(ARCHIVE_DIR.glob("*.md"))
|
|
if not archive_files:
|
|
return "Nenhuma sessão arquivada."
|
|
|
|
lines = [f"Sessões arquivadas: {len(archive_files)} arquivo(s)"]
|
|
for af in sorted(archive_files):
|
|
lines.append(f" - {af.name}")
|
|
return "\n".join(lines)
|