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,584 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ JARVIS Token Checkpoint System v1.0
4
+ Sistema de checkpoint baseado em estimativa de uso de tokens.
5
+
6
+ Como Claude Code não expõe contagem direta de tokens aos hooks,
7
+ usamos heurísticas baseadas em:
8
+ - Número de ações/tool calls
9
+ - Tamanho do conteúdo processado
10
+ - Turnos de conversa
11
+
12
+ Triggers de checkpoint:
13
+ - 50% do limite estimado (WARNING)
14
+ - 75% do limite estimado (CHECKPOINT)
15
+ - 90% do limite estimado (CRITICAL)
16
+
17
+ Integra com:
18
+ - STATE.json (estado JARVIS)
19
+ - Session autosave (persistência)
20
+ - HANDOFF system (continuidade)
21
+ """
22
+
23
+ import json
24
+ import sys
25
+ import os
26
+ from datetime import datetime
27
+ from pathlib import Path
28
+ from dataclasses import dataclass, field, asdict
29
+ from typing import Dict, List, Optional, Any
30
+ from enum import Enum
31
+ import threading
32
+
33
+
34
+ # =============================================================================
35
+ # CONFIGURATION
36
+ # =============================================================================
37
+
38
+ class Config:
39
+ """Configuração do sistema de checkpoint."""
40
+ PROJECT_DIR = Path(os.environ.get('CLAUDE_PROJECT_DIR', '.'))
41
+ JARVIS_DIR = PROJECT_DIR / ".claude" / "jarvis"
42
+ MISSION_CONTROL_DIR = PROJECT_DIR / ".claude" / "mission-control"
43
+ LOGS_DIR = PROJECT_DIR / "logs"
44
+
45
+ # Estimativas de tokens por tipo de ação
46
+ TOKENS_PER_TOOL_CALL = 500 # Média estimada por tool call
47
+ TOKENS_PER_CHAR_INPUT = 0.25 # ~4 chars por token
48
+ TOKENS_PER_CHAR_OUTPUT = 0.25
49
+
50
+ # Limites de contexto (conservador para Opus)
51
+ CONTEXT_LIMIT = 200000 # Limite estimado de contexto
52
+ WARNING_THRESHOLD = 0.50 # 50% - warning
53
+ CHECKPOINT_THRESHOLD = 0.75 # 75% - checkpoint automático
54
+ CRITICAL_THRESHOLD = 0.90 # 90% - checkpoint crítico
55
+
56
+ # Checkpoint por ações (fallback)
57
+ MAX_ACTIONS_BETWEEN_CHECKPOINTS = 50
58
+ MAX_FILES_BETWEEN_CHECKPOINTS = 20
59
+
60
+ # Arquivos de estado
61
+ STATE_FILE = JARVIS_DIR / "STATE.json"
62
+ CHECKPOINT_FILE = JARVIS_DIR / "TOKEN-CHECKPOINT.json"
63
+ CHECKPOINT_LOG = LOGS_DIR / "token_checkpoints.jsonl"
64
+
65
+
66
+ class CheckpointLevel(Enum):
67
+ """Níveis de checkpoint."""
68
+ NORMAL = "normal"
69
+ WARNING = "warning"
70
+ CHECKPOINT = "checkpoint"
71
+ CRITICAL = "critical"
72
+
73
+
74
+ # =============================================================================
75
+ # DATA STRUCTURES
76
+ # =============================================================================
77
+
78
+ @dataclass
79
+ class TokenEstimate:
80
+ """Estimativa de uso de tokens."""
81
+ input_tokens: int = 0
82
+ output_tokens: int = 0
83
+ tool_call_tokens: int = 0
84
+ total_estimated: int = 0
85
+ percent_of_limit: float = 0.0
86
+ level: str = "normal"
87
+
88
+
89
+ @dataclass
90
+ class ActionRecord:
91
+ """Registro de uma ação para estimativa."""
92
+ timestamp: str
93
+ action_type: str
94
+ input_chars: int = 0
95
+ output_chars: int = 0
96
+ is_tool_call: bool = False
97
+ estimated_tokens: int = 0
98
+
99
+
100
+ @dataclass
101
+ class CheckpointData:
102
+ """Dados de um checkpoint."""
103
+ checkpoint_id: str
104
+ session_id: str
105
+ created_at: str
106
+ level: str
107
+ token_estimate: TokenEstimate
108
+ actions_since_last: int
109
+ files_modified_since_last: int
110
+ summary: str
111
+ state_snapshot: Dict[str, Any] = field(default_factory=dict)
112
+ continuation_hint: str = ""
113
+
114
+
115
+ @dataclass
116
+ class TokenCheckpointState:
117
+ """Estado completo do sistema de checkpoint."""
118
+ session_id: str
119
+ started_at: str
120
+ last_checkpoint_at: Optional[str] = None
121
+ checkpoint_count: int = 0
122
+ current_estimate: TokenEstimate = field(default_factory=TokenEstimate)
123
+ actions: List[ActionRecord] = field(default_factory=list)
124
+ files_modified: List[str] = field(default_factory=list)
125
+ checkpoints: List[str] = field(default_factory=list) # IDs dos checkpoints
126
+
127
+
128
+ # =============================================================================
129
+ # TOKEN CHECKPOINT MANAGER
130
+ # =============================================================================
131
+
132
+ class TokenCheckpointManager:
133
+ """Gerenciador singleton de checkpoints de token."""
134
+
135
+ _instance = None
136
+ _lock = threading.Lock()
137
+
138
+ def __new__(cls):
139
+ with cls._lock:
140
+ if cls._instance is None:
141
+ cls._instance = super().__new__(cls)
142
+ cls._instance._initialized = False
143
+ return cls._instance
144
+
145
+ def __init__(self):
146
+ if self._initialized:
147
+ return
148
+
149
+ self._initialized = True
150
+ self.state = self._load_or_create_state()
151
+ self._ensure_directories()
152
+
153
+ def _ensure_directories(self):
154
+ """Garante que diretórios existem."""
155
+ Config.JARVIS_DIR.mkdir(parents=True, exist_ok=True)
156
+ Config.MISSION_CONTROL_DIR.mkdir(parents=True, exist_ok=True)
157
+ Config.LOGS_DIR.mkdir(parents=True, exist_ok=True)
158
+
159
+ def _generate_session_id(self) -> str:
160
+ """Gera ID de sessão."""
161
+ return f"TOKEN-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
162
+
163
+ def _generate_checkpoint_id(self) -> str:
164
+ """Gera ID de checkpoint."""
165
+ return f"CKPT-{datetime.now().strftime('%Y%m%d-%H%M%S')}-{self.state.checkpoint_count + 1:03d}"
166
+
167
+ def _load_or_create_state(self) -> TokenCheckpointState:
168
+ """Carrega estado existente ou cria novo."""
169
+ if Config.CHECKPOINT_FILE.exists():
170
+ try:
171
+ with open(Config.CHECKPOINT_FILE, 'r', encoding='utf-8') as f:
172
+ data = json.load(f)
173
+
174
+ # Reconstruir objetos
175
+ state = TokenCheckpointState(
176
+ session_id=data.get('session_id', self._generate_session_id()),
177
+ started_at=data.get('started_at', datetime.now().isoformat()),
178
+ last_checkpoint_at=data.get('last_checkpoint_at'),
179
+ checkpoint_count=data.get('checkpoint_count', 0),
180
+ checkpoints=data.get('checkpoints', []),
181
+ files_modified=data.get('files_modified', [])
182
+ )
183
+
184
+ # Reconstruir token estimate
185
+ if 'current_estimate' in data:
186
+ est = data['current_estimate']
187
+ state.current_estimate = TokenEstimate(
188
+ input_tokens=est.get('input_tokens', 0),
189
+ output_tokens=est.get('output_tokens', 0),
190
+ tool_call_tokens=est.get('tool_call_tokens', 0),
191
+ total_estimated=est.get('total_estimated', 0),
192
+ percent_of_limit=est.get('percent_of_limit', 0.0),
193
+ level=est.get('level', 'normal')
194
+ )
195
+
196
+ # Reconstruir actions
197
+ if 'actions' in data:
198
+ state.actions = [
199
+ ActionRecord(**a) for a in data['actions'][-100:] # Manter últimas 100
200
+ ]
201
+
202
+ return state
203
+
204
+ except Exception:
205
+ pass
206
+
207
+ return TokenCheckpointState(
208
+ session_id=self._generate_session_id(),
209
+ started_at=datetime.now().isoformat()
210
+ )
211
+
212
+ def _save_state(self):
213
+ """Salva estado atual."""
214
+ data = {
215
+ 'session_id': self.state.session_id,
216
+ 'started_at': self.state.started_at,
217
+ 'last_checkpoint_at': self.state.last_checkpoint_at,
218
+ 'checkpoint_count': self.state.checkpoint_count,
219
+ 'checkpoints': self.state.checkpoints,
220
+ 'files_modified': self.state.files_modified[-50:], # Limitar
221
+ 'current_estimate': asdict(self.state.current_estimate),
222
+ 'actions': [asdict(a) for a in self.state.actions[-100:]],
223
+ 'updated_at': datetime.now().isoformat()
224
+ }
225
+
226
+ with open(Config.CHECKPOINT_FILE, 'w', encoding='utf-8') as f:
227
+ json.dump(data, f, indent=2, ensure_ascii=False)
228
+
229
+ def _calculate_level(self, percent: float) -> str:
230
+ """Determina nível baseado na porcentagem."""
231
+ if percent >= Config.CRITICAL_THRESHOLD:
232
+ return CheckpointLevel.CRITICAL.value
233
+ elif percent >= Config.CHECKPOINT_THRESHOLD:
234
+ return CheckpointLevel.CHECKPOINT.value
235
+ elif percent >= Config.WARNING_THRESHOLD:
236
+ return CheckpointLevel.WARNING.value
237
+ return CheckpointLevel.NORMAL.value
238
+
239
+ def _update_estimate(self):
240
+ """Atualiza estimativa total de tokens."""
241
+ est = self.state.current_estimate
242
+ est.total_estimated = est.input_tokens + est.output_tokens + est.tool_call_tokens
243
+ est.percent_of_limit = est.total_estimated / Config.CONTEXT_LIMIT
244
+ est.level = self._calculate_level(est.percent_of_limit)
245
+
246
+ def record_action(
247
+ self,
248
+ action_type: str,
249
+ input_chars: int = 0,
250
+ output_chars: int = 0,
251
+ is_tool_call: bool = False
252
+ ) -> Dict[str, Any]:
253
+ """
254
+ Registra uma ação e atualiza estimativa.
255
+
256
+ Returns:
257
+ Dict com status e se checkpoint é necessário
258
+ """
259
+ # Calcular tokens estimados
260
+ input_tokens = int(input_chars * Config.TOKENS_PER_CHAR_INPUT)
261
+ output_tokens = int(output_chars * Config.TOKENS_PER_CHAR_OUTPUT)
262
+ tool_tokens = Config.TOKENS_PER_TOOL_CALL if is_tool_call else 0
263
+ total = input_tokens + output_tokens + tool_tokens
264
+
265
+ # Criar registro
266
+ record = ActionRecord(
267
+ timestamp=datetime.now().isoformat(),
268
+ action_type=action_type,
269
+ input_chars=input_chars,
270
+ output_chars=output_chars,
271
+ is_tool_call=is_tool_call,
272
+ estimated_tokens=total
273
+ )
274
+
275
+ # Atualizar estado
276
+ self.state.actions.append(record)
277
+ self.state.current_estimate.input_tokens += input_tokens
278
+ self.state.current_estimate.output_tokens += output_tokens
279
+ self.state.current_estimate.tool_call_tokens += tool_tokens
280
+
281
+ # Recalcular
282
+ self._update_estimate()
283
+
284
+ # Verificar se precisa checkpoint
285
+ needs_checkpoint = self._check_checkpoint_needed()
286
+
287
+ # Salvar estado
288
+ self._save_state()
289
+
290
+ return {
291
+ 'recorded': True,
292
+ 'estimated_tokens': total,
293
+ 'total_estimated': self.state.current_estimate.total_estimated,
294
+ 'percent_of_limit': self.state.current_estimate.percent_of_limit,
295
+ 'level': self.state.current_estimate.level,
296
+ 'needs_checkpoint': needs_checkpoint
297
+ }
298
+
299
+ def record_file_modified(self, file_path: str):
300
+ """Registra arquivo modificado."""
301
+ if file_path not in self.state.files_modified:
302
+ self.state.files_modified.append(file_path)
303
+ self._save_state()
304
+
305
+ def _check_checkpoint_needed(self) -> bool:
306
+ """Verifica se checkpoint é necessário."""
307
+ est = self.state.current_estimate
308
+
309
+ # Por porcentagem de contexto
310
+ if est.percent_of_limit >= Config.CHECKPOINT_THRESHOLD:
311
+ return True
312
+
313
+ # Por número de ações desde último checkpoint
314
+ actions_since = len([
315
+ a for a in self.state.actions
316
+ if not self.state.last_checkpoint_at or
317
+ a.timestamp > self.state.last_checkpoint_at
318
+ ])
319
+ if actions_since >= Config.MAX_ACTIONS_BETWEEN_CHECKPOINTS:
320
+ return True
321
+
322
+ # Por número de arquivos
323
+ files_since = len([
324
+ f for i, f in enumerate(self.state.files_modified)
325
+ if i >= len(self.state.files_modified) - Config.MAX_FILES_BETWEEN_CHECKPOINTS
326
+ ])
327
+ if files_since >= Config.MAX_FILES_BETWEEN_CHECKPOINTS:
328
+ return True
329
+
330
+ return False
331
+
332
+ def create_checkpoint(self, summary: str = "") -> CheckpointData:
333
+ """
334
+ Cria um checkpoint.
335
+
336
+ Args:
337
+ summary: Resumo do trabalho até agora
338
+
339
+ Returns:
340
+ CheckpointData com informações do checkpoint
341
+ """
342
+ checkpoint_id = self._generate_checkpoint_id()
343
+
344
+ # Carregar estado JARVIS para snapshot
345
+ state_snapshot = {}
346
+ if Config.STATE_FILE.exists():
347
+ try:
348
+ with open(Config.STATE_FILE, 'r', encoding='utf-8') as f:
349
+ state_snapshot = json.load(f)
350
+ except Exception:
351
+ pass
352
+
353
+ # Calcular ações desde último checkpoint
354
+ actions_since = len([
355
+ a for a in self.state.actions
356
+ if not self.state.last_checkpoint_at or
357
+ a.timestamp > self.state.last_checkpoint_at
358
+ ])
359
+
360
+ # Criar checkpoint
361
+ checkpoint = CheckpointData(
362
+ checkpoint_id=checkpoint_id,
363
+ session_id=self.state.session_id,
364
+ created_at=datetime.now().isoformat(),
365
+ level=self.state.current_estimate.level,
366
+ token_estimate=self.state.current_estimate,
367
+ actions_since_last=actions_since,
368
+ files_modified_since_last=len(self.state.files_modified),
369
+ summary=summary or f"Checkpoint automático - {self.state.current_estimate.percent_of_limit:.1%} do contexto",
370
+ state_snapshot=state_snapshot,
371
+ continuation_hint=self._generate_continuation_hint()
372
+ )
373
+
374
+ # Atualizar estado
375
+ self.state.checkpoints.append(checkpoint_id)
376
+ self.state.checkpoint_count += 1
377
+ self.state.last_checkpoint_at = checkpoint.created_at
378
+
379
+ # Logar checkpoint
380
+ self._log_checkpoint(checkpoint)
381
+
382
+ # Salvar estado
383
+ self._save_state()
384
+
385
+ return checkpoint
386
+
387
+ def _generate_continuation_hint(self) -> str:
388
+ """Gera dica de continuação para próxima sessão."""
389
+ recent_actions = self.state.actions[-10:]
390
+ action_types = [a.action_type for a in recent_actions]
391
+
392
+ if 'batch_process' in action_types:
393
+ return "Continuar processamento de batch"
394
+ elif 'file_write' in action_types or 'file_edit' in action_types:
395
+ return "Continuar modificações de arquivos"
396
+ elif 'search' in action_types:
397
+ return "Continuar pesquisa/análise"
398
+
399
+ return "Verificar estado e continuar trabalho"
400
+
401
+ def _log_checkpoint(self, checkpoint: CheckpointData):
402
+ """Loga checkpoint em arquivo."""
403
+ log_entry = {
404
+ 'timestamp': checkpoint.created_at,
405
+ 'checkpoint_id': checkpoint.checkpoint_id,
406
+ 'session_id': checkpoint.session_id,
407
+ 'level': checkpoint.level,
408
+ 'percent_of_limit': checkpoint.token_estimate.percent_of_limit,
409
+ 'total_tokens': checkpoint.token_estimate.total_estimated,
410
+ 'actions_since_last': checkpoint.actions_since_last,
411
+ 'summary': checkpoint.summary[:200]
412
+ }
413
+
414
+ with open(Config.CHECKPOINT_LOG, 'a', encoding='utf-8') as f:
415
+ f.write(json.dumps(log_entry, ensure_ascii=False) + '\n')
416
+
417
+ def get_status(self) -> Dict[str, Any]:
418
+ """Retorna status atual do sistema."""
419
+ return {
420
+ 'session_id': self.state.session_id,
421
+ 'started_at': self.state.started_at,
422
+ 'checkpoint_count': self.state.checkpoint_count,
423
+ 'last_checkpoint_at': self.state.last_checkpoint_at,
424
+ 'token_estimate': {
425
+ 'total': self.state.current_estimate.total_estimated,
426
+ 'percent': self.state.current_estimate.percent_of_limit,
427
+ 'level': self.state.current_estimate.level
428
+ },
429
+ 'actions_count': len(self.state.actions),
430
+ 'files_modified': len(self.state.files_modified),
431
+ 'needs_checkpoint': self._check_checkpoint_needed()
432
+ }
433
+
434
+ def reset_session(self):
435
+ """Reseta para nova sessão."""
436
+ self.state = TokenCheckpointState(
437
+ session_id=self._generate_session_id(),
438
+ started_at=datetime.now().isoformat()
439
+ )
440
+ self._save_state()
441
+
442
+
443
+ # =============================================================================
444
+ # GLOBAL API
445
+ # =============================================================================
446
+
447
+ _manager: Optional[TokenCheckpointManager] = None
448
+
449
+
450
+ def get_manager() -> TokenCheckpointManager:
451
+ """Obtém instância do manager."""
452
+ global _manager
453
+ if _manager is None:
454
+ _manager = TokenCheckpointManager()
455
+ return _manager
456
+
457
+
458
+ def record_action(
459
+ action_type: str,
460
+ input_chars: int = 0,
461
+ output_chars: int = 0,
462
+ is_tool_call: bool = False
463
+ ) -> Dict[str, Any]:
464
+ """Registra uma ação."""
465
+ return get_manager().record_action(action_type, input_chars, output_chars, is_tool_call)
466
+
467
+
468
+ def record_file(file_path: str):
469
+ """Registra arquivo modificado."""
470
+ get_manager().record_file_modified(file_path)
471
+
472
+
473
+ def create_checkpoint(summary: str = "") -> Dict[str, Any]:
474
+ """Cria checkpoint."""
475
+ checkpoint = get_manager().create_checkpoint(summary)
476
+ return asdict(checkpoint)
477
+
478
+
479
+ def get_status() -> Dict[str, Any]:
480
+ """Obtém status atual."""
481
+ return get_manager().get_status()
482
+
483
+
484
+ def needs_checkpoint() -> bool:
485
+ """Verifica se checkpoint é necessário."""
486
+ return get_manager()._check_checkpoint_needed()
487
+
488
+
489
+ def reset_session():
490
+ """Reseta sessão."""
491
+ get_manager().reset_session()
492
+
493
+
494
+ # =============================================================================
495
+ # HOOK INTEGRATION
496
+ # =============================================================================
497
+
498
+ def process_hook_input(hook_input: Dict[str, Any]) -> Dict[str, Any]:
499
+ """
500
+ Processa input de hook e registra ação.
501
+
502
+ Chamado por outros hooks para registrar ações automaticamente.
503
+ """
504
+ action_type = hook_input.get('tool_name', 'unknown')
505
+ input_content = hook_input.get('tool_input', {})
506
+ output_content = hook_input.get('tool_result', '')
507
+
508
+ # Estimar tamanho
509
+ input_chars = len(json.dumps(input_content)) if input_content else 0
510
+ output_chars = len(str(output_content)) if output_content else 0
511
+
512
+ result = record_action(
513
+ action_type=action_type,
514
+ input_chars=input_chars,
515
+ output_chars=output_chars,
516
+ is_tool_call=True
517
+ )
518
+
519
+ # Se arquivo foi modificado, registrar
520
+ if action_type in ['Write', 'Edit', 'NotebookEdit']:
521
+ file_path = input_content.get('file_path', '')
522
+ if file_path:
523
+ record_file(file_path)
524
+
525
+ return result
526
+
527
+
528
+ # =============================================================================
529
+ # CLI
530
+ # =============================================================================
531
+
532
+ def main():
533
+ """CLI para teste e debug."""
534
+ import argparse
535
+
536
+ parser = argparse.ArgumentParser(description='JARVIS Token Checkpoint System')
537
+ parser.add_argument('command', choices=['status', 'checkpoint', 'reset', 'test', 'record'])
538
+ parser.add_argument('--summary', '-s', help='Resumo para checkpoint')
539
+ parser.add_argument('tool_name', nargs='?', default='unknown', help='Nome da tool (para record)')
540
+
541
+ args = parser.parse_args()
542
+
543
+ if args.command == 'status':
544
+ status = get_status()
545
+ print(json.dumps(status, indent=2))
546
+
547
+ elif args.command == 'checkpoint':
548
+ checkpoint = create_checkpoint(args.summary or '')
549
+ print(f"Checkpoint criado: {checkpoint['checkpoint_id']}")
550
+ print(json.dumps(checkpoint, indent=2, default=str))
551
+
552
+ elif args.command == 'reset':
553
+ reset_session()
554
+ print("Sessão resetada")
555
+
556
+ elif args.command == 'test':
557
+ # Simular algumas ações
558
+ for i in range(5):
559
+ result = record_action(
560
+ action_type=f'test_action_{i}',
561
+ input_chars=1000,
562
+ output_chars=2000,
563
+ is_tool_call=True
564
+ )
565
+ print(f"Action {i}: {result['percent_of_limit']:.2%}")
566
+
567
+ status = get_status()
568
+ print(f"\nStatus final:")
569
+ print(json.dumps(status, indent=2))
570
+
571
+ elif args.command == 'record':
572
+ # Registrar ação de tool (chamado pelos hooks)
573
+ result = record_action(
574
+ action_type=args.tool_name,
575
+ input_chars=500, # Estimativa média
576
+ output_chars=1000, # Estimativa média
577
+ is_tool_call=True
578
+ )
579
+ # Output silencioso para não poluir - apenas JSON para debug
580
+ print(json.dumps({'recorded': True, 'tool': args.tool_name, 'percent': result['percent_of_limit']}))
581
+
582
+
583
+ if __name__ == '__main__':
584
+ main()
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ JARVIS User Prompt Submit Hook
4
+ Executado quando o usuário envia uma mensagem.
5
+
6
+ Responsabilidades:
7
+ 1. Registrar prompts para análise
8
+ 2. Detectar intenções especiais
9
+ 3. Injetar contexto básico (status, greeting)
10
+
11
+ NOTE: Skill routing (REGRA #27) e quality watchdog são hooks separados
12
+ registrados em settings.json. Este hook foca apenas em intents básicos.
13
+ """
14
+
15
+ import json
16
+ import sys
17
+ import os
18
+ from datetime import datetime
19
+ from pathlib import Path
20
+
21
+
22
+ def get_project_dir():
23
+ """Obtém o diretório do projeto."""
24
+ return os.environ.get('CLAUDE_PROJECT_DIR', os.getcwd())
25
+
26
+
27
+ def detect_special_intents(prompt):
28
+ """Detecta intenções especiais no prompt."""
29
+ prompt_lower = prompt.lower()
30
+
31
+ intents = []
32
+
33
+ if any(word in prompt_lower for word in ['status', 'onde estamos', 'onde paramos']):
34
+ intents.append('status_request')
35
+
36
+ if any(word in prompt_lower for word in ['ajuda', 'help', 'como fazer']):
37
+ intents.append('help_request')
38
+
39
+ if any(word in prompt_lower for word in ['bom dia', 'boa tarde', 'boa noite', 'olá', 'oi']):
40
+ intents.append('greeting')
41
+
42
+ if any(word in prompt_lower for word in ['crie', 'criar', 'faça', 'fazer', 'gerar']):
43
+ intents.append('creation_request')
44
+
45
+ if any(word in prompt_lower for word in ['analise', 'verifique', 'cheque', 'revise']):
46
+ intents.append('analysis_request')
47
+
48
+ if any(phrase in prompt_lower for phrase in ['war room', 'debate sobre', 'múltiplas perspectivas', 'prós e contras']):
49
+ intents.append('war_room_request')
50
+
51
+ if any(phrase in prompt_lower for phrase in ['use os agentes', 'consulte especialistas', 'análise profunda']):
52
+ intents.append('force_agents')
53
+
54
+ return intents
55
+
56
+
57
+ def load_context_for_intents(intents):
58
+ """Carrega contexto relevante baseado nas intenções."""
59
+ project_dir = get_project_dir()
60
+ context_parts = []
61
+
62
+ if 'status_request' in intents:
63
+ state_path = Path(project_dir) / '.claude' / 'jarvis' / 'STATE.json'
64
+ if state_path.exists():
65
+ try:
66
+ with open(state_path, 'r', encoding='utf-8') as f:
67
+ state = json.load(f)
68
+ phase = state.get('current_state', {}).get('phase_name', 'IDLE')
69
+ pct = state.get('current_state', {}).get('percent_complete', 0)
70
+ context_parts.append(
71
+ f"[JARVIS Context] Estado: Fase {phase} | Progresso: {pct}%"
72
+ )
73
+ except Exception:
74
+ pass
75
+
76
+ return context_parts
77
+
78
+
79
+ def main():
80
+ """Hook entry point - reads JSON from stdin, outputs JSON to stdout."""
81
+ try:
82
+ input_data = sys.stdin.read()
83
+ hook_input = json.loads(input_data) if input_data else {}
84
+
85
+ prompt = hook_input.get('prompt', '')
86
+ session_id = hook_input.get('session_id', 'unknown')
87
+
88
+ # Detectar intenções
89
+ intents = detect_special_intents(prompt)
90
+
91
+ # Carregar contexto básico
92
+ context_parts = load_context_for_intents(intents)
93
+
94
+ # Registrar prompt para análise posterior
95
+ project_dir = get_project_dir()
96
+ prompts_path = Path(project_dir) / 'logs' / 'prompts.jsonl'
97
+ prompts_path.parent.mkdir(parents=True, exist_ok=True)
98
+
99
+ prompt_log = {
100
+ 'timestamp': datetime.now().isoformat(),
101
+ 'session_id': session_id,
102
+ 'prompt_length': len(prompt),
103
+ 'intents': intents
104
+ }
105
+
106
+ try:
107
+ with open(prompts_path, 'a', encoding='utf-8') as f:
108
+ f.write(json.dumps(prompt_log) + '\n')
109
+ except Exception:
110
+ pass
111
+
112
+ # Output
113
+ output = {
114
+ 'continue': True,
115
+ 'feedback': '\n'.join(context_parts) if context_parts else None
116
+ }
117
+
118
+ print(json.dumps(output))
119
+
120
+ except Exception:
121
+ print(json.dumps({'continue': True, 'feedback': None}))
122
+
123
+
124
+ if __name__ == '__main__':
125
+ main()