mega-brain-ai 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mega-brain-ai might be problematic. Click here for more details.
- package/.claude/CLAUDE.md +155 -0
- package/.claude/commands/agents.md +161 -0
- package/.claude/commands/ask.md +117 -0
- package/.claude/commands/benchmark.md +224 -0
- package/.claude/commands/chat.md +343 -0
- package/.claude/commands/compare.md +116 -0
- package/.claude/commands/conclave.md +194 -0
- package/.claude/commands/config.md +133 -0
- package/.claude/commands/council.md +194 -0
- package/.claude/commands/create-agent.md +452 -0
- package/.claude/commands/debate.md +157 -0
- package/.claude/commands/documentation/create-architecture-documentation.md +175 -0
- package/.claude/commands/dossiers.md +180 -0
- package/.claude/commands/evolve.md +223 -0
- package/.claude/commands/extract-dna.md +170 -0
- package/.claude/commands/extract-knowledge.md +507 -0
- package/.claude/commands/inbox.md +296 -0
- package/.claude/commands/ingest-empresa.md +191 -0
- package/.claude/commands/ingest.md +182 -0
- package/.claude/commands/jarvis-briefing.md +67 -0
- package/.claude/commands/jarvis-control.md +169 -0
- package/.claude/commands/jarvis-full.md +181 -0
- package/.claude/commands/jarvis.md +212 -0
- package/.claude/commands/ler-drive.md +212 -0
- package/.claude/commands/log.md +158 -0
- package/.claude/commands/loop.md +133 -0
- package/.claude/commands/loops.md +73 -0
- package/.claude/commands/mission-autopilot.md +538 -0
- package/.claude/commands/mission.md +353 -0
- package/.claude/commands/process-inbox.md +148 -0
- package/.claude/commands/process-jarvis.md +3036 -0
- package/.claude/commands/process-video.md +131 -0
- package/.claude/commands/rag-search.md +78 -0
- package/.claude/commands/resume.md +33 -0
- package/.claude/commands/save.md +38 -0
- package/.claude/commands/scan-inbox.md +125 -0
- package/.claude/commands/setup.md +99 -0
- package/.claude/commands/system-digest.md +243 -0
- package/.claude/commands/verify.md +182 -0
- package/.claude/commands/view-dna.md +169 -0
- package/.claude/hooks/agent_doctor.py +433 -0
- package/.claude/hooks/agent_memory_persister.py +203 -0
- package/.claude/hooks/auto_formatter.py +158 -0
- package/.claude/hooks/checkpoint_writer.py +244 -0
- package/.claude/hooks/claude_md_guard.py +146 -0
- package/.claude/hooks/creation_validator.py +357 -0
- package/.claude/hooks/enforce_dual_location.py +501 -0
- package/.claude/hooks/enforce_plan_mode.py +220 -0
- package/.claude/hooks/inbox_age_alert.py +367 -0
- package/.claude/hooks/jarvis_briefing.py +506 -0
- package/.claude/hooks/ledger_updater.py +301 -0
- package/.claude/hooks/memory_hints_injector.py +251 -0
- package/.claude/hooks/memory_updater.py +202 -0
- package/.claude/hooks/multi_agent_hook.py +464 -0
- package/.claude/hooks/notification_system.py +120 -0
- package/.claude/hooks/pattern_analyzer.py +526 -0
- package/.claude/hooks/pending_tracker.py +188 -0
- package/.claude/hooks/post_batch_cascading.py +1740 -0
- package/.claude/hooks/post_output_validator.py +358 -0
- package/.claude/hooks/post_tool_use.py +120 -0
- package/.claude/hooks/post_write_validator.py +200 -0
- package/.claude/hooks/quality_watchdog.py +394 -0
- package/.claude/hooks/ralph_wiggum.py +277 -0
- package/.claude/hooks/session-source-sync.py +218 -0
- package/.claude/hooks/session_autosave_v2.py +1135 -0
- package/.claude/hooks/session_end.py +203 -0
- package/.claude/hooks/session_start.py +939 -0
- package/.claude/hooks/skill_indexer.py +48 -0
- package/.claude/hooks/skill_router.py +358 -0
- package/.claude/hooks/stop_hook_completeness.py +178 -0
- package/.claude/hooks/subagent_tracker.py +163 -0
- package/.claude/hooks/token_checkpoint.py +584 -0
- package/.claude/hooks/user_prompt_submit.py +125 -0
- package/.claude/rules/ANTHROPIC-STANDARDS.md +384 -0
- package/.claude/rules/CLAUDE-LITE.md +201 -0
- package/.claude/rules/RULE-GROUP-1.md +320 -0
- package/.claude/rules/RULE-GROUP-2.md +307 -0
- package/.claude/rules/RULE-GROUP-3.md +248 -0
- package/.claude/rules/RULE-GROUP-4.md +427 -0
- package/.claude/rules/RULE-GROUP-5.md +388 -0
- package/.claude/rules/RULE-GROUP-6.md +387 -0
- package/.claude/rules/logging.md +53 -0
- package/.claude/rules/mcp-governance.md +128 -0
- package/.claude/rules/pipeline.md +60 -0
- package/.claude/rules/state-management.md +93 -0
- package/.claude/scripts/apply-tags.py +77 -0
- package/.claude/scripts/batch-extract-transcriptions.py +132 -0
- package/.claude/scripts/build-complete-index.py +250 -0
- package/.claude/scripts/build-planilha-index.py +170 -0
- package/.claude/scripts/complete-tag-matching.py +250 -0
- package/.claude/scripts/deduplicate-inbox.py +139 -0
- package/.claude/scripts/docx-xml-extractor.py +141 -0
- package/.claude/scripts/extract-docx-text.py +58 -0
- package/.claude/scripts/extract-single-transcription.py +74 -0
- package/.claude/scripts/extract_docx_from_gdrive.py +77 -0
- package/.claude/scripts/organized-downloader.py +246 -0
- package/.claude/scripts/planilha-tagger.py +187 -0
- package/.claude/scripts/revert-tags.py +70 -0
- package/.claude/scripts/source-sync.py +265 -0
- package/.claude/scripts/tag-inbox-files.py +276 -0
- package/.claude/scripts/tag-inbox-v2.py +253 -0
- package/.claude/scripts/test-extraction.py +35 -0
- package/.claude/scripts/test-full-extraction.py +74 -0
- package/.claude/skills/00-SKILL-CREATOR/SKILL.md +186 -0
- package/.claude/skills/01-SKILL-DOCS-MEGABRAIN/SKILL.md +251 -0
- package/.claude/skills/02-SKILL-PYTHON-MEGABRAIN/SKILL.md +323 -0
- package/.claude/skills/03-SKILL-AGENT-CREATION/SKILL.md +374 -0
- package/.claude/skills/04-SKILL-KNOWLEDGE-EXTRACTION/SKILL.md +318 -0
- package/.claude/skills/05-SKILL-PIPELINE-JARVIS/SKILL.md +430 -0
- package/.claude/skills/06-SKILL-BRAINSTORMING/SKILL.md +72 -0
- package/.claude/skills/07-SKILL-DISPATCHING-PARALLEL-AGENTS/SKILL.md +193 -0
- package/.claude/skills/08-SKILL-EXECUTING-PLANS/SKILL.md +114 -0
- package/.claude/skills/09-SKILL-WRITING-PLANS/SKILL.md +184 -0
- package/.claude/skills/10-SKILL-VERIFICATION-BEFORE-COMPLETION/SKILL.md +130 -0
- package/.claude/skills/11-SKILL-USING-SUPERPOWERS/SKILL.md +105 -0
- package/.claude/skills/DETECTION-PROTOCOL.md +217 -0
- package/.claude/skills/README.md +240 -0
- package/.claude/skills/SKILL-REGISTRY.md +284 -0
- package/.claude/skills/SKILL-SUGGESTIONS.md +114 -0
- package/.claude/skills/_TEMPLATES/SKILL-WRITER-GUIDE.md +385 -0
- package/.claude/skills/chronicler/SKILL.md +146 -0
- package/.claude/skills/chronicler/chronicler_core.py +468 -0
- package/.claude/skills/code-review/SKILL.md +160 -0
- package/.claude/skills/council/SKILL.md +210 -0
- package/.claude/skills/executor/SKILL.md +161 -0
- package/.claude/skills/fase-2-5-tagging/SKILL.md +182 -0
- package/.claude/skills/feature-dev/SKILL.md +154 -0
- package/.claude/skills/finance-agent/SKILL.md +137 -0
- package/.claude/skills/frontend-design/SKILL.md +165 -0
- package/.claude/skills/gdrive-transcription-downloader/SKILL.md +249 -0
- package/.claude/skills/gemini-fallback/SKILL.md +67 -0
- package/.claude/skills/gemini-fallback/gemini_fetch.py +0 -0
- package/.claude/skills/gha/SKILL.md +96 -0
- package/.claude/skills/gha/gha_diagnostic.py +227 -0
- package/.claude/skills/github-workflow/SKILL.md +190 -0
- package/.claude/skills/hookify/SKILL.md +134 -0
- package/.claude/skills/hybrid-source-reading/SKILL.md +265 -0
- package/.claude/skills/jarvis/SKILL.md +546 -0
- package/.claude/skills/jarvis-briefing/SKILL.md +340 -0
- package/.claude/skills/ler-planilha/SKILL.md +281 -0
- package/.claude/skills/plugin-dev/SKILL.md +176 -0
- package/.claude/skills/pr-review-toolkit/SKILL.md +178 -0
- package/.claude/skills/resume/SKILL.md +61 -0
- package/.claude/skills/save/SKILL.md +87 -0
- package/.claude/skills/skill-writer/SKILL.md +153 -0
- package/.claude/skills/skill-writer/examples.md +191 -0
- package/.claude/skills/skill-writer/troubleshooting.md +205 -0
- package/.claude/skills/smart-download-tagger/SKILL.md +148 -0
- package/.claude/skills/source-sync/SKILL.md +240 -0
- package/.claude/skills/sync-docs/SKILL.md +193 -0
- package/.claude/skills/sync-docs/config.json +37 -0
- package/.claude/skills/sync-docs/gdrive_sync.py +358 -0
- package/.claude/skills/sync-docs/reauth.py +71 -0
- package/.claude/skills/talent-agent/SKILL.md +183 -0
- package/.claude/skills/verify/SKILL.md +154 -0
- package/.claude/skills/verify/verify_runner.py +0 -0
- package/.claude/skills/verify-6-levels/SKILL.md +234 -0
- package/.claude/templates/BATCH-LOG-TEMPLATE.md +221 -0
- package/.claudeignore +9 -0
- package/.gitattributes +4 -0
- package/.github/layer1-allowlist.txt +80 -0
- package/.github/layer2-manifest.txt +40 -0
- package/.gitignore +219 -0
- package/README.md +1210 -0
- package/agents/_templates/INDEX.md +741 -0
- package/agents/_templates/TEMPLATE-AGENT-MD-ULTRA-ROBUSTO-V3.md +2399 -0
- package/agents/boardroom/CHECKLIST-MASTER.md +281 -0
- package/agents/boardroom/INTEGRATION-GUIDE.md +406 -0
- package/agents/boardroom/README.md +238 -0
- package/agents/boardroom/config/BOARDROOM-CONFIG.md +186 -0
- package/agents/boardroom/config/TTS-INTEGRATION.md +258 -0
- package/agents/boardroom/config/VOICE-PROFILES.md +624 -0
- package/agents/boardroom/config/voice_mapping.json +128 -0
- package/agents/boardroom/scripts/audio_generator.py +375 -0
- package/agents/boardroom/scripts/audio_generator_edge.py +353 -0
- package/agents/boardroom/scripts/jarvis_boardroom_hook.py +415 -0
- package/agents/boardroom/scripts/notebooklm_generator.py +578 -0
- package/agents/boardroom/templates/EPISODE-TEMPLATE.md +367 -0
- package/agents/boardroom/templates/scene-templates/SCENE-AGENT-DEBATE.md +252 -0
- package/agents/boardroom/templates/scene-templates/SCENE-COUNCIL.md +270 -0
- package/agents/boardroom/templates/scene-templates/SCENE-DNA-CONSULTATION.md +126 -0
- package/agents/boardroom/templates/scene-templates/SCENE-QUESTION.md +174 -0
- package/agents/boardroom/workflows/WORKFLOW-AUDIO-GENERATION.md +421 -0
- package/agents/constitution/BASE-CONSTITUTION.md +254 -0
- package/agents/council/CRITIC.md +197 -0
- package/agents/council/DEVILS-ADVOCATE.md +274 -0
- package/agents/council/SYNTHESIZER.md +293 -0
- package/agents/council/advogado-do-diabo/AGENT.md +489 -0
- package/agents/council/advogado-do-diabo/SOUL.md +100 -0
- package/agents/council/critico-metodologico/AGENT.md +670 -0
- package/agents/council/critico-metodologico/SOUL.md +107 -0
- package/agents/council/sintetizador/AGENT.md +558 -0
- package/agents/council/sintetizador/SOUL.md +94 -0
- package/agents/persons/_example/AGENT-EXAMPLE.md +42 -0
- package/agents/persons/_example/DNA-EXAMPLE.yaml +61 -0
- package/agents/protocols/AGENT-COGNITION-PROTOCOL.md +779 -0
- package/agents/protocols/AGENT-INTEGRITY-PROTOCOL.md +692 -0
- package/agents/protocols/BATCH-VISUAL-PROTOCOL.md +841 -0
- package/agents/protocols/DNA-CONFIG-TEMPLATE.yaml +181 -0
- package/agents/protocols/DNA-EXTRACTION-PROTOCOL.md +370 -0
- package/agents/protocols/EPISTEMIC-PROTOCOL.md +333 -0
- package/agents/protocols/LOG-STRUCTURE-PROTOCOL.md +65 -0
- package/agents/protocols/MEMORY-PROTOCOL.md +567 -0
- package/agents/protocols/NARRATIVE-SYNTHESIS-PROTOCOL.md +278 -0
- package/agents/protocols/PHASE-4-VERIFICATION-CHECKPOINT.md +146 -0
- package/agents/protocols/SOUL-TEMPLATE.md +416 -0
- package/agents/protocols/TEMPLATE-EVOLUTION-PROTOCOL.md +544 -0
- package/agents/protocols/VISUAL-DIFF-PROTOCOL.md +159 -0
- package/agents/sua-empresa/README.md +44 -0
- package/agents/sua-empresa/_example/jds/EXAMPLE-JD.md +42 -0
- package/agents/sua-empresa/_example/org/EXAMPLE-ORG.md +32 -0
- package/agents/sua-empresa/_example/roles/EXAMPLE-ROLE.md +38 -0
- package/bin/cli.js +2 -0
- package/bin/lib/ascii-art.js +234 -0
- package/bin/lib/installer.js +402 -0
- package/bin/lib/setup-wizard.js +95 -0
- package/bin/lib/validate-email.js +109 -0
- package/bin/mega-brain.js +97 -0
- package/bin/push.js +342 -0
- package/bin/templates/env.example +38 -0
- package/inbox/.gitkeep +0 -0
- package/integrations/README.md +46 -0
- package/integrations/mcps/MCP-REGISTRY.md +56 -0
- package/integrations/mcps/excalidraw/CONFIG.md +56 -0
- package/integrations/mcps/gdrive/CONFIG.md +38 -0
- package/knowledge/dna/.gitkeep +0 -0
- package/knowledge/dossiers/persons/.gitkeep +0 -0
- package/knowledge/dossiers/persons/DOSSIER-EXAMPLE.md +49 -0
- package/knowledge/dossiers/system/.gitkeep +0 -0
- package/knowledge/dossiers/themes/.gitkeep +0 -0
- package/knowledge/playbooks/.gitkeep +0 -0
- package/knowledge/playbooks/PLAYBOOK-EXAMPLE.md +50 -0
- package/knowledge/sources/.gitkeep +0 -0
- package/logs/.gitkeep +0 -0
- package/package.json +128 -0
- package/processing/canonical/.gitkeep +0 -0
- package/processing/chunks/.gitkeep +0 -0
- package/processing/insights/.gitkeep +0 -0
- package/processing/narratives/.gitkeep +0 -0
- package/reference/CONSELHO.md +337 -0
- package/reference/CONTEXT7_README.md +28 -0
- package/reference/JARVIS-LOGGING-PROTOCOL.md +380 -0
- package/reference/QUICK-START.md +197 -0
- package/reference/README-RALPH-CASCATEAMENTO.md +207 -0
- package/reference/TEMPLATE-MASTER.md +727 -0
- package/reference/prds/prd-jarvis-mega-brain-v3.md +1305 -0
- package/reference/templates/phase5/IMPLEMENTATION-GUIDE.md +355 -0
- package/reference/templates/phase5/MOGA-BRAIN-PHASE5-TEMPLATES.md +1284 -0
- package/reference/templates/phase5/README.md +165 -0
- package/reference/workflow-claude-code-boris-cherny-continuous-claude.md +2232 -0
- package/system/database/001_moneyclub_buyers.sql +160 -0
- package/system/database/002_premium_token.sql +97 -0
- package/system/database/apply-migration.mjs +129 -0
- package/system/docs/MEGA-BRAIN-DEMO-COMPLETA.md +1226 -0
- package/system/docs/MEGA-BRAIN-MANIFESTO-COMPLETO.md +1054 -0
- package/system/docs/MOGA-BRAIN-EXPLICACAO-COMPLETA.md +791 -0
- package/system/docs/STRATEGIC-INTEGRATION-GUIDE.md +725 -0
- package/system/docs/architecture/01-system-context.md +136 -0
- package/system/docs/architecture/02-components.md +225 -0
- package/system/docs/architecture/03-data-flow.md +235 -0
- package/system/docs/architecture/04-integrations.md +283 -0
- package/system/docs/architecture/README.md +71 -0
- package/system/docs/architecture/diagrams/component-diagram.mmd +50 -0
- package/system/docs/architecture/diagrams/data-flow.mmd +39 -0
- package/system/docs/architecture/diagrams/system-overview.mmd +68 -0
- package/system/protocols/AGENT-AUTHORITY.md +217 -0
- package/system/protocols/CONSTITUICAO-BASE.md +115 -0
- package/system/protocols/CONSTITUTION.md +231 -0
- package/system/protocols/GOVERNANCE-MAP.md +123 -0
- package/system/protocols/HOOK-SECURITY-THREAT-MODEL.md +152 -0
- package/system/protocols/ORQUESTRACAO-PROTOCOL.md +215 -0
- package/system/protocols/_archive/CHUNKING-PROTOCOL.md +207 -0
- package/system/protocols/_archive/ENTITY-RESOLUTION-PROTOCOL.md +269 -0
- package/system/protocols/_archive/INSIGHT-EXTRACTION-PROTOCOL.md +257 -0
- package/system/protocols/_archive/NARRATIVE-SYNTHESIS-PROTOCOL.md +290 -0
- package/system/protocols/agents/AGENT-INTERACTION.md +315 -0
- package/system/protocols/agents/CORTEX-PROTOCOL.md +520 -0
- package/system/protocols/agents/EPISTEMIC-PROTOCOL.md +465 -0
- package/system/protocols/agents/MEMORY-PROTOCOL.md +366 -0
- package/system/protocols/agents/WAR-ROOM.md +355 -0
- package/system/protocols/company/COMPANY-DOCUMENT-PROTOCOL.md +793 -0
- package/system/protocols/company/COMPANY-ENRICHMENT-PROTOCOL.md +679 -0
- package/system/protocols/conclave/CONCLAVE-LOG-TEMPLATE-v2.md +309 -0
- package/system/protocols/conclave/CONCLAVE-PROTOCOL.md +518 -0
- package/system/protocols/conclave/DEBATE-DYNAMICS-CONFIG.yaml +322 -0
- package/system/protocols/conclave/DEBATE-DYNAMICS-PROTOCOL.md +613 -0
- package/system/protocols/conclave/DEBATE-PROTOCOL.md +323 -0
- package/system/protocols/council/COUNCIL-LOG-TEMPLATE-v2.md +309 -0
- package/system/protocols/council/COUNCIL-PROTOCOL.md +518 -0
- package/system/protocols/council/DEBATE-DYNAMICS-CONFIG.yaml +322 -0
- package/system/protocols/council/DEBATE-DYNAMICS-PROTOCOL.md +613 -0
- package/system/protocols/council/DEBATE-PROTOCOL.md +323 -0
- package/system/protocols/dna/DNA-EXTRACTION-PROTOCOL.md +1214 -0
- package/system/protocols/dna/ENRICHMENT-PROTOCOL.md +408 -0
- package/system/protocols/dna/REASONING-MODEL-PROTOCOL.md +331 -0
- package/system/protocols/pipeline/DOSSIER-COMPILATION-PROTOCOL.md +790 -0
- package/system/protocols/pipeline/NARRATIVE-METABOLISM-PROTOCOL.md +292 -0
- package/system/protocols/pipeline/PIPELINE-JARVIS-v2.1.md +606 -0
- package/system/protocols/pipeline/PROMPT-1.1-CHUNKING.md +154 -0
- package/system/protocols/pipeline/PROMPT-1.2-ENTITY-RESOLUTION.md +186 -0
- package/system/protocols/pipeline/PROMPT-2.1-DNA-TAGS-INCREMENT.md +208 -0
- package/system/protocols/pipeline/PROMPT-2.1-INSIGHT-EXTRACTION.md +191 -0
- package/system/protocols/pipeline/PROMPT-3.1-NARRATIVE-SYNTHESIS.md +331 -0
- package/system/protocols/pipeline/SOURCES-COMPILATION-PROTOCOL.md +340 -0
- package/system/protocols/system/AUTO-LOG-PROTOCOL.md +369 -0
- package/system/protocols/system/CHECKPOINT-ENFORCEMENT.md +176 -0
- package/system/protocols/system/ENFORCEMENT.md +435 -0
- package/system/protocols/system/LOG-TEMPLATES.md +1068 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Post Output Validator - Layer 1 do META-AGENT System v1.0
|
|
4
|
+
|
|
5
|
+
FUNÇÃO: Valida compliance do output vs especificação do agente.
|
|
6
|
+
AVISA sobre gaps mas NÃO BLOQUEIA entrega.
|
|
7
|
+
|
|
8
|
+
REGRA #28: META-AGENT QUALITY AWARENESS (WARN, NOT BLOCK)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import re
|
|
13
|
+
import json
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
from typing import List, Dict, Optional
|
|
17
|
+
|
|
18
|
+
PROJECT_ROOT = Path(os.environ.get('CLAUDE_PROJECT_DIR', '.'))
|
|
19
|
+
LOGS_PATH = PROJECT_ROOT / "logs"
|
|
20
|
+
VALIDATION_LOG = LOGS_PATH / "output_validations.jsonl"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
24
|
+
# QUALITY MARKERS
|
|
25
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
26
|
+
|
|
27
|
+
# Marcadores padrão para outputs visuais (usado por CHRONICLER e similares)
|
|
28
|
+
VISUAL_MARKERS = [
|
|
29
|
+
{
|
|
30
|
+
"name": "ASCII Header",
|
|
31
|
+
"pattern": r"╔═+.*═+╗",
|
|
32
|
+
"weight": 10,
|
|
33
|
+
"description": "Cabeçalho com bordas duplas"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "Progress Bar",
|
|
37
|
+
"pattern": r"[█▓░]{5,}|████+",
|
|
38
|
+
"weight": 10,
|
|
39
|
+
"description": "Barras de progresso visuais"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "Metrics Panel",
|
|
43
|
+
"pattern": r"┌─.*(?:MÉTRICA|PAINEL|MÉTRICAS)",
|
|
44
|
+
"weight": 10,
|
|
45
|
+
"description": "Painel de métricas estruturado"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "Changes Section",
|
|
49
|
+
"pattern": r"O QUE MUDOU|NOVIDADES|MUDANÇAS",
|
|
50
|
+
"weight": 15,
|
|
51
|
+
"description": "Seção de mudanças/novidades"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "Personal Notes",
|
|
55
|
+
"pattern": r"NOTAS DO|OBSERVAÇÕES|— \w+$",
|
|
56
|
+
"weight": 10,
|
|
57
|
+
"description": "Notas pessoais do agente"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "ASCII Boxes",
|
|
61
|
+
"pattern": r"[┌┐└┘├┤│─┬┴┼]{3,}",
|
|
62
|
+
"weight": 5,
|
|
63
|
+
"description": "Caixas ASCII estruturadas"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "Explanations",
|
|
67
|
+
"pattern": r"\[[^\]]{10,}\]",
|
|
68
|
+
"weight": 5,
|
|
69
|
+
"description": "Explicações entre colchetes"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"name": "Section Dividers",
|
|
73
|
+
"pattern": r"[═─━]{10,}",
|
|
74
|
+
"weight": 5,
|
|
75
|
+
"description": "Divisores de seção"
|
|
76
|
+
},
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
# Marcadores para outputs analíticos
|
|
80
|
+
ANALYTICAL_MARKERS = [
|
|
81
|
+
{
|
|
82
|
+
"name": "Data Points",
|
|
83
|
+
"pattern": r"\d+[%,.]?\d*",
|
|
84
|
+
"weight": 5,
|
|
85
|
+
"description": "Números e porcentagens"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"name": "Bullet Points",
|
|
89
|
+
"pattern": r"^[\s]*[-•*]\s",
|
|
90
|
+
"weight": 3,
|
|
91
|
+
"description": "Lista com bullets"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"name": "Headers",
|
|
95
|
+
"pattern": r"^#{1,3}\s",
|
|
96
|
+
"weight": 3,
|
|
97
|
+
"description": "Headers markdown"
|
|
98
|
+
},
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
103
|
+
# QUALITY SCORING
|
|
104
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
105
|
+
|
|
106
|
+
def calculate_quality_score(
|
|
107
|
+
output: str,
|
|
108
|
+
markers: List[Dict] = None,
|
|
109
|
+
agent_type: str = "visual"
|
|
110
|
+
) -> Dict:
|
|
111
|
+
"""
|
|
112
|
+
Calcula score de qualidade do output.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
output: Texto do output a validar
|
|
116
|
+
markers: Lista de marcadores customizados (opcional)
|
|
117
|
+
agent_type: "visual" ou "analytical" para selecionar marcadores
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
dict com score, passing, details, missing
|
|
121
|
+
"""
|
|
122
|
+
if markers is None:
|
|
123
|
+
markers = VISUAL_MARKERS if agent_type == "visual" else ANALYTICAL_MARKERS
|
|
124
|
+
|
|
125
|
+
score = 0
|
|
126
|
+
max_score = sum(m["weight"] for m in markers)
|
|
127
|
+
details = []
|
|
128
|
+
missing = []
|
|
129
|
+
found = []
|
|
130
|
+
|
|
131
|
+
for marker in markers:
|
|
132
|
+
pattern = marker["pattern"]
|
|
133
|
+
weight = marker["weight"]
|
|
134
|
+
name = marker["name"]
|
|
135
|
+
|
|
136
|
+
if re.search(pattern, output, re.IGNORECASE | re.MULTILINE):
|
|
137
|
+
score += weight
|
|
138
|
+
details.append(f"✅ {name}: +{weight}")
|
|
139
|
+
found.append(name)
|
|
140
|
+
else:
|
|
141
|
+
missing.append(name)
|
|
142
|
+
details.append(f"❌ {name}: 0")
|
|
143
|
+
|
|
144
|
+
# Normaliza para 100
|
|
145
|
+
normalized_score = int((score / max_score) * 100) if max_score > 0 else 0
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
"score": normalized_score,
|
|
149
|
+
"raw_score": score,
|
|
150
|
+
"max_score": max_score,
|
|
151
|
+
"passing": normalized_score >= 70,
|
|
152
|
+
"details": details,
|
|
153
|
+
"missing": missing,
|
|
154
|
+
"found": found,
|
|
155
|
+
"markers_checked": len(markers)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def validate_output(output: str, agent_name: str, agent_type: str = "visual") -> Dict:
|
|
160
|
+
"""
|
|
161
|
+
Valida output completo. AVISA mas NÃO BLOQUEIA.
|
|
162
|
+
|
|
163
|
+
Esta é a função principal chamada após geração de output.
|
|
164
|
+
MODIFICAÇÃO CRÍTICA: action = "warn" em vez de "block"
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
output: Texto do output gerado
|
|
168
|
+
agent_name: Nome do agente que gerou
|
|
169
|
+
agent_type: Tipo do agente ("visual", "analytical")
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
dict com resultado da validação
|
|
173
|
+
"""
|
|
174
|
+
result = calculate_quality_score(output, agent_type=agent_type)
|
|
175
|
+
|
|
176
|
+
result["agent"] = agent_name
|
|
177
|
+
result["agent_type"] = agent_type
|
|
178
|
+
result["timestamp"] = datetime.now().isoformat()
|
|
179
|
+
|
|
180
|
+
if not result["passing"]:
|
|
181
|
+
# MODIFICAÇÃO: Avisa em vez de bloquear
|
|
182
|
+
result["warning"] = (
|
|
183
|
+
f"⚠️ Quality score: {result['score']}/100\n"
|
|
184
|
+
f"Missing elements: {', '.join(result['missing'])}\n"
|
|
185
|
+
f"Consider adding these elements for better quality."
|
|
186
|
+
)
|
|
187
|
+
result["action"] = "warn" # NÃO "block"
|
|
188
|
+
result["recommendation"] = "Output delivered with quality warning"
|
|
189
|
+
else:
|
|
190
|
+
result["action"] = "pass"
|
|
191
|
+
result["recommendation"] = "Output quality acceptable"
|
|
192
|
+
|
|
193
|
+
# Log validation
|
|
194
|
+
log_validation(result)
|
|
195
|
+
|
|
196
|
+
return result
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def validate_against_spec(output: str, spec: str, agent_name: str) -> Dict:
|
|
200
|
+
"""
|
|
201
|
+
Valida output contra especificação customizada.
|
|
202
|
+
|
|
203
|
+
Para casos onde MANDATORY_SECTIONS define requisitos específicos.
|
|
204
|
+
"""
|
|
205
|
+
result = {
|
|
206
|
+
"agent": agent_name,
|
|
207
|
+
"timestamp": datetime.now().isoformat(),
|
|
208
|
+
"spec_based": True,
|
|
209
|
+
"requirements_met": [],
|
|
210
|
+
"requirements_missing": []
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# Extrai requisitos da spec
|
|
214
|
+
requirements = extract_requirements_from_spec(spec)
|
|
215
|
+
|
|
216
|
+
score = 0
|
|
217
|
+
for req in requirements:
|
|
218
|
+
if re.search(req["pattern"], output, re.IGNORECASE | re.DOTALL):
|
|
219
|
+
result["requirements_met"].append(req["name"])
|
|
220
|
+
score += req.get("weight", 10)
|
|
221
|
+
else:
|
|
222
|
+
result["requirements_missing"].append(req["name"])
|
|
223
|
+
|
|
224
|
+
max_score = sum(r.get("weight", 10) for r in requirements)
|
|
225
|
+
result["score"] = int((score / max_score) * 100) if max_score > 0 else 100
|
|
226
|
+
result["passing"] = result["score"] >= 70
|
|
227
|
+
|
|
228
|
+
if not result["passing"]:
|
|
229
|
+
result["action"] = "warn"
|
|
230
|
+
result["warning"] = f"Score: {result['score']}. Missing: {result['requirements_missing']}"
|
|
231
|
+
else:
|
|
232
|
+
result["action"] = "pass"
|
|
233
|
+
|
|
234
|
+
return result
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def extract_requirements_from_spec(spec: str) -> List[Dict]:
|
|
238
|
+
"""
|
|
239
|
+
Extrai requisitos de uma spec MANDATORY_SECTIONS.
|
|
240
|
+
|
|
241
|
+
Formato esperado na spec:
|
|
242
|
+
| Section | Required | Marker | Example |
|
|
243
|
+
"""
|
|
244
|
+
requirements = []
|
|
245
|
+
|
|
246
|
+
# Tenta extrair da tabela markdown
|
|
247
|
+
table_pattern = r'\|\s*([^|]+)\s*\|\s*YES\s*\|\s*`([^`]+)`\s*\|'
|
|
248
|
+
matches = re.findall(table_pattern, spec, re.IGNORECASE)
|
|
249
|
+
|
|
250
|
+
for name, marker in matches:
|
|
251
|
+
requirements.append({
|
|
252
|
+
"name": name.strip(),
|
|
253
|
+
"pattern": re.escape(marker.strip()),
|
|
254
|
+
"weight": 10
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
# Se não encontrou tabela, usa marcadores padrão
|
|
258
|
+
if not requirements:
|
|
259
|
+
return [{"name": "default", "pattern": ".", "weight": 100}]
|
|
260
|
+
|
|
261
|
+
return requirements
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
265
|
+
# LOGGING
|
|
266
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
267
|
+
|
|
268
|
+
def log_validation(result: Dict):
|
|
269
|
+
"""Loga resultado da validação."""
|
|
270
|
+
VALIDATION_LOG.parent.mkdir(parents=True, exist_ok=True)
|
|
271
|
+
|
|
272
|
+
entry = {
|
|
273
|
+
"timestamp": result.get("timestamp", datetime.now().isoformat()),
|
|
274
|
+
"agent": result.get("agent", "unknown"),
|
|
275
|
+
"score": result.get("score", 0),
|
|
276
|
+
"passing": result.get("passing", False),
|
|
277
|
+
"action": result.get("action", "unknown"),
|
|
278
|
+
"missing": result.get("missing", []),
|
|
279
|
+
"found": result.get("found", [])
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
try:
|
|
283
|
+
with open(VALIDATION_LOG, "a", encoding='utf-8') as f:
|
|
284
|
+
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
|
|
285
|
+
except Exception:
|
|
286
|
+
pass # Falha silenciosa
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
290
|
+
# INTEGRATION HELPERS
|
|
291
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
292
|
+
|
|
293
|
+
def should_trigger_doctor(result: Dict, threshold: int = 50) -> bool:
|
|
294
|
+
"""
|
|
295
|
+
Determina se deve acionar o DOCTOR (Layer 2) para propor fixes.
|
|
296
|
+
|
|
297
|
+
Threshold mais baixo (50) aciona propostas de melhoria.
|
|
298
|
+
Threshold 70 é apenas warning.
|
|
299
|
+
"""
|
|
300
|
+
return result.get("score", 100) < threshold
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def format_warning_message(result: Dict) -> str:
|
|
304
|
+
"""Formata mensagem de warning para exibição."""
|
|
305
|
+
if result.get("action") == "pass":
|
|
306
|
+
return ""
|
|
307
|
+
|
|
308
|
+
return f"""
|
|
309
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
310
|
+
│ ⚠️ QUALITY WARNING │
|
|
311
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
312
|
+
│ Agent: {result.get('agent', 'unknown'):<54} │
|
|
313
|
+
│ Score: {result.get('score', 0)}/100 {'(PASSING)' if result.get('passing') else '(BELOW THRESHOLD)':>43} │
|
|
314
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
315
|
+
│ Missing: {', '.join(result.get('missing', []))[:53]:<53} │
|
|
316
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
317
|
+
"""
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
321
|
+
# CLI INTERFACE
|
|
322
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
323
|
+
|
|
324
|
+
if __name__ == "__main__":
|
|
325
|
+
# Test output
|
|
326
|
+
test_output = """
|
|
327
|
+
╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
328
|
+
║ ALEX HORMOZI - DNA CONSOLIDADO ║
|
|
329
|
+
╚═══════════════════════════════════════════════════════════════════════════════╝
|
|
330
|
+
|
|
331
|
+
┌─ MÉTRICAS ─────────────────────────────────────────────────────────────────────┐
|
|
332
|
+
│ Total elementos: 260 │
|
|
333
|
+
│ Progresso: ████████████████████░░░░░░░░░░░░░░░░░░░░ 50% │
|
|
334
|
+
└────────────────────────────────────────────────────────────────────────────────┘
|
|
335
|
+
|
|
336
|
+
O QUE MUDOU DESDE O ÚLTIMO LOG:
|
|
337
|
+
- Adicionados 30 novos frameworks
|
|
338
|
+
- Atualizado DNA-CONFIG.yaml
|
|
339
|
+
|
|
340
|
+
NOTAS DO CHRONICLER:
|
|
341
|
+
"O conhecimento do Hormozi está consolidando bem."
|
|
342
|
+
|
|
343
|
+
— Chronicler
|
|
344
|
+
"""
|
|
345
|
+
|
|
346
|
+
result = validate_output(test_output, "chronicler", "visual")
|
|
347
|
+
|
|
348
|
+
print(f"Score: {result['score']}/100")
|
|
349
|
+
print(f"Passing: {result['passing']}")
|
|
350
|
+
print(f"Action: {result['action']}")
|
|
351
|
+
print(f"\nDetails:")
|
|
352
|
+
for detail in result['details']:
|
|
353
|
+
print(f" {detail}")
|
|
354
|
+
|
|
355
|
+
if result.get('warning'):
|
|
356
|
+
print(f"\n{result['warning']}")
|
|
357
|
+
|
|
358
|
+
print(format_warning_message(result))
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
JARVIS Post Tool Use Hook
|
|
4
|
+
Executado após Claude Code usar uma ferramenta de edição/escrita.
|
|
5
|
+
|
|
6
|
+
Responsabilidades:
|
|
7
|
+
1. Registrar arquivos modificados
|
|
8
|
+
2. Detectar padrões
|
|
9
|
+
3. Sugerir melhorias quando apropriado
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import sys
|
|
14
|
+
import os
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
def get_project_dir():
|
|
19
|
+
"""Obtém o diretório do projeto."""
|
|
20
|
+
return os.environ.get('CLAUDE_PROJECT_DIR', os.getcwd())
|
|
21
|
+
|
|
22
|
+
def load_actions_log():
|
|
23
|
+
"""Carrega log de ações."""
|
|
24
|
+
project_dir = get_project_dir()
|
|
25
|
+
log_path = Path(project_dir) / 'logs' / 'actions.json'
|
|
26
|
+
|
|
27
|
+
if log_path.exists():
|
|
28
|
+
with open(log_path, 'r', encoding='utf-8') as f:
|
|
29
|
+
return json.load(f)
|
|
30
|
+
return {'actions': []}
|
|
31
|
+
|
|
32
|
+
def save_actions_log(log):
|
|
33
|
+
"""Salva log de ações."""
|
|
34
|
+
project_dir = get_project_dir()
|
|
35
|
+
log_path = Path(project_dir) / 'logs' / 'actions.json'
|
|
36
|
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
37
|
+
|
|
38
|
+
# Manter apenas últimas 100 ações
|
|
39
|
+
log['actions'] = log['actions'][-100:]
|
|
40
|
+
|
|
41
|
+
with open(log_path, 'w', encoding='utf-8') as f:
|
|
42
|
+
json.dump(log, f, indent=2, ensure_ascii=False)
|
|
43
|
+
|
|
44
|
+
def detect_patterns(actions):
|
|
45
|
+
"""Detecta padrões nas ações recentes."""
|
|
46
|
+
if len(actions) < 3:
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
# Verificar se mesmo arquivo foi editado múltiplas vezes
|
|
50
|
+
recent = actions[-10:]
|
|
51
|
+
file_counts = {}
|
|
52
|
+
for action in recent:
|
|
53
|
+
file_path = action.get('file_path', '')
|
|
54
|
+
if file_path:
|
|
55
|
+
file_counts[file_path] = file_counts.get(file_path, 0) + 1
|
|
56
|
+
|
|
57
|
+
# Se algum arquivo foi editado 3+ vezes
|
|
58
|
+
repeated = [f for f, c in file_counts.items() if c >= 3]
|
|
59
|
+
if repeated:
|
|
60
|
+
return {
|
|
61
|
+
'type': 'repeated_edits',
|
|
62
|
+
'files': repeated,
|
|
63
|
+
'suggestion': 'Arquivo editado múltiplas vezes. Considerar refatoração.'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
def main():
|
|
69
|
+
"""Função principal do hook."""
|
|
70
|
+
try:
|
|
71
|
+
# Ler input do hook (stdin)
|
|
72
|
+
input_data = sys.stdin.read()
|
|
73
|
+
hook_input = json.loads(input_data) if input_data else {}
|
|
74
|
+
|
|
75
|
+
# Extrair informações da ferramenta
|
|
76
|
+
tool_name = hook_input.get('tool_name', 'unknown')
|
|
77
|
+
tool_input = hook_input.get('tool_input', {})
|
|
78
|
+
|
|
79
|
+
file_path = tool_input.get('file_path', '')
|
|
80
|
+
|
|
81
|
+
# Carregar log
|
|
82
|
+
log = load_actions_log()
|
|
83
|
+
|
|
84
|
+
# Registrar ação
|
|
85
|
+
action = {
|
|
86
|
+
'timestamp': datetime.now().isoformat(),
|
|
87
|
+
'tool': tool_name,
|
|
88
|
+
'file_path': file_path,
|
|
89
|
+
'session_id': hook_input.get('session_id', 'unknown')
|
|
90
|
+
}
|
|
91
|
+
log['actions'].append(action)
|
|
92
|
+
|
|
93
|
+
# Salvar log
|
|
94
|
+
save_actions_log(log)
|
|
95
|
+
|
|
96
|
+
# Detectar padrões
|
|
97
|
+
pattern = detect_patterns(log['actions'])
|
|
98
|
+
|
|
99
|
+
# Preparar feedback
|
|
100
|
+
feedback = None
|
|
101
|
+
if pattern:
|
|
102
|
+
feedback = f"[JARVIS] Padrão detectado: {pattern['suggestion']}"
|
|
103
|
+
|
|
104
|
+
output = {
|
|
105
|
+
'continue': True,
|
|
106
|
+
'feedback': feedback
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
print(json.dumps(output))
|
|
110
|
+
|
|
111
|
+
except Exception as e:
|
|
112
|
+
# Em caso de erro, não bloquear a operação
|
|
113
|
+
error_output = {
|
|
114
|
+
'continue': True,
|
|
115
|
+
'feedback': None
|
|
116
|
+
}
|
|
117
|
+
print(json.dumps(error_output))
|
|
118
|
+
|
|
119
|
+
if __name__ == '__main__':
|
|
120
|
+
main()
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
POST-WRITE VALIDATOR HOOK
|
|
4
|
+
=========================
|
|
5
|
+
Valida automaticamente arquivos criados/editados.
|
|
6
|
+
|
|
7
|
+
Baseado no workflow Boris Cherny: "give Claude a way to verify its work"
|
|
8
|
+
|
|
9
|
+
Triggers:
|
|
10
|
+
- Após Write de BATCH-*.md → Valida estrutura do batch
|
|
11
|
+
- Após Write de AGENT.md → Valida template V3
|
|
12
|
+
- Após Write de SOUL.md → Valida rastreabilidade
|
|
13
|
+
- Após Write de DNA-CONFIG.yaml → Valida estrutura
|
|
14
|
+
|
|
15
|
+
Output:
|
|
16
|
+
- Se válido: exit 0 (silencioso)
|
|
17
|
+
- Se inválido: print erros para Claude corrigir
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import sys
|
|
21
|
+
import os
|
|
22
|
+
import json
|
|
23
|
+
import re
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from datetime import datetime
|
|
26
|
+
|
|
27
|
+
# Paths
|
|
28
|
+
PROJECT_ROOT = Path(os.environ.get('CLAUDE_PROJECT_DIR', '.'))
|
|
29
|
+
LOGS_PATH = PROJECT_ROOT / 'logs' / 'validation'
|
|
30
|
+
LOGS_PATH.mkdir(parents=True, exist_ok=True)
|
|
31
|
+
|
|
32
|
+
def log_validation(file_path: str, file_type: str, is_valid: bool, errors: list):
|
|
33
|
+
"""Log validation result"""
|
|
34
|
+
log_file = LOGS_PATH / 'validation.jsonl'
|
|
35
|
+
entry = {
|
|
36
|
+
'timestamp': datetime.now().isoformat(),
|
|
37
|
+
'file': file_path,
|
|
38
|
+
'type': file_type,
|
|
39
|
+
'valid': is_valid,
|
|
40
|
+
'errors': errors
|
|
41
|
+
}
|
|
42
|
+
with open(log_file, 'a') as f:
|
|
43
|
+
f.write(json.dumps(entry) + '\n')
|
|
44
|
+
|
|
45
|
+
def validate_batch(content: str, file_path: str) -> tuple[bool, list]:
|
|
46
|
+
"""Validate BATCH-*.md structure"""
|
|
47
|
+
errors = []
|
|
48
|
+
|
|
49
|
+
# Required sections
|
|
50
|
+
required_sections = [
|
|
51
|
+
('ASCII ART HEADER', r'[╔═╗║╚]'),
|
|
52
|
+
('CONTEXTO DA MISSÃO', r'CONTEXTO DA MISS[ÃA]O|MISSION CONTEXT'),
|
|
53
|
+
('BATCH SUMMARY', r'BATCH SUMMARY|RESUMO DO BATCH'),
|
|
54
|
+
('ARQUIVOS PROCESSADOS', r'ARQUIVOS PROCESSADOS|FILES PROCESSED'),
|
|
55
|
+
('DESTINO DO CONHECIMENTO', r'DESTINO DO CONHECIMENTO|KNOWLEDGE DESTINATION'),
|
|
56
|
+
('KEY FRAMEWORKS', r'KEY FRAMEWORKS|FRAMEWORKS'),
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
for section_name, pattern in required_sections:
|
|
60
|
+
if not re.search(pattern, content, re.IGNORECASE):
|
|
61
|
+
errors.append(f"Missing section: {section_name}")
|
|
62
|
+
|
|
63
|
+
# Check for cascading section (REGRA #22)
|
|
64
|
+
if 'Cascateamento Executado' not in content and 'CASCATEAMENTO' not in content.upper():
|
|
65
|
+
errors.append("Missing section: Cascateamento Executado (REGRA #22)")
|
|
66
|
+
|
|
67
|
+
# Check for DNA layers
|
|
68
|
+
dna_layers = ['FILOSOFIA', 'MODELO-MENTAL', 'HEURISTICA', 'FRAMEWORK', 'METODOLOGIA']
|
|
69
|
+
found_layers = sum(1 for layer in dna_layers if layer in content.upper())
|
|
70
|
+
if found_layers < 3:
|
|
71
|
+
errors.append(f"Only {found_layers}/5 DNA layers found. Expected at least 3.")
|
|
72
|
+
|
|
73
|
+
is_valid = len(errors) == 0
|
|
74
|
+
log_validation(file_path, 'BATCH', is_valid, errors)
|
|
75
|
+
return is_valid, errors
|
|
76
|
+
|
|
77
|
+
def validate_agent(content: str, file_path: str) -> tuple[bool, list]:
|
|
78
|
+
"""Validate AGENT.md template V3 structure"""
|
|
79
|
+
errors = []
|
|
80
|
+
|
|
81
|
+
# Required parts from Template V3
|
|
82
|
+
required_parts = [
|
|
83
|
+
('PARTE 0: ÍNDICE', r'PARTE 0|ÍNDICE|INDEX'),
|
|
84
|
+
('PARTE 1: COMPOSIÇÃO', r'PARTE 1|COMPOSI[ÇC][ÃA]O'),
|
|
85
|
+
('PARTE 3: MAPA NEURAL', r'PARTE 3|MAPA NEURAL|DNA'),
|
|
86
|
+
('PARTE 5: SISTEMA DE VOZ', r'PARTE 5|VOZ|VOICE'),
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
for part_name, pattern in required_parts:
|
|
90
|
+
if not re.search(pattern, content, re.IGNORECASE):
|
|
91
|
+
errors.append(f"Missing: {part_name}")
|
|
92
|
+
|
|
93
|
+
# Check for ASCII header
|
|
94
|
+
if not re.search(r'[╔═╗║╚]', content):
|
|
95
|
+
errors.append("Missing ASCII art header")
|
|
96
|
+
|
|
97
|
+
# Check for version
|
|
98
|
+
if not re.search(r'[Vv]ers[ãa]o|Version', content):
|
|
99
|
+
errors.append("Missing version declaration")
|
|
100
|
+
|
|
101
|
+
# Check for sources/fontes
|
|
102
|
+
if not re.search(r'[Ff]ontes?|[Ss]ources?', content):
|
|
103
|
+
errors.append("Missing source attribution")
|
|
104
|
+
|
|
105
|
+
is_valid = len(errors) == 0
|
|
106
|
+
log_validation(file_path, 'AGENT', is_valid, errors)
|
|
107
|
+
return is_valid, errors
|
|
108
|
+
|
|
109
|
+
def validate_soul(content: str, file_path: str) -> tuple[bool, list]:
|
|
110
|
+
"""Validate SOUL.md rastreabilidade"""
|
|
111
|
+
errors = []
|
|
112
|
+
|
|
113
|
+
# Check for source citations
|
|
114
|
+
citation_patterns = [
|
|
115
|
+
r'\^\[FONTE:',
|
|
116
|
+
r'\^\[chunk_id',
|
|
117
|
+
r'\^\[insight_id',
|
|
118
|
+
r'\^\[RAIZ:',
|
|
119
|
+
r'\[FONTE:',
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
has_citations = any(re.search(p, content) for p in citation_patterns)
|
|
123
|
+
if not has_citations:
|
|
124
|
+
errors.append("No traceable citations found (REGRA #24 requires ^[FONTE:] or similar)")
|
|
125
|
+
|
|
126
|
+
# Check for DNA layers
|
|
127
|
+
if not re.search(r'FILOSOFIA|MODELO.MENTAL|HEURISTICA|FRAMEWORK|METODOLOGIA', content, re.IGNORECASE):
|
|
128
|
+
errors.append("No DNA layers referenced")
|
|
129
|
+
|
|
130
|
+
is_valid = len(errors) == 0
|
|
131
|
+
log_validation(file_path, 'SOUL', is_valid, errors)
|
|
132
|
+
return is_valid, errors
|
|
133
|
+
|
|
134
|
+
def validate_dna_config(content: str, file_path: str) -> tuple[bool, list]:
|
|
135
|
+
"""Validate DNA-CONFIG.yaml structure"""
|
|
136
|
+
errors = []
|
|
137
|
+
|
|
138
|
+
# Required fields
|
|
139
|
+
required_fields = ['name', 'type', 'version']
|
|
140
|
+
for field in required_fields:
|
|
141
|
+
if f'{field}:' not in content.lower():
|
|
142
|
+
errors.append(f"Missing required field: {field}")
|
|
143
|
+
|
|
144
|
+
# Check for layers
|
|
145
|
+
layers = ['filosofias', 'modelos_mentais', 'heuristicas', 'frameworks', 'metodologias']
|
|
146
|
+
found_layers = sum(1 for layer in layers if layer in content.lower())
|
|
147
|
+
if found_layers < 3:
|
|
148
|
+
errors.append(f"Only {found_layers}/5 DNA layers defined")
|
|
149
|
+
|
|
150
|
+
is_valid = len(errors) == 0
|
|
151
|
+
log_validation(file_path, 'DNA_CONFIG', is_valid, errors)
|
|
152
|
+
return is_valid, errors
|
|
153
|
+
|
|
154
|
+
def main():
|
|
155
|
+
"""Main validation dispatcher"""
|
|
156
|
+
if len(sys.argv) < 2:
|
|
157
|
+
sys.exit(0)
|
|
158
|
+
|
|
159
|
+
file_path = sys.argv[1]
|
|
160
|
+
|
|
161
|
+
# Skip if file doesn't exist or is not relevant
|
|
162
|
+
if not os.path.exists(file_path):
|
|
163
|
+
sys.exit(0)
|
|
164
|
+
|
|
165
|
+
filename = os.path.basename(file_path).upper()
|
|
166
|
+
|
|
167
|
+
# Determine file type and validate
|
|
168
|
+
try:
|
|
169
|
+
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
170
|
+
content = f.read()
|
|
171
|
+
except Exception:
|
|
172
|
+
sys.exit(0)
|
|
173
|
+
|
|
174
|
+
is_valid = True
|
|
175
|
+
errors = []
|
|
176
|
+
|
|
177
|
+
if 'BATCH-' in filename and filename.endswith('.MD'):
|
|
178
|
+
is_valid, errors = validate_batch(content, file_path)
|
|
179
|
+
elif filename == 'AGENT.MD':
|
|
180
|
+
is_valid, errors = validate_agent(content, file_path)
|
|
181
|
+
elif filename == 'SOUL.MD':
|
|
182
|
+
is_valid, errors = validate_soul(content, file_path)
|
|
183
|
+
elif 'DNA-CONFIG' in filename and filename.endswith('.YAML'):
|
|
184
|
+
is_valid, errors = validate_dna_config(content, file_path)
|
|
185
|
+
else:
|
|
186
|
+
# Not a file we validate
|
|
187
|
+
sys.exit(0)
|
|
188
|
+
|
|
189
|
+
# Output for Claude to see
|
|
190
|
+
if not is_valid:
|
|
191
|
+
print(f"\n⚠️ VALIDATION FAILED for {os.path.basename(file_path)}:")
|
|
192
|
+
for error in errors:
|
|
193
|
+
print(f" ❌ {error}")
|
|
194
|
+
print("\nPlease fix these issues before proceeding.\n")
|
|
195
|
+
# Exit 0 anyway to not block, but Claude sees the output
|
|
196
|
+
|
|
197
|
+
sys.exit(0)
|
|
198
|
+
|
|
199
|
+
if __name__ == '__main__':
|
|
200
|
+
main()
|