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.

Files changed (308) hide show
  1. package/.claude/CLAUDE.md +155 -0
  2. package/.claude/commands/agents.md +161 -0
  3. package/.claude/commands/ask.md +117 -0
  4. package/.claude/commands/benchmark.md +224 -0
  5. package/.claude/commands/chat.md +343 -0
  6. package/.claude/commands/compare.md +116 -0
  7. package/.claude/commands/conclave.md +194 -0
  8. package/.claude/commands/config.md +133 -0
  9. package/.claude/commands/council.md +194 -0
  10. package/.claude/commands/create-agent.md +452 -0
  11. package/.claude/commands/debate.md +157 -0
  12. package/.claude/commands/documentation/create-architecture-documentation.md +175 -0
  13. package/.claude/commands/dossiers.md +180 -0
  14. package/.claude/commands/evolve.md +223 -0
  15. package/.claude/commands/extract-dna.md +170 -0
  16. package/.claude/commands/extract-knowledge.md +507 -0
  17. package/.claude/commands/inbox.md +296 -0
  18. package/.claude/commands/ingest-empresa.md +191 -0
  19. package/.claude/commands/ingest.md +182 -0
  20. package/.claude/commands/jarvis-briefing.md +67 -0
  21. package/.claude/commands/jarvis-control.md +169 -0
  22. package/.claude/commands/jarvis-full.md +181 -0
  23. package/.claude/commands/jarvis.md +212 -0
  24. package/.claude/commands/ler-drive.md +212 -0
  25. package/.claude/commands/log.md +158 -0
  26. package/.claude/commands/loop.md +133 -0
  27. package/.claude/commands/loops.md +73 -0
  28. package/.claude/commands/mission-autopilot.md +538 -0
  29. package/.claude/commands/mission.md +353 -0
  30. package/.claude/commands/process-inbox.md +148 -0
  31. package/.claude/commands/process-jarvis.md +3036 -0
  32. package/.claude/commands/process-video.md +131 -0
  33. package/.claude/commands/rag-search.md +78 -0
  34. package/.claude/commands/resume.md +33 -0
  35. package/.claude/commands/save.md +38 -0
  36. package/.claude/commands/scan-inbox.md +125 -0
  37. package/.claude/commands/setup.md +99 -0
  38. package/.claude/commands/system-digest.md +243 -0
  39. package/.claude/commands/verify.md +182 -0
  40. package/.claude/commands/view-dna.md +169 -0
  41. package/.claude/hooks/agent_doctor.py +433 -0
  42. package/.claude/hooks/agent_memory_persister.py +203 -0
  43. package/.claude/hooks/auto_formatter.py +158 -0
  44. package/.claude/hooks/checkpoint_writer.py +244 -0
  45. package/.claude/hooks/claude_md_guard.py +146 -0
  46. package/.claude/hooks/creation_validator.py +357 -0
  47. package/.claude/hooks/enforce_dual_location.py +501 -0
  48. package/.claude/hooks/enforce_plan_mode.py +220 -0
  49. package/.claude/hooks/inbox_age_alert.py +367 -0
  50. package/.claude/hooks/jarvis_briefing.py +506 -0
  51. package/.claude/hooks/ledger_updater.py +301 -0
  52. package/.claude/hooks/memory_hints_injector.py +251 -0
  53. package/.claude/hooks/memory_updater.py +202 -0
  54. package/.claude/hooks/multi_agent_hook.py +464 -0
  55. package/.claude/hooks/notification_system.py +120 -0
  56. package/.claude/hooks/pattern_analyzer.py +526 -0
  57. package/.claude/hooks/pending_tracker.py +188 -0
  58. package/.claude/hooks/post_batch_cascading.py +1740 -0
  59. package/.claude/hooks/post_output_validator.py +358 -0
  60. package/.claude/hooks/post_tool_use.py +120 -0
  61. package/.claude/hooks/post_write_validator.py +200 -0
  62. package/.claude/hooks/quality_watchdog.py +394 -0
  63. package/.claude/hooks/ralph_wiggum.py +277 -0
  64. package/.claude/hooks/session-source-sync.py +218 -0
  65. package/.claude/hooks/session_autosave_v2.py +1135 -0
  66. package/.claude/hooks/session_end.py +203 -0
  67. package/.claude/hooks/session_start.py +939 -0
  68. package/.claude/hooks/skill_indexer.py +48 -0
  69. package/.claude/hooks/skill_router.py +358 -0
  70. package/.claude/hooks/stop_hook_completeness.py +178 -0
  71. package/.claude/hooks/subagent_tracker.py +163 -0
  72. package/.claude/hooks/token_checkpoint.py +584 -0
  73. package/.claude/hooks/user_prompt_submit.py +125 -0
  74. package/.claude/rules/ANTHROPIC-STANDARDS.md +384 -0
  75. package/.claude/rules/CLAUDE-LITE.md +201 -0
  76. package/.claude/rules/RULE-GROUP-1.md +320 -0
  77. package/.claude/rules/RULE-GROUP-2.md +307 -0
  78. package/.claude/rules/RULE-GROUP-3.md +248 -0
  79. package/.claude/rules/RULE-GROUP-4.md +427 -0
  80. package/.claude/rules/RULE-GROUP-5.md +388 -0
  81. package/.claude/rules/RULE-GROUP-6.md +387 -0
  82. package/.claude/rules/logging.md +53 -0
  83. package/.claude/rules/mcp-governance.md +128 -0
  84. package/.claude/rules/pipeline.md +60 -0
  85. package/.claude/rules/state-management.md +93 -0
  86. package/.claude/scripts/apply-tags.py +77 -0
  87. package/.claude/scripts/batch-extract-transcriptions.py +132 -0
  88. package/.claude/scripts/build-complete-index.py +250 -0
  89. package/.claude/scripts/build-planilha-index.py +170 -0
  90. package/.claude/scripts/complete-tag-matching.py +250 -0
  91. package/.claude/scripts/deduplicate-inbox.py +139 -0
  92. package/.claude/scripts/docx-xml-extractor.py +141 -0
  93. package/.claude/scripts/extract-docx-text.py +58 -0
  94. package/.claude/scripts/extract-single-transcription.py +74 -0
  95. package/.claude/scripts/extract_docx_from_gdrive.py +77 -0
  96. package/.claude/scripts/organized-downloader.py +246 -0
  97. package/.claude/scripts/planilha-tagger.py +187 -0
  98. package/.claude/scripts/revert-tags.py +70 -0
  99. package/.claude/scripts/source-sync.py +265 -0
  100. package/.claude/scripts/tag-inbox-files.py +276 -0
  101. package/.claude/scripts/tag-inbox-v2.py +253 -0
  102. package/.claude/scripts/test-extraction.py +35 -0
  103. package/.claude/scripts/test-full-extraction.py +74 -0
  104. package/.claude/skills/00-SKILL-CREATOR/SKILL.md +186 -0
  105. package/.claude/skills/01-SKILL-DOCS-MEGABRAIN/SKILL.md +251 -0
  106. package/.claude/skills/02-SKILL-PYTHON-MEGABRAIN/SKILL.md +323 -0
  107. package/.claude/skills/03-SKILL-AGENT-CREATION/SKILL.md +374 -0
  108. package/.claude/skills/04-SKILL-KNOWLEDGE-EXTRACTION/SKILL.md +318 -0
  109. package/.claude/skills/05-SKILL-PIPELINE-JARVIS/SKILL.md +430 -0
  110. package/.claude/skills/06-SKILL-BRAINSTORMING/SKILL.md +72 -0
  111. package/.claude/skills/07-SKILL-DISPATCHING-PARALLEL-AGENTS/SKILL.md +193 -0
  112. package/.claude/skills/08-SKILL-EXECUTING-PLANS/SKILL.md +114 -0
  113. package/.claude/skills/09-SKILL-WRITING-PLANS/SKILL.md +184 -0
  114. package/.claude/skills/10-SKILL-VERIFICATION-BEFORE-COMPLETION/SKILL.md +130 -0
  115. package/.claude/skills/11-SKILL-USING-SUPERPOWERS/SKILL.md +105 -0
  116. package/.claude/skills/DETECTION-PROTOCOL.md +217 -0
  117. package/.claude/skills/README.md +240 -0
  118. package/.claude/skills/SKILL-REGISTRY.md +284 -0
  119. package/.claude/skills/SKILL-SUGGESTIONS.md +114 -0
  120. package/.claude/skills/_TEMPLATES/SKILL-WRITER-GUIDE.md +385 -0
  121. package/.claude/skills/chronicler/SKILL.md +146 -0
  122. package/.claude/skills/chronicler/chronicler_core.py +468 -0
  123. package/.claude/skills/code-review/SKILL.md +160 -0
  124. package/.claude/skills/council/SKILL.md +210 -0
  125. package/.claude/skills/executor/SKILL.md +161 -0
  126. package/.claude/skills/fase-2-5-tagging/SKILL.md +182 -0
  127. package/.claude/skills/feature-dev/SKILL.md +154 -0
  128. package/.claude/skills/finance-agent/SKILL.md +137 -0
  129. package/.claude/skills/frontend-design/SKILL.md +165 -0
  130. package/.claude/skills/gdrive-transcription-downloader/SKILL.md +249 -0
  131. package/.claude/skills/gemini-fallback/SKILL.md +67 -0
  132. package/.claude/skills/gemini-fallback/gemini_fetch.py +0 -0
  133. package/.claude/skills/gha/SKILL.md +96 -0
  134. package/.claude/skills/gha/gha_diagnostic.py +227 -0
  135. package/.claude/skills/github-workflow/SKILL.md +190 -0
  136. package/.claude/skills/hookify/SKILL.md +134 -0
  137. package/.claude/skills/hybrid-source-reading/SKILL.md +265 -0
  138. package/.claude/skills/jarvis/SKILL.md +546 -0
  139. package/.claude/skills/jarvis-briefing/SKILL.md +340 -0
  140. package/.claude/skills/ler-planilha/SKILL.md +281 -0
  141. package/.claude/skills/plugin-dev/SKILL.md +176 -0
  142. package/.claude/skills/pr-review-toolkit/SKILL.md +178 -0
  143. package/.claude/skills/resume/SKILL.md +61 -0
  144. package/.claude/skills/save/SKILL.md +87 -0
  145. package/.claude/skills/skill-writer/SKILL.md +153 -0
  146. package/.claude/skills/skill-writer/examples.md +191 -0
  147. package/.claude/skills/skill-writer/troubleshooting.md +205 -0
  148. package/.claude/skills/smart-download-tagger/SKILL.md +148 -0
  149. package/.claude/skills/source-sync/SKILL.md +240 -0
  150. package/.claude/skills/sync-docs/SKILL.md +193 -0
  151. package/.claude/skills/sync-docs/config.json +37 -0
  152. package/.claude/skills/sync-docs/gdrive_sync.py +358 -0
  153. package/.claude/skills/sync-docs/reauth.py +71 -0
  154. package/.claude/skills/talent-agent/SKILL.md +183 -0
  155. package/.claude/skills/verify/SKILL.md +154 -0
  156. package/.claude/skills/verify/verify_runner.py +0 -0
  157. package/.claude/skills/verify-6-levels/SKILL.md +234 -0
  158. package/.claude/templates/BATCH-LOG-TEMPLATE.md +221 -0
  159. package/.claudeignore +9 -0
  160. package/.gitattributes +4 -0
  161. package/.github/layer1-allowlist.txt +80 -0
  162. package/.github/layer2-manifest.txt +40 -0
  163. package/.gitignore +219 -0
  164. package/README.md +1210 -0
  165. package/agents/_templates/INDEX.md +741 -0
  166. package/agents/_templates/TEMPLATE-AGENT-MD-ULTRA-ROBUSTO-V3.md +2399 -0
  167. package/agents/boardroom/CHECKLIST-MASTER.md +281 -0
  168. package/agents/boardroom/INTEGRATION-GUIDE.md +406 -0
  169. package/agents/boardroom/README.md +238 -0
  170. package/agents/boardroom/config/BOARDROOM-CONFIG.md +186 -0
  171. package/agents/boardroom/config/TTS-INTEGRATION.md +258 -0
  172. package/agents/boardroom/config/VOICE-PROFILES.md +624 -0
  173. package/agents/boardroom/config/voice_mapping.json +128 -0
  174. package/agents/boardroom/scripts/audio_generator.py +375 -0
  175. package/agents/boardroom/scripts/audio_generator_edge.py +353 -0
  176. package/agents/boardroom/scripts/jarvis_boardroom_hook.py +415 -0
  177. package/agents/boardroom/scripts/notebooklm_generator.py +578 -0
  178. package/agents/boardroom/templates/EPISODE-TEMPLATE.md +367 -0
  179. package/agents/boardroom/templates/scene-templates/SCENE-AGENT-DEBATE.md +252 -0
  180. package/agents/boardroom/templates/scene-templates/SCENE-COUNCIL.md +270 -0
  181. package/agents/boardroom/templates/scene-templates/SCENE-DNA-CONSULTATION.md +126 -0
  182. package/agents/boardroom/templates/scene-templates/SCENE-QUESTION.md +174 -0
  183. package/agents/boardroom/workflows/WORKFLOW-AUDIO-GENERATION.md +421 -0
  184. package/agents/constitution/BASE-CONSTITUTION.md +254 -0
  185. package/agents/council/CRITIC.md +197 -0
  186. package/agents/council/DEVILS-ADVOCATE.md +274 -0
  187. package/agents/council/SYNTHESIZER.md +293 -0
  188. package/agents/council/advogado-do-diabo/AGENT.md +489 -0
  189. package/agents/council/advogado-do-diabo/SOUL.md +100 -0
  190. package/agents/council/critico-metodologico/AGENT.md +670 -0
  191. package/agents/council/critico-metodologico/SOUL.md +107 -0
  192. package/agents/council/sintetizador/AGENT.md +558 -0
  193. package/agents/council/sintetizador/SOUL.md +94 -0
  194. package/agents/persons/_example/AGENT-EXAMPLE.md +42 -0
  195. package/agents/persons/_example/DNA-EXAMPLE.yaml +61 -0
  196. package/agents/protocols/AGENT-COGNITION-PROTOCOL.md +779 -0
  197. package/agents/protocols/AGENT-INTEGRITY-PROTOCOL.md +692 -0
  198. package/agents/protocols/BATCH-VISUAL-PROTOCOL.md +841 -0
  199. package/agents/protocols/DNA-CONFIG-TEMPLATE.yaml +181 -0
  200. package/agents/protocols/DNA-EXTRACTION-PROTOCOL.md +370 -0
  201. package/agents/protocols/EPISTEMIC-PROTOCOL.md +333 -0
  202. package/agents/protocols/LOG-STRUCTURE-PROTOCOL.md +65 -0
  203. package/agents/protocols/MEMORY-PROTOCOL.md +567 -0
  204. package/agents/protocols/NARRATIVE-SYNTHESIS-PROTOCOL.md +278 -0
  205. package/agents/protocols/PHASE-4-VERIFICATION-CHECKPOINT.md +146 -0
  206. package/agents/protocols/SOUL-TEMPLATE.md +416 -0
  207. package/agents/protocols/TEMPLATE-EVOLUTION-PROTOCOL.md +544 -0
  208. package/agents/protocols/VISUAL-DIFF-PROTOCOL.md +159 -0
  209. package/agents/sua-empresa/README.md +44 -0
  210. package/agents/sua-empresa/_example/jds/EXAMPLE-JD.md +42 -0
  211. package/agents/sua-empresa/_example/org/EXAMPLE-ORG.md +32 -0
  212. package/agents/sua-empresa/_example/roles/EXAMPLE-ROLE.md +38 -0
  213. package/bin/cli.js +2 -0
  214. package/bin/lib/ascii-art.js +234 -0
  215. package/bin/lib/installer.js +402 -0
  216. package/bin/lib/setup-wizard.js +95 -0
  217. package/bin/lib/validate-email.js +109 -0
  218. package/bin/mega-brain.js +97 -0
  219. package/bin/push.js +342 -0
  220. package/bin/templates/env.example +38 -0
  221. package/inbox/.gitkeep +0 -0
  222. package/integrations/README.md +46 -0
  223. package/integrations/mcps/MCP-REGISTRY.md +56 -0
  224. package/integrations/mcps/excalidraw/CONFIG.md +56 -0
  225. package/integrations/mcps/gdrive/CONFIG.md +38 -0
  226. package/knowledge/dna/.gitkeep +0 -0
  227. package/knowledge/dossiers/persons/.gitkeep +0 -0
  228. package/knowledge/dossiers/persons/DOSSIER-EXAMPLE.md +49 -0
  229. package/knowledge/dossiers/system/.gitkeep +0 -0
  230. package/knowledge/dossiers/themes/.gitkeep +0 -0
  231. package/knowledge/playbooks/.gitkeep +0 -0
  232. package/knowledge/playbooks/PLAYBOOK-EXAMPLE.md +50 -0
  233. package/knowledge/sources/.gitkeep +0 -0
  234. package/logs/.gitkeep +0 -0
  235. package/package.json +128 -0
  236. package/processing/canonical/.gitkeep +0 -0
  237. package/processing/chunks/.gitkeep +0 -0
  238. package/processing/insights/.gitkeep +0 -0
  239. package/processing/narratives/.gitkeep +0 -0
  240. package/reference/CONSELHO.md +337 -0
  241. package/reference/CONTEXT7_README.md +28 -0
  242. package/reference/JARVIS-LOGGING-PROTOCOL.md +380 -0
  243. package/reference/QUICK-START.md +197 -0
  244. package/reference/README-RALPH-CASCATEAMENTO.md +207 -0
  245. package/reference/TEMPLATE-MASTER.md +727 -0
  246. package/reference/prds/prd-jarvis-mega-brain-v3.md +1305 -0
  247. package/reference/templates/phase5/IMPLEMENTATION-GUIDE.md +355 -0
  248. package/reference/templates/phase5/MOGA-BRAIN-PHASE5-TEMPLATES.md +1284 -0
  249. package/reference/templates/phase5/README.md +165 -0
  250. package/reference/workflow-claude-code-boris-cherny-continuous-claude.md +2232 -0
  251. package/system/database/001_moneyclub_buyers.sql +160 -0
  252. package/system/database/002_premium_token.sql +97 -0
  253. package/system/database/apply-migration.mjs +129 -0
  254. package/system/docs/MEGA-BRAIN-DEMO-COMPLETA.md +1226 -0
  255. package/system/docs/MEGA-BRAIN-MANIFESTO-COMPLETO.md +1054 -0
  256. package/system/docs/MOGA-BRAIN-EXPLICACAO-COMPLETA.md +791 -0
  257. package/system/docs/STRATEGIC-INTEGRATION-GUIDE.md +725 -0
  258. package/system/docs/architecture/01-system-context.md +136 -0
  259. package/system/docs/architecture/02-components.md +225 -0
  260. package/system/docs/architecture/03-data-flow.md +235 -0
  261. package/system/docs/architecture/04-integrations.md +283 -0
  262. package/system/docs/architecture/README.md +71 -0
  263. package/system/docs/architecture/diagrams/component-diagram.mmd +50 -0
  264. package/system/docs/architecture/diagrams/data-flow.mmd +39 -0
  265. package/system/docs/architecture/diagrams/system-overview.mmd +68 -0
  266. package/system/protocols/AGENT-AUTHORITY.md +217 -0
  267. package/system/protocols/CONSTITUICAO-BASE.md +115 -0
  268. package/system/protocols/CONSTITUTION.md +231 -0
  269. package/system/protocols/GOVERNANCE-MAP.md +123 -0
  270. package/system/protocols/HOOK-SECURITY-THREAT-MODEL.md +152 -0
  271. package/system/protocols/ORQUESTRACAO-PROTOCOL.md +215 -0
  272. package/system/protocols/_archive/CHUNKING-PROTOCOL.md +207 -0
  273. package/system/protocols/_archive/ENTITY-RESOLUTION-PROTOCOL.md +269 -0
  274. package/system/protocols/_archive/INSIGHT-EXTRACTION-PROTOCOL.md +257 -0
  275. package/system/protocols/_archive/NARRATIVE-SYNTHESIS-PROTOCOL.md +290 -0
  276. package/system/protocols/agents/AGENT-INTERACTION.md +315 -0
  277. package/system/protocols/agents/CORTEX-PROTOCOL.md +520 -0
  278. package/system/protocols/agents/EPISTEMIC-PROTOCOL.md +465 -0
  279. package/system/protocols/agents/MEMORY-PROTOCOL.md +366 -0
  280. package/system/protocols/agents/WAR-ROOM.md +355 -0
  281. package/system/protocols/company/COMPANY-DOCUMENT-PROTOCOL.md +793 -0
  282. package/system/protocols/company/COMPANY-ENRICHMENT-PROTOCOL.md +679 -0
  283. package/system/protocols/conclave/CONCLAVE-LOG-TEMPLATE-v2.md +309 -0
  284. package/system/protocols/conclave/CONCLAVE-PROTOCOL.md +518 -0
  285. package/system/protocols/conclave/DEBATE-DYNAMICS-CONFIG.yaml +322 -0
  286. package/system/protocols/conclave/DEBATE-DYNAMICS-PROTOCOL.md +613 -0
  287. package/system/protocols/conclave/DEBATE-PROTOCOL.md +323 -0
  288. package/system/protocols/council/COUNCIL-LOG-TEMPLATE-v2.md +309 -0
  289. package/system/protocols/council/COUNCIL-PROTOCOL.md +518 -0
  290. package/system/protocols/council/DEBATE-DYNAMICS-CONFIG.yaml +322 -0
  291. package/system/protocols/council/DEBATE-DYNAMICS-PROTOCOL.md +613 -0
  292. package/system/protocols/council/DEBATE-PROTOCOL.md +323 -0
  293. package/system/protocols/dna/DNA-EXTRACTION-PROTOCOL.md +1214 -0
  294. package/system/protocols/dna/ENRICHMENT-PROTOCOL.md +408 -0
  295. package/system/protocols/dna/REASONING-MODEL-PROTOCOL.md +331 -0
  296. package/system/protocols/pipeline/DOSSIER-COMPILATION-PROTOCOL.md +790 -0
  297. package/system/protocols/pipeline/NARRATIVE-METABOLISM-PROTOCOL.md +292 -0
  298. package/system/protocols/pipeline/PIPELINE-JARVIS-v2.1.md +606 -0
  299. package/system/protocols/pipeline/PROMPT-1.1-CHUNKING.md +154 -0
  300. package/system/protocols/pipeline/PROMPT-1.2-ENTITY-RESOLUTION.md +186 -0
  301. package/system/protocols/pipeline/PROMPT-2.1-DNA-TAGS-INCREMENT.md +208 -0
  302. package/system/protocols/pipeline/PROMPT-2.1-INSIGHT-EXTRACTION.md +191 -0
  303. package/system/protocols/pipeline/PROMPT-3.1-NARRATIVE-SYNTHESIS.md +331 -0
  304. package/system/protocols/pipeline/SOURCES-COMPILATION-PROTOCOL.md +340 -0
  305. package/system/protocols/system/AUTO-LOG-PROTOCOL.md +369 -0
  306. package/system/protocols/system/CHECKPOINT-ENFORCEMENT.md +176 -0
  307. package/system/protocols/system/ENFORCEMENT.md +435 -0
  308. package/system/protocols/system/LOG-TEMPLATES.md +1068 -0
@@ -0,0 +1,501 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ DUAL-LOCATION ENFORCEMENT HOOK - REGRA #8
4
+ ==========================================
5
+ Garante que todo batch log existe em AMBOS os locais:
6
+ - /logs/batches/BATCH-XXX.md
7
+ - /.claude/mission-control/batch-logs/BATCH-XXX.json
8
+
9
+ Autor: JARVIS
10
+ Data: 2026-01-11
11
+ """
12
+
13
+ import os
14
+ import re
15
+ import json
16
+ import sys
17
+ from pathlib import Path
18
+ from datetime import datetime
19
+ from typing import Dict, Optional, List, Tuple
20
+
21
+ # Caminhos
22
+ BASE_PATH = Path(os.environ.get('CLAUDE_PROJECT_DIR', '.'))
23
+ LOGS_MD = BASE_PATH / "logs" / "batches"
24
+ LOGS_JSON = BASE_PATH / ".claude" / "mission-control" / "batch-logs"
25
+ ENFORCEMENT_LOG = BASE_PATH / "logs" / "enforcement.jsonl"
26
+
27
+
28
+ def ensure_directories():
29
+ """Garante que os diretórios existem."""
30
+ LOGS_MD.mkdir(parents=True, exist_ok=True)
31
+ LOGS_JSON.mkdir(parents=True, exist_ok=True)
32
+
33
+
34
+ def log_enforcement(action: str, batch_id: str, details: dict):
35
+ """Registra ação de enforcement no log."""
36
+ entry = {
37
+ "timestamp": datetime.now().isoformat(),
38
+ "action": action,
39
+ "batch_id": batch_id,
40
+ "details": details
41
+ }
42
+ with open(ENFORCEMENT_LOG, "a", encoding="utf-8") as f:
43
+ f.write(json.dumps(entry, ensure_ascii=False) + "\n")
44
+
45
+
46
+ def extract_batch_id_from_filename(filename: str) -> Optional[str]:
47
+ """
48
+ Extrai o ID do batch do nome do arquivo.
49
+ Suporta múltiplos formatos:
50
+ - BATCH-050.md
51
+ - BATCH-033-CG.json
52
+ - BATCH-001-JEREMY-HAYNES-SOPS-20260104.md
53
+ """
54
+ # Tenta extrair número do batch
55
+ match = re.search(r'BATCH[_-]?(\d+)', filename, re.IGNORECASE)
56
+ if match:
57
+ return match.group(1).zfill(3) # Padroniza para 3 dígitos
58
+ return None
59
+
60
+
61
+ def extract_metadata_from_md(md_path: Path) -> dict:
62
+ """
63
+ Extrai metadados do arquivo .md para criar .json.
64
+ Faz parsing do formato visual do batch log.
65
+ """
66
+ content = md_path.read_text(encoding="utf-8")
67
+
68
+ metadata = {
69
+ "batch_id": "",
70
+ "source": "",
71
+ "timestamp": datetime.now().isoformat(),
72
+ "status": "COMPLETE",
73
+ "files_processed": 0,
74
+ "files": [],
75
+ "extraction_summary": {
76
+ "filosofias": 0,
77
+ "frameworks": 0,
78
+ "heuristicas": 0,
79
+ "metodologias": 0,
80
+ "modelos_mentais": 0
81
+ },
82
+ "key_frameworks": [],
83
+ "key_heuristicas": [],
84
+ "key_filosofias": [],
85
+ "key_metodologias": [],
86
+ "auto_generated": True,
87
+ "generated_from": str(md_path.name),
88
+ "generated_at": datetime.now().isoformat()
89
+ }
90
+
91
+ # Extrai batch_id do nome do arquivo
92
+ batch_match = re.search(r'BATCH[_-]?(\d+)', md_path.name, re.IGNORECASE)
93
+ if batch_match:
94
+ metadata["batch_id"] = f"BATCH-{batch_match.group(1).zfill(3)}"
95
+
96
+ # Extrai SOURCE
97
+ source_patterns = [
98
+ r'SOURCE\s+([A-Z][A-Z\s\(\)\.]+)',
99
+ r'FONTE\s+([A-Z][A-Z\s\(\)\.]+)',
100
+ r'Source:\s*([^\n]+)',
101
+ r'\|\s*SOURCE\s*\|\s*([^\|]+)',
102
+ ]
103
+ for pattern in source_patterns:
104
+ match = re.search(pattern, content, re.IGNORECASE)
105
+ if match:
106
+ metadata["source"] = match.group(1).strip()
107
+ break
108
+
109
+ # Se nao encontrou, tenta extrair do nome do arquivo dinamicamente
110
+ if not metadata["source"]:
111
+ # Extract source hint from filename by removing BATCH-XXX prefix and extension
112
+ name_upper = md_path.stem.upper()
113
+ # Remove BATCH-NNN- prefix
114
+ source_hint = re.sub(r'^BATCH[_-]?\d+[_-]?', '', name_upper).strip('-_ ')
115
+ if source_hint:
116
+ # Convert dash/underscore separated name to readable form
117
+ metadata["source"] = source_hint.replace('-', ' ').replace('_', ' ').strip()
118
+
119
+ # Extrai metricas
120
+ metrics_patterns = {
121
+ "filosofias": r'Filosofias\s*[:\|]?\s*(\d+)',
122
+ "frameworks": r'Frameworks?\s*[:\|]?\s*(\d+)',
123
+ "heuristicas": r'Heur[ií]sticas?\s*[:\|]?\s*(\d+)',
124
+ "metodologias": r'Metodologias?\s*[:\|]?\s*(\d+)',
125
+ "modelos_mentais": r'Modelos?\s*Mentais?\s*[:\|]?\s*(\d+)'
126
+ }
127
+
128
+ for key, pattern in metrics_patterns.items():
129
+ match = re.search(pattern, content, re.IGNORECASE)
130
+ if match:
131
+ metadata["extraction_summary"][key] = int(match.group(1))
132
+
133
+ # Extrai arquivos processados da tabela
134
+ table_pattern = r'\|\s*\d+\s*\|\s*([^\|]+)\s*\|'
135
+ files = re.findall(table_pattern, content)
136
+ metadata["files"] = [f.strip() for f in files if f.strip() and "Arquivo" not in f]
137
+ metadata["files_processed"] = len(metadata["files"])
138
+
139
+ # Extrai filosofias destaque
140
+ filosofias_section = re.search(r'PHILOSOPHIES.*?```(.*?)```', content, re.DOTALL | re.IGNORECASE)
141
+ if filosofias_section:
142
+ filosofias = re.findall(r'"([^"]+)"', filosofias_section.group(1))
143
+ metadata["key_filosofias"] = filosofias[:12] # Limita a 12
144
+
145
+ # Extrai frameworks
146
+ frameworks_section = re.search(r'KEY FRAMEWORKS(.*?)(?:##|FILOSOFIAS|HEURISTICAS|```\s*\n\s*##)', content, re.DOTALL | re.IGNORECASE)
147
+ if frameworks_section:
148
+ # Busca nomes de frameworks entre boxes ASCII
149
+ framework_names = re.findall(r'[\u2500-\u257F]\s*([A-Z][A-Za-z0-9\s\(\)\-]+?)\s*[\u2500-\u257F]', frameworks_section.group(1))
150
+ if not framework_names:
151
+ framework_names = re.findall(r'([A-Z][A-Z\s\-]+(?:Framework|Method|System|Model|Process))', frameworks_section.group(1), re.IGNORECASE)
152
+ metadata["key_frameworks"] = list(set(framework_names))[:12]
153
+
154
+ # Extrai heuristicas
155
+ heuristicas_section = re.search(r'HEURISTICS.*?```(.*?)```', content, re.DOTALL | re.IGNORECASE)
156
+ if heuristicas_section:
157
+ heuristicas = re.findall(r'"([^"]+)"', heuristicas_section.group(1))
158
+ metadata["key_heuristicas"] = [{"heuristica": h, "rating": 4} for h in heuristicas[:17]]
159
+
160
+ return metadata
161
+
162
+
163
+ def create_json_from_md(batch_id: str, md_path: Path) -> bool:
164
+ """Cria arquivo .json a partir do .md existente."""
165
+ try:
166
+ metadata = extract_metadata_from_md(md_path)
167
+
168
+ # Determina o nome do arquivo JSON dynamically from source name
169
+ source_code = ""
170
+ source_upper = metadata["source"].upper().strip()
171
+ if source_upper:
172
+ # Generate short code from initials of source name words
173
+ words = source_upper.replace('(', '').replace(')', '').replace('.', '').split()
174
+ if len(words) == 1:
175
+ source_code = f"-{words[0][:3]}"
176
+ else:
177
+ source_code = f"-{''.join(w[0] for w in words if w)}"
178
+
179
+ json_filename = f"BATCH-{batch_id}{source_code}.json"
180
+ json_path = LOGS_JSON / json_filename
181
+
182
+ with open(json_path, "w", encoding="utf-8") as f:
183
+ json.dump(metadata, f, indent=2, ensure_ascii=False)
184
+
185
+ log_enforcement("CREATE_JSON", batch_id, {
186
+ "source_md": str(md_path.name),
187
+ "created_json": json_filename,
188
+ "files_processed": metadata["files_processed"]
189
+ })
190
+
191
+ return True
192
+
193
+ except Exception as e:
194
+ log_enforcement("ERROR_CREATE_JSON", batch_id, {
195
+ "source_md": str(md_path.name),
196
+ "error": str(e)
197
+ })
198
+ return False
199
+
200
+
201
+ def create_md_from_json(batch_id: str, json_path: Path) -> bool:
202
+ """Cria arquivo .md minimo a partir do .json existente."""
203
+ try:
204
+ with open(json_path, "r", encoding="utf-8") as f:
205
+ data = json.load(f)
206
+
207
+ # Gera markdown minimo
208
+ source = data.get("source", "UNKNOWN")
209
+ files_processed = data.get("files_processed", 0)
210
+ timestamp = data.get("timestamp", datetime.now().isoformat())
211
+
212
+ extraction = data.get("extraction_summary", {})
213
+ filosofias = extraction.get("filosofias", 0)
214
+ frameworks = extraction.get("frameworks", 0)
215
+ heuristicas = extraction.get("heuristicas", 0)
216
+ metodologias = extraction.get("metodologias", 0)
217
+ modelos = extraction.get("modelos_mentais", 0)
218
+ total = filosofias + frameworks + heuristicas + metodologias + modelos
219
+
220
+ md_content = f"""# BATCH-{batch_id}
221
+
222
+ > **AUTO-GENERATED from JSON** - {datetime.now().strftime('%Y-%m-%d %H:%M')}
223
+ > Original JSON: {json_path.name}
224
+
225
+ ## BATCH SUMMARY
226
+
227
+ | Campo | Valor |
228
+ |-------|-------|
229
+ | SOURCE | {source} |
230
+ | ARQUIVOS | {files_processed} |
231
+ | TIMESTAMP | {timestamp} |
232
+ | STATUS | {data.get('status', 'COMPLETE')} |
233
+
234
+ ## METRICAS
235
+
236
+ | Camada | Quantidade |
237
+ |--------|------------|
238
+ | Filosofias | {filosofias} |
239
+ | Frameworks | {frameworks} |
240
+ | Heuristicas | {heuristicas} |
241
+ | Metodologias | {metodologias} |
242
+ | Modelos Mentais | {modelos} |
243
+ | **TOTAL** | **{total}** |
244
+
245
+ ## ARQUIVOS PROCESSADOS
246
+
247
+ """
248
+ files = data.get("files", [])
249
+ for i, f in enumerate(files, 1):
250
+ md_content += f"| {i} | {f} |\n"
251
+
252
+ if data.get("key_frameworks"):
253
+ md_content += "\n## KEY FRAMEWORKS\n\n"
254
+ for fw in data["key_frameworks"]:
255
+ md_content += f"- {fw}\n"
256
+
257
+ if data.get("key_filosofias"):
258
+ md_content += "\n## FILOSOFIAS DESTAQUE\n\n"
259
+ for fil in data["key_filosofias"]:
260
+ md_content += f"- \"{fil}\"\n"
261
+
262
+ md_content += f"""
263
+ ---
264
+
265
+ ```
266
+ AUTO-GENERATED BY DUAL-LOCATION ENFORCEMENT HOOK
267
+ JARVIS v3.33 | {datetime.now().strftime('%Y-%m-%d %H:%M')}
268
+ ```
269
+ """
270
+
271
+ md_filename = f"BATCH-{batch_id}.md"
272
+ md_path = LOGS_MD / md_filename
273
+
274
+ with open(md_path, "w", encoding="utf-8") as f:
275
+ f.write(md_content)
276
+
277
+ log_enforcement("CREATE_MD", batch_id, {
278
+ "source_json": str(json_path.name),
279
+ "created_md": md_filename
280
+ })
281
+
282
+ return True
283
+
284
+ except Exception as e:
285
+ log_enforcement("ERROR_CREATE_MD", batch_id, {
286
+ "source_json": str(json_path.name),
287
+ "error": str(e)
288
+ })
289
+ return False
290
+
291
+
292
+ def get_all_batches() -> Dict[str, Dict[str, Optional[Path]]]:
293
+ """
294
+ Coleta todos os batches de ambos os locais.
295
+ Retorna dict: batch_id -> {"md": Path or None, "json": Path or None}
296
+ """
297
+ batches = {}
298
+
299
+ # Coleta .md files
300
+ if LOGS_MD.exists():
301
+ for md_file in LOGS_MD.glob("BATCH-*.md"):
302
+ batch_id = extract_batch_id_from_filename(md_file.name)
303
+ if batch_id:
304
+ if batch_id not in batches:
305
+ batches[batch_id] = {"md": None, "json": None}
306
+ batches[batch_id]["md"] = md_file
307
+
308
+ # Coleta .json files
309
+ if LOGS_JSON.exists():
310
+ for json_file in LOGS_JSON.glob("BATCH-*.json"):
311
+ batch_id = extract_batch_id_from_filename(json_file.name)
312
+ if batch_id:
313
+ if batch_id not in batches:
314
+ batches[batch_id] = {"md": None, "json": None}
315
+ batches[batch_id]["json"] = json_file
316
+
317
+ return batches
318
+
319
+
320
+ def enforce_dual_location(batch_id: str) -> Tuple[bool, str]:
321
+ """
322
+ Garante que batch existe em ambos locais.
323
+ Retorna (success, message)
324
+ """
325
+ # Busca arquivos existentes para este batch
326
+ md_files = list(LOGS_MD.glob(f"BATCH-{batch_id}*.md")) + list(LOGS_MD.glob(f"BATCH-{batch_id.lstrip('0')}*.md"))
327
+ json_files = list(LOGS_JSON.glob(f"BATCH-{batch_id}*.json")) + list(LOGS_JSON.glob(f"BATCH-{batch_id.lstrip('0')}*.json"))
328
+
329
+ md_exists = len(md_files) > 0
330
+ json_exists = len(json_files) > 0
331
+
332
+ if md_exists and json_exists:
333
+ return True, f"BATCH-{batch_id}: Dual-location OK"
334
+
335
+ if md_exists and not json_exists:
336
+ success = create_json_from_md(batch_id, md_files[0])
337
+ if success:
338
+ return True, f"BATCH-{batch_id}: JSON criado a partir de MD"
339
+ return False, f"BATCH-{batch_id}: ERRO ao criar JSON"
340
+
341
+ if json_exists and not md_exists:
342
+ success = create_md_from_json(batch_id, json_files[0])
343
+ if success:
344
+ return True, f"BATCH-{batch_id}: MD criado a partir de JSON"
345
+ return False, f"BATCH-{batch_id}: ERRO ao criar MD"
346
+
347
+ return False, f"BATCH-{batch_id}: Nao encontrado em nenhum local"
348
+
349
+
350
+ def enforce_single_batch(batch_id: str) -> dict:
351
+ """
352
+ Enforça dual-location para um batch especifico.
353
+ Usado como hook apos criar batch.
354
+ """
355
+ ensure_directories()
356
+ success, message = enforce_dual_location(batch_id)
357
+
358
+ result = {
359
+ "batch_id": batch_id,
360
+ "success": success,
361
+ "message": message,
362
+ "timestamp": datetime.now().isoformat()
363
+ }
364
+
365
+ return result
366
+
367
+
368
+ def main():
369
+ """
370
+ Verifica TODOS os batches e enforça dual-location.
371
+ Gera relatorio completo.
372
+ """
373
+ ensure_directories()
374
+
375
+ print("=" * 70)
376
+ print(" DUAL-LOCATION ENFORCEMENT HOOK - REGRA #8")
377
+ print(" Verificando todos os batches...")
378
+ print("=" * 70)
379
+ print()
380
+
381
+ batches = get_all_batches()
382
+
383
+ stats = {
384
+ "total": len(batches),
385
+ "complete": 0,
386
+ "md_only": 0,
387
+ "json_only": 0,
388
+ "created_json": 0,
389
+ "created_md": 0,
390
+ "errors": 0
391
+ }
392
+
393
+ # Ordena por numero do batch
394
+ sorted_batches = sorted(batches.items(), key=lambda x: int(x[0]))
395
+
396
+ for batch_id, paths in sorted_batches:
397
+ md_exists = paths["md"] is not None
398
+ json_exists = paths["json"] is not None
399
+
400
+ if md_exists and json_exists:
401
+ stats["complete"] += 1
402
+ status = "OK"
403
+ elif md_exists and not json_exists:
404
+ stats["md_only"] += 1
405
+ # Tenta criar JSON
406
+ success = create_json_from_md(batch_id, paths["md"])
407
+ if success:
408
+ stats["created_json"] += 1
409
+ status = "CREATED JSON"
410
+ else:
411
+ stats["errors"] += 1
412
+ status = "ERROR"
413
+ elif json_exists and not md_exists:
414
+ stats["json_only"] += 1
415
+ # Tenta criar MD
416
+ success = create_md_from_json(batch_id, paths["json"])
417
+ if success:
418
+ stats["created_md"] += 1
419
+ status = "CREATED MD"
420
+ else:
421
+ stats["errors"] += 1
422
+ status = "ERROR"
423
+ else:
424
+ status = "MISSING"
425
+ stats["errors"] += 1
426
+
427
+ # Output visual
428
+ md_icon = "+" if md_exists or status == "CREATED MD" else "X"
429
+ json_icon = "+" if json_exists or status == "CREATED JSON" else "X"
430
+ print(f" BATCH-{batch_id}: [MD:{md_icon}] [JSON:{json_icon}] -> {status}")
431
+
432
+ # Sumario
433
+ print()
434
+ print("=" * 70)
435
+ print(" SUMARIO")
436
+ print("=" * 70)
437
+ print(f" Total de batches: {stats['total']}")
438
+ print(f" Ja completos: {stats['complete']}")
439
+ print(f" Apenas MD: {stats['md_only']}")
440
+ print(f" Apenas JSON: {stats['json_only']}")
441
+ print(f" JSONs criados: {stats['created_json']}")
442
+ print(f" MDs criados: {stats['created_md']}")
443
+ print(f" Erros: {stats['errors']}")
444
+ print()
445
+
446
+ final_complete = stats['complete'] + stats['created_json'] + stats['created_md']
447
+ compliance = (final_complete / stats['total'] * 100) if stats['total'] > 0 else 0
448
+
449
+ print(f" COMPLIANCE FINAL: {final_complete}/{stats['total']} ({compliance:.1f}%)")
450
+ print()
451
+ print(f" Log salvo em: {ENFORCEMENT_LOG}")
452
+ print("=" * 70)
453
+
454
+ # Log final
455
+ log_enforcement("FULL_SCAN", "ALL", {
456
+ "stats": stats,
457
+ "compliance": compliance
458
+ })
459
+
460
+ return stats
461
+
462
+
463
+ def hook_main():
464
+ """
465
+ Hook entry point for Claude Code PostToolUse event.
466
+ Reads JSON from stdin, outputs JSON to stdout.
467
+ Triggers dual-location enforcement when a batch file is written.
468
+ """
469
+ try:
470
+ input_data = sys.stdin.read()
471
+ hook_input = json.loads(input_data) if input_data else {}
472
+
473
+ tool_input = hook_input.get('tool_input', {})
474
+ file_path = tool_input.get('file_path', '')
475
+
476
+ # Only trigger for batch files
477
+ if 'BATCH' not in file_path.upper():
478
+ print(json.dumps({'continue': True}))
479
+ return
480
+
481
+ # Extract batch ID from path
482
+ batch_id = extract_batch_id_from_filename(Path(file_path).name)
483
+ if not batch_id:
484
+ print(json.dumps({'continue': True}))
485
+ return
486
+
487
+ ensure_directories()
488
+ success, message = enforce_dual_location(batch_id)
489
+
490
+ feedback = f"[REGRA #8] {message}" if success else None
491
+ print(json.dumps({'continue': True, 'feedback': feedback}))
492
+
493
+ except Exception:
494
+ print(json.dumps({'continue': True}))
495
+
496
+
497
+ if __name__ == "__main__":
498
+ if len(sys.argv) > 1 and sys.argv[1] == '--full':
499
+ main()
500
+ else:
501
+ hook_main()