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>
116 lines
3.3 KiB
Python
116 lines
3.3 KiB
Python
"""
|
|
Busca full-text via SQLite FTS5 no histórico de sessões.
|
|
"""
|
|
|
|
import sqlite3
|
|
from pathlib import Path
|
|
|
|
from config import DB_PATH, MAX_SEARCH_RESULTS
|
|
from models import SearchResult
|
|
|
|
|
|
def _get_connection() -> sqlite3.Connection:
|
|
"""Retorna conexão SQLite com FTS5."""
|
|
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
conn = sqlite3.connect(str(DB_PATH))
|
|
conn.execute("PRAGMA journal_mode=WAL")
|
|
return conn
|
|
|
|
|
|
def init_search_db():
|
|
"""Cria tabela FTS5 se não existir."""
|
|
conn = _get_connection()
|
|
conn.execute("""
|
|
CREATE VIRTUAL TABLE IF NOT EXISTS session_search USING fts5(
|
|
session_number,
|
|
date,
|
|
section,
|
|
content,
|
|
tokenize='unicode61'
|
|
)
|
|
""")
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
|
|
def index_session(session_number: int, date: str, sections: dict[str, str]):
|
|
"""
|
|
Indexa conteúdo de uma sessão.
|
|
sections: {"topics": "texto", "decisions": "texto", ...}
|
|
"""
|
|
conn = _get_connection()
|
|
# Remove entradas antigas da mesma sessão
|
|
conn.execute(
|
|
"DELETE FROM session_search WHERE session_number = ?",
|
|
(str(session_number),),
|
|
)
|
|
for section_name, content in sections.items():
|
|
if content.strip():
|
|
conn.execute(
|
|
"INSERT INTO session_search (session_number, date, section, content) VALUES (?, ?, ?, ?)",
|
|
(str(session_number), date, section_name, content),
|
|
)
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
|
|
def search(query: str, limit: int = MAX_SEARCH_RESULTS) -> list[SearchResult]:
|
|
"""Busca full-text no histórico."""
|
|
conn = _get_connection()
|
|
try:
|
|
rows = conn.execute(
|
|
"""
|
|
SELECT session_number, date, section, snippet(session_search, 3, '>>>', '<<<', '...', 40)
|
|
FROM session_search
|
|
WHERE session_search MATCH ?
|
|
ORDER BY rank
|
|
LIMIT ?
|
|
""",
|
|
(query, limit),
|
|
).fetchall()
|
|
except sqlite3.OperationalError:
|
|
# Tabela não existe ou query inválida
|
|
return []
|
|
finally:
|
|
conn.close()
|
|
|
|
results = []
|
|
for row in rows:
|
|
results.append(SearchResult(
|
|
session_number=int(row[0]),
|
|
date=row[1],
|
|
section=row[2],
|
|
snippet=row[3],
|
|
))
|
|
return results
|
|
|
|
|
|
def reindex_all(sessions_dir: Path):
|
|
"""Reconstrói índice a partir dos arquivos de sessão."""
|
|
conn = _get_connection()
|
|
conn.execute("DELETE FROM session_search")
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
for session_file in sorted(sessions_dir.glob("session-*.md")):
|
|
try:
|
|
num = int(session_file.stem.split("-")[1])
|
|
except (IndexError, ValueError):
|
|
continue
|
|
|
|
text = session_file.read_text(encoding="utf-8")
|
|
date = ""
|
|
sections = {}
|
|
current_section = "general"
|
|
|
|
for line in text.splitlines():
|
|
if line.startswith("# Sessão") and "—" in line:
|
|
date = line.split("—")[-1].strip()
|
|
elif line.startswith("## "):
|
|
current_section = line[3:].strip().lower()
|
|
else:
|
|
sections.setdefault(current_section, "")
|
|
sections[current_section] += line + "\n"
|
|
|
|
index_session(num, date, sections)
|