mega-brain-ai 1.3.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.
- package/.antigravity/README.md +46 -0
- package/.antigravity/rules/.gitkeep +0 -0
- package/.antigravity/rules/mega-brain.md +39 -0
- package/.claude/CLAUDE.md +172 -0
- package/.claude/agents.yaml +44 -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 +196 -0
- package/.claude/commands/config.md +133 -0
- package/.claude/commands/create-agent.md +467 -0
- package/.claude/commands/debate.md +159 -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 +172 -0
- package/.claude/commands/extract-knowledge.md +507 -0
- package/.claude/commands/gsd/add-phase.md +43 -0
- package/.claude/commands/gsd/add-tests.md +41 -0
- package/.claude/commands/gsd/add-todo.md +47 -0
- package/.claude/commands/gsd/audit-milestone.md +36 -0
- package/.claude/commands/gsd/check-todos.md +45 -0
- package/.claude/commands/gsd/cleanup.md +18 -0
- package/.claude/commands/gsd/complete-milestone.md +136 -0
- package/.claude/commands/gsd/debug.md +167 -0
- package/.claude/commands/gsd/discuss-phase.md +83 -0
- package/.claude/commands/gsd/execute-phase.md +41 -0
- package/.claude/commands/gsd/health.md +22 -0
- package/.claude/commands/gsd/help.md +22 -0
- package/.claude/commands/gsd/insert-phase.md +32 -0
- package/.claude/commands/gsd/join-discord.md +18 -0
- package/.claude/commands/gsd/list-phase-assumptions.md +46 -0
- package/.claude/commands/gsd/map-codebase.md +71 -0
- package/.claude/commands/gsd/new-milestone.md +44 -0
- package/.claude/commands/gsd/new-project.md +42 -0
- package/.claude/commands/gsd/pause-work.md +38 -0
- package/.claude/commands/gsd/plan-milestone-gaps.md +34 -0
- package/.claude/commands/gsd/plan-phase.md +45 -0
- package/.claude/commands/gsd/progress.md +24 -0
- package/.claude/commands/gsd/quick.md +41 -0
- package/.claude/commands/gsd/reapply-patches.md +110 -0
- package/.claude/commands/gsd/remove-phase.md +31 -0
- package/.claude/commands/gsd/research-phase.md +189 -0
- package/.claude/commands/gsd/resume-work.md +40 -0
- package/.claude/commands/gsd/set-profile.md +34 -0
- package/.claude/commands/gsd/settings.md +36 -0
- package/.claude/commands/gsd/update.md +37 -0
- package/.claude/commands/gsd/verify-work.md +38 -0
- package/.claude/commands/inbox.md +296 -0
- package/.claude/commands/ingest-empresa.md +191 -0
- package/.claude/commands/ingest.md +183 -0
- package/.claude/commands/jarvis-briefing.md +67 -0
- package/.claude/commands/jarvis-control.md +169 -0
- package/.claude/commands/jarvis-full.md +182 -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/get-shit-done/VERSION +1 -0
- package/.claude/get-shit-done/bin/gsd-tools.cjs +588 -0
- package/.claude/get-shit-done/bin/lib/commands.cjs +553 -0
- package/.claude/get-shit-done/bin/lib/config.cjs +162 -0
- package/.claude/get-shit-done/bin/lib/core.cjs +411 -0
- package/.claude/get-shit-done/bin/lib/frontmatter.cjs +299 -0
- package/.claude/get-shit-done/bin/lib/init.cjs +710 -0
- package/.claude/get-shit-done/bin/lib/milestone.cjs +216 -0
- package/.claude/get-shit-done/bin/lib/phase.cjs +871 -0
- package/.claude/get-shit-done/bin/lib/roadmap.cjs +298 -0
- package/.claude/get-shit-done/bin/lib/state.cjs +679 -0
- package/.claude/get-shit-done/bin/lib/template.cjs +222 -0
- package/.claude/get-shit-done/bin/lib/verify.cjs +773 -0
- package/.claude/get-shit-done/references/checkpoints.md +776 -0
- package/.claude/get-shit-done/references/continuation-format.md +249 -0
- package/.claude/get-shit-done/references/decimal-phase-calculation.md +65 -0
- package/.claude/get-shit-done/references/git-integration.md +248 -0
- package/.claude/get-shit-done/references/git-planning-commit.md +38 -0
- package/.claude/get-shit-done/references/model-profile-resolution.md +34 -0
- package/.claude/get-shit-done/references/model-profiles.md +92 -0
- package/.claude/get-shit-done/references/phase-argument-parsing.md +61 -0
- package/.claude/get-shit-done/references/planning-config.md +196 -0
- package/.claude/get-shit-done/references/questioning.md +145 -0
- package/.claude/get-shit-done/references/tdd.md +263 -0
- package/.claude/get-shit-done/references/ui-brand.md +160 -0
- package/.claude/get-shit-done/references/verification-patterns.md +612 -0
- package/.claude/get-shit-done/templates/DEBUG.md +164 -0
- package/.claude/get-shit-done/templates/UAT.md +247 -0
- package/.claude/get-shit-done/templates/VALIDATION.md +76 -0
- package/.claude/get-shit-done/templates/codebase/architecture.md +255 -0
- package/.claude/get-shit-done/templates/codebase/concerns.md +310 -0
- package/.claude/get-shit-done/templates/codebase/conventions.md +307 -0
- package/.claude/get-shit-done/templates/codebase/integrations.md +280 -0
- package/.claude/get-shit-done/templates/codebase/stack.md +186 -0
- package/.claude/get-shit-done/templates/codebase/structure.md +285 -0
- package/.claude/get-shit-done/templates/codebase/testing.md +480 -0
- package/.claude/get-shit-done/templates/config.json +37 -0
- package/.claude/get-shit-done/templates/context.md +283 -0
- package/.claude/get-shit-done/templates/continue-here.md +78 -0
- package/.claude/get-shit-done/templates/debug-subagent-prompt.md +91 -0
- package/.claude/get-shit-done/templates/discovery.md +146 -0
- package/.claude/get-shit-done/templates/milestone-archive.md +123 -0
- package/.claude/get-shit-done/templates/milestone.md +115 -0
- package/.claude/get-shit-done/templates/phase-prompt.md +569 -0
- package/.claude/get-shit-done/templates/planner-subagent-prompt.md +117 -0
- package/.claude/get-shit-done/templates/project.md +184 -0
- package/.claude/get-shit-done/templates/requirements.md +231 -0
- package/.claude/get-shit-done/templates/research-project/ARCHITECTURE.md +204 -0
- package/.claude/get-shit-done/templates/research-project/FEATURES.md +147 -0
- package/.claude/get-shit-done/templates/research-project/PITFALLS.md +200 -0
- package/.claude/get-shit-done/templates/research-project/STACK.md +120 -0
- package/.claude/get-shit-done/templates/research-project/SUMMARY.md +170 -0
- package/.claude/get-shit-done/templates/research.md +552 -0
- package/.claude/get-shit-done/templates/retrospective.md +54 -0
- package/.claude/get-shit-done/templates/roadmap.md +202 -0
- package/.claude/get-shit-done/templates/state.md +176 -0
- package/.claude/get-shit-done/templates/summary-complex.md +59 -0
- package/.claude/get-shit-done/templates/summary-minimal.md +41 -0
- package/.claude/get-shit-done/templates/summary-standard.md +48 -0
- package/.claude/get-shit-done/templates/summary.md +248 -0
- package/.claude/get-shit-done/templates/user-setup.md +311 -0
- package/.claude/get-shit-done/templates/verification-report.md +322 -0
- package/.claude/get-shit-done/workflows/add-phase.md +111 -0
- package/.claude/get-shit-done/workflows/add-tests.md +350 -0
- package/.claude/get-shit-done/workflows/add-todo.md +157 -0
- package/.claude/get-shit-done/workflows/audit-milestone.md +297 -0
- package/.claude/get-shit-done/workflows/check-todos.md +176 -0
- package/.claude/get-shit-done/workflows/cleanup.md +152 -0
- package/.claude/get-shit-done/workflows/complete-milestone.md +763 -0
- package/.claude/get-shit-done/workflows/diagnose-issues.md +219 -0
- package/.claude/get-shit-done/workflows/discovery-phase.md +289 -0
- package/.claude/get-shit-done/workflows/discuss-phase.md +542 -0
- package/.claude/get-shit-done/workflows/execute-phase.md +449 -0
- package/.claude/get-shit-done/workflows/execute-plan.md +448 -0
- package/.claude/get-shit-done/workflows/health.md +156 -0
- package/.claude/get-shit-done/workflows/help.md +489 -0
- package/.claude/get-shit-done/workflows/insert-phase.md +129 -0
- package/.claude/get-shit-done/workflows/list-phase-assumptions.md +178 -0
- package/.claude/get-shit-done/workflows/map-codebase.md +315 -0
- package/.claude/get-shit-done/workflows/new-milestone.md +382 -0
- package/.claude/get-shit-done/workflows/new-project.md +1116 -0
- package/.claude/get-shit-done/workflows/pause-work.md +122 -0
- package/.claude/get-shit-done/workflows/plan-milestone-gaps.md +274 -0
- package/.claude/get-shit-done/workflows/plan-phase.md +569 -0
- package/.claude/get-shit-done/workflows/progress.md +381 -0
- package/.claude/get-shit-done/workflows/quick.md +453 -0
- package/.claude/get-shit-done/workflows/remove-phase.md +154 -0
- package/.claude/get-shit-done/workflows/research-phase.md +73 -0
- package/.claude/get-shit-done/workflows/resume-project.md +306 -0
- package/.claude/get-shit-done/workflows/set-profile.md +80 -0
- package/.claude/get-shit-done/workflows/settings.md +213 -0
- package/.claude/get-shit-done/workflows/transition.md +544 -0
- package/.claude/get-shit-done/workflows/update.md +219 -0
- package/.claude/get-shit-done/workflows/verify-phase.md +242 -0
- package/.claude/get-shit-done/workflows/verify-work.md +569 -0
- package/.claude/gsd-file-manifest.json +144 -0
- package/.claude/hooks/agent_creation_trigger.py +168 -0
- package/.claude/hooks/agent_index_updater.py +255 -0
- package/.claude/hooks/agent_memory_persister.py +203 -0
- package/.claude/hooks/claude_md_agent_sync.py +162 -0
- package/.claude/hooks/claude_md_guard.py +154 -0
- package/.claude/hooks/continuous_save.py +414 -0
- package/.claude/hooks/creation_validator.py +360 -0
- package/.claude/hooks/enforce_dual_location.py +501 -0
- package/.claude/hooks/enforce_plan_mode.py +220 -0
- package/.claude/hooks/gsd-check-update.js +62 -0
- package/.claude/hooks/gsd-context-monitor.js +122 -0
- package/.claude/hooks/gsd-statusline.js +108 -0
- package/.claude/hooks/inbox_age_alert.py +367 -0
- package/.claude/hooks/ledger_updater.py +303 -0
- package/.claude/hooks/memory_hints_injector.py +251 -0
- package/.claude/hooks/memory_updater.py +202 -0
- package/.claude/hooks/notification_system.py +115 -0
- package/.claude/hooks/pending_tracker.py +188 -0
- package/.claude/hooks/pipeline_checkpoint.py +583 -0
- package/.claude/hooks/post_batch_cascading.py +1740 -0
- package/.claude/hooks/post_tool_use.py +120 -0
- package/.claude/hooks/quality_watchdog.py +394 -0
- package/.claude/hooks/ralph_wiggum.py +286 -0
- package/.claude/hooks/session-source-sync.py +223 -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 +187 -0
- package/.claude/hooks/user_prompt_submit.py +125 -0
- package/.claude/package.json +1 -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/RULE-GSD-MANDATORY.md +106 -0
- package/.claude/rules/agent-cognition.md +779 -0
- package/.claude/rules/agent-integrity.md +692 -0
- package/.claude/rules/epistemic-standards.md +333 -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/jarvis_orchestrator.py +5 -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/scripts/validate_cascading_integrity.py +409 -0
- package/.claude/settings.json +215 -0
- package/.claude/skills/DETECTION-PROTOCOL.md +217 -0
- package/.claude/skills/README.md +240 -0
- package/.claude/skills/SKILL-REGISTRY.md +283 -0
- package/.claude/skills/SKILL-SUGGESTIONS.md +114 -0
- package/.claude/skills/_TEMPLATES/SKILL-WRITER-GUIDE.md +385 -0
- package/.claude/skills/agent-creation/SKILL.md +374 -0
- package/.claude/skills/ask-company/SKILL.md +198 -0
- package/.claude/skills/brainstorming/SKILL.md +72 -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/convert-to-company-docs/SKILL.md +68 -0
- package/.claude/skills/convert-to-company-docs/convert.py +532 -0
- package/.claude/skills/dispatching-parallel-agents/SKILL.md +193 -0
- package/.claude/skills/docs-megabrain/SKILL.md +251 -0
- package/.claude/skills/executing-plans/SKILL.md +114 -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/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/knowledge-extraction/SKILL.md +318 -0
- package/.claude/skills/ler-planilha/SKILL.md +281 -0
- package/.claude/skills/pipeline-jarvis/SKILL.md +430 -0
- package/.claude/skills/plugin-dev/SKILL.md +176 -0
- package/.claude/skills/pr-review-toolkit/SKILL.md +178 -0
- package/.claude/skills/process-company-inbox/SKILL.md +183 -0
- package/.claude/skills/python-megabrain/SKILL.md +323 -0
- package/.claude/skills/resume/SKILL.md +61 -0
- package/.claude/skills/save/SKILL.md +87 -0
- package/.claude/skills/skill-creator-internal/SKILL.md +186 -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/using-superpowers/SKILL.md +105 -0
- package/.claude/skills/verification-before-completion/SKILL.md +130 -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/skills/writing-plans/SKILL.md +184 -0
- package/.claude/templates/BATCH-LOG-TEMPLATE.md +221 -0
- package/.claudeignore +9 -0
- package/.cursor/agents.yaml +44 -0
- package/.cursor/rules/mega-brain.md +39 -0
- package/.gitattributes +19 -0
- package/.github/CODEOWNERS +8 -0
- package/.github/ISSUE_TEMPLATE/agent.md +96 -0
- package/.github/ISSUE_TEMPLATE/bug.md +67 -0
- package/.github/ISSUE_TEMPLATE/feature.md +56 -0
- package/.github/ISSUE_TEMPLATE/pipeline.md +70 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +30 -0
- package/.github/assets/banner.svg +152 -0
- package/.github/assets/logo-dark.svg +79 -0
- package/.github/assets/social-preview.png +0 -0
- package/.github/layer1-allowlist.txt +196 -0
- package/.github/layer2-manifest.txt +42 -0
- package/.github/layer3-manifest.txt +94 -0
- package/.github/workflows/claude-code-pr.yml +198 -0
- package/.github/workflows/claude-code-review.yml +57 -0
- package/.github/workflows/claude.yml +76 -0
- package/.github/workflows/publish-pro.yml +72 -0
- package/.github/workflows/publish.yml +86 -0
- package/.github/workflows/verification.yml +251 -0
- package/.gitignore +244 -0
- package/.gitleaks.toml +118 -0
- package/.windsurf/agents.yaml +44 -0
- package/.windsurf/rules/mega-brain.md +39 -0
- package/CONTRIBUTING.md +62 -0
- package/QUICK-START.md +231 -0
- package/README.md +168 -0
- package/agents/AGENT-INDEX.yaml +107 -0
- package/agents/MASTER-AGENT.md +612 -0
- package/agents/README.md +48 -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/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/conclave/CRITIC.md +197 -0
- package/agents/conclave/DEVILS-ADVOCATE.md +274 -0
- package/agents/conclave/README.md +35 -0
- package/agents/conclave/SYNTHESIZER.md +293 -0
- package/agents/conclave/advogado-do-diabo/AGENT.md +502 -0
- package/agents/conclave/advogado-do-diabo/SOUL.md +100 -0
- package/agents/conclave/critico-metodologico/AGENT.md +683 -0
- package/agents/conclave/critico-metodologico/SOUL.md +107 -0
- package/agents/conclave/sintetizador/AGENT.md +571 -0
- package/agents/conclave/sintetizador/SOUL.md +94 -0
- package/agents/constitution/BASE-CONSTITUTION.md +254 -0
- package/agents/persona-registry.yaml +300 -0
- package/agents/sua-empresa/.gitkeep +0 -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/artifacts/README.md +11 -0
- package/artifacts/canonical/.gitkeep +0 -0
- package/artifacts/chunks/.gitkeep +0 -0
- package/artifacts/insights/.gitkeep +0 -0
- package/artifacts/narratives/.gitkeep +0 -0
- package/bin/cli.js +2 -0
- package/bin/lib/ascii-art.js +202 -0
- package/bin/lib/feature-gate.js +46 -0
- package/bin/lib/installer.js +593 -0
- package/bin/lib/license.js +59 -0
- package/bin/lib/pro-commands.js +75 -0
- package/bin/lib/setup-wizard.js +547 -0
- package/bin/lib/validate-email.js +113 -0
- package/bin/mega-brain.js +136 -0
- package/bin/pre-publish-gate.js +229 -0
- package/bin/push.js +1056 -0
- package/bin/templates/env.example +27 -0
- package/bin/utils/pro-detector.js +50 -0
- package/bin/validate-package.js +190 -0
- package/core/__init__.py +2 -0
- package/core/glossary/INDEX.md +63 -0
- package/core/glossary/digital.md +243 -0
- package/core/glossary/finance.md +49 -0
- package/core/glossary/marketing.md +69 -0
- package/core/glossary/operations.md +50 -0
- package/core/glossary/sales.md +690 -0
- package/core/intelligence/__init__.py +41 -0
- package/core/intelligence/agent_trigger.py +468 -0
- package/core/intelligence/audit_layers.py +491 -0
- package/core/intelligence/autonomous_processor.py +796 -0
- package/core/intelligence/bootstrap_registry.py +550 -0
- package/core/intelligence/business_model_detector.py +476 -0
- package/core/intelligence/dossier_trigger.py +336 -0
- package/core/intelligence/entity_normalizer.py +565 -0
- package/core/intelligence/org_chain_detector.py +411 -0
- package/core/intelligence/review_dashboard.py +338 -0
- package/core/intelligence/role_detector.py +855 -0
- package/core/intelligence/session_autosave.py +46 -0
- package/core/intelligence/skill_generator.py +601 -0
- package/core/intelligence/sow_generator.py +711 -0
- package/core/intelligence/sync_package_files.py +504 -0
- package/core/intelligence/task_orchestrator.py +780 -0
- package/core/intelligence/theme_analyzer.py +562 -0
- package/core/intelligence/tool_discovery.py +432 -0
- package/core/intelligence/validate_json_integrity.py +106 -0
- package/core/intelligence/validate_layers.py +310 -0
- package/core/intelligence/verify_classifications.py +94 -0
- package/core/intelligence/viability_scorer.py +592 -0
- package/core/jarvis/02-JARVIS-SOUL.md +390 -0
- package/core/jarvis/03-JARVIS-DNA.yaml +312 -0
- package/core/jarvis/AGENT.md +191 -0
- package/core/jarvis/agent-creator/AGENT.md +199 -0
- package/core/jarvis/agent-creator/SOUL.md +82 -0
- package/core/jarvis/agent-creator/tasks/create-agent.md +133 -0
- package/core/jarvis/agent-creator/tasks/sync-agents.md +100 -0
- package/core/jarvis/agent-creator/workflows/wf-create-agent.yaml +110 -0
- package/core/jarvis/agent-creator/workflows/wf-pipeline-trigger.yaml +111 -0
- package/core/jarvis/autonomous/benchmark/AGENT.md +347 -0
- package/core/jarvis/autonomous/benchmark/SOUL.md +78 -0
- package/core/jarvis/autonomous/critic/AGENT.md +324 -0
- package/core/jarvis/autonomous/critic/SOUL.md +78 -0
- package/core/jarvis/autonomous/evolver/AGENT.md +294 -0
- package/core/jarvis/autonomous/evolver/SOUL.md +85 -0
- package/core/jarvis/autonomous/playbook-generator/AGENT.md +399 -0
- package/core/jarvis/autonomous/playbook-generator/SOUL.md +80 -0
- package/core/patterns/_ROLE_PATTERNS.yaml +547 -0
- package/core/patterns/quality_gates.yaml +259 -0
- package/core/patterns/trigger_config.yaml +193 -0
- package/core/schemas/SCHEMA-INDEX.md +94 -0
- package/core/schemas/canonical-map.schema.json +98 -0
- package/core/schemas/chunks-state.schema.json +131 -0
- package/core/schemas/decisions-registry.schema.json +120 -0
- package/core/schemas/file-registry.schema.json +69 -0
- package/core/schemas/insights-state.schema.json +111 -0
- package/core/schemas/narratives-state.schema.json +150 -0
- package/core/tasks/CHANGELOG.md +55 -0
- package/core/tasks/TASK-REGISTRY.md +113 -0
- package/core/tasks/_templates/task-tmpl.md +105 -0
- package/core/tasks/analyze-themes.md +84 -0
- package/core/tasks/detect-role.md +82 -0
- package/core/tasks/extract-dna.md +114 -0
- package/core/tasks/normalize-entities.md +82 -0
- package/core/tasks/process-batch.md +111 -0
- package/core/tasks/validate-cascade.md +105 -0
- package/core/templates/README.md +27 -0
- package/core/templates/agents/dna-config-template.yaml +181 -0
- package/core/templates/agents/enrichment-protocol.md +408 -0
- package/core/templates/agents/memory-template.md +567 -0
- package/core/templates/agents/reasoning-model.md +331 -0
- package/core/templates/agents/soul-template.md +416 -0
- package/core/templates/agents/template-evolution.md +544 -0
- package/core/templates/debates/CONCLAVE-LOG-TEMPLATE-v2.md +309 -0
- package/core/templates/debates/conclave-log-template.md +309 -0
- package/core/templates/debates/conclave-protocol.md +518 -0
- package/core/templates/debates/debate-dynamics-config.yaml +322 -0
- package/core/templates/debates/debate-dynamics.md +613 -0
- package/core/templates/debates/debate-protocol.md +323 -0
- package/core/templates/logs/LOG-TEMPLATES.md +1068 -0
- package/core/templates/logs/batch-visual-template.md +841 -0
- package/core/templates/logs/log-structure.md +65 -0
- package/core/templates/logs/visual-diff.md +159 -0
- package/core/templates/phases/dossier-compilation.md +790 -0
- package/core/templates/phases/narrative-metabolism.md +292 -0
- package/core/templates/phases/narrative-synthesis.md +278 -0
- package/core/templates/phases/phase4-checkpoint.md +146 -0
- package/core/templates/phases/prompt-1.1-chunking.md +154 -0
- package/core/templates/phases/prompt-1.2-entity-resolution.md +186 -0
- package/core/templates/phases/prompt-2.1-dna-tags.md +208 -0
- package/core/templates/phases/prompt-2.1-insight-extraction.md +191 -0
- package/core/templates/phases/prompt-3.1-narrative.md +331 -0
- package/core/templates/phases/sources-compilation.md +340 -0
- package/core/workflows/PIPELINE-JARVIS-DOCS.md +606 -0
- package/core/workflows/wf-conclave.yaml +139 -0
- package/core/workflows/wf-extract-dna.yaml +158 -0
- package/core/workflows/wf-ingest.yaml +88 -0
- package/core/workflows/wf-pipeline-full.yaml +138 -0
- package/docs/API-KEYS-GUIDE.md +372 -0
- package/docs/INTEGRATION-POINTS.md +501 -0
- package/docs/LAYERS.md +403 -0
- package/docs/PLAN-MODE-PROTOCOL.md +388 -0
- package/docs/RESTORE-AND-INDEX.md +203 -0
- package/docs/TAG-RESOLVER-IMPLEMENTATION.md +597 -0
- package/docs/conselho.md +337 -0
- package/docs/context7-readme.md +28 -0
- package/docs/jarvis-logging-protocol.md +380 -0
- package/docs/pipeline-completa-v4.md +1315 -0
- package/docs/prompts/meta_agente_mapeamento_processos.md +297 -0
- package/docs/quick-start.md +197 -0
- package/docs/readme-ralph-cascateamento.md +207 -0
- package/docs/template-master.md +727 -0
- package/docs/templates/phase5/IMPLEMENTATION-GUIDE.md +355 -0
- package/docs/templates/phase5/MOGA-BRAIN-PHASE5-TEMPLATES.md +1284 -0
- package/docs/templates/phase5/README.md +165 -0
- package/docs/workflow-continuous-claude.md +2232 -0
- package/inbox/.gitkeep +0 -0
- package/inbox/README.md +15 -0
- package/knowledge/NAVIGATION-MAP.json +292 -0
- package/knowledge/README.md +11 -0
- package/knowledge/dna/.gitkeep +0 -0
- package/knowledge/dossiers/persons/.gitkeep +0 -0
- package/knowledge/dossiers/system/.gitkeep +0 -0
- package/knowledge/dossiers/themes/.gitkeep +0 -0
- package/knowledge/playbooks/.gitkeep +0 -0
- package/knowledge/sources/.gitkeep +0 -0
- package/logs/.gitkeep +0 -0
- package/logs/README.md +11 -0
- package/package.json +180 -0
- package/requirements.txt +4 -0
|
@@ -0,0 +1,1740 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
POST-BATCH CASCADING HOOK - REGRA #22 ENFORCEMENT
|
|
4
|
+
===================================================
|
|
5
|
+
|
|
6
|
+
Executa cascateamento automatico apos criacao de batch.
|
|
7
|
+
|
|
8
|
+
REGRA #22: A secao "DESTINO DO CONHECIMENTO" nao e informativa - e ORDEM DE EXECUCAO.
|
|
9
|
+
|
|
10
|
+
Este hook:
|
|
11
|
+
1. E chamado APOS criar qualquer batch
|
|
12
|
+
2. Le a secao "DESTINO DO CONHECIMENTO" do batch
|
|
13
|
+
3. Para cada destino:
|
|
14
|
+
- AGENTS: Verificar se existe, criar/atualizar MEMORY.md com CONTEUDO REAL
|
|
15
|
+
- PLAYBOOKS: Verificar se existe, criar/atualizar com CONTEUDO REAL dos frameworks
|
|
16
|
+
- DNAs: Atualizar DNA-CONFIG.yaml
|
|
17
|
+
- DOSSIERS: Atualizar theme dossiers
|
|
18
|
+
4. Adiciona secao "### Cascateamento Executado" ao batch
|
|
19
|
+
5. Loga acoes em /logs/cascading.jsonl
|
|
20
|
+
|
|
21
|
+
IMPORTANTE v2.0: Extrai CONTEUDO REAL dos frameworks, nao apenas referencias.
|
|
22
|
+
|
|
23
|
+
v2.1.0: Integra REGRA #26 - Valida integridade antes de marcar completo.
|
|
24
|
+
So marca batch como completo se destinos existem e foram atualizados.
|
|
25
|
+
|
|
26
|
+
Autor: JARVIS
|
|
27
|
+
Versao: 2.1.0
|
|
28
|
+
Data: 2026-01-13
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
import os
|
|
32
|
+
import re
|
|
33
|
+
import json
|
|
34
|
+
import yaml
|
|
35
|
+
from datetime import datetime
|
|
36
|
+
from pathlib import Path
|
|
37
|
+
from typing import Dict, List, Optional, Tuple
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
#=================================
|
|
41
|
+
# CONFIGURATION
|
|
42
|
+
#=================================
|
|
43
|
+
|
|
44
|
+
PROJECT_DIR = os.environ.get(
|
|
45
|
+
'CLAUDE_PROJECT_DIR',
|
|
46
|
+
'.'
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
AGENTS_DIR = Path(PROJECT_DIR) / 'agents'
|
|
50
|
+
KNOWLEDGE_DIR = Path(PROJECT_DIR) / 'knowledge'
|
|
51
|
+
DOSSIERS_DIR = KNOWLEDGE_DIR / 'dossiers' / 'themes'
|
|
52
|
+
LOGS_DIR = Path(PROJECT_DIR) / 'logs'
|
|
53
|
+
CASCADING_LOG = LOGS_DIR / 'cascading.jsonl'
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
#=================================
|
|
57
|
+
# LOGGING
|
|
58
|
+
#=================================
|
|
59
|
+
|
|
60
|
+
def log_cascading_action(action: Dict) -> None:
|
|
61
|
+
"""
|
|
62
|
+
Registra acao de cascateamento em JSONL.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
action: Dicionario com detalhes da acao
|
|
66
|
+
"""
|
|
67
|
+
LOGS_DIR.mkdir(parents=True, exist_ok=True)
|
|
68
|
+
|
|
69
|
+
action['timestamp'] = datetime.now().isoformat()
|
|
70
|
+
|
|
71
|
+
with open(CASCADING_LOG, 'a', encoding='utf-8') as f:
|
|
72
|
+
f.write(json.dumps(action, ensure_ascii=False) + '\n')
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def log_batch_result(batch_id: str, result: Dict) -> None:
|
|
76
|
+
"""
|
|
77
|
+
Registra resultado completo do cascateamento de um batch.
|
|
78
|
+
"""
|
|
79
|
+
log_cascading_action({
|
|
80
|
+
'type': 'batch_cascade_complete',
|
|
81
|
+
'batch_id': batch_id,
|
|
82
|
+
'result': result
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
#=================================
|
|
87
|
+
# DESTINATION EXTRACTION
|
|
88
|
+
#=================================
|
|
89
|
+
|
|
90
|
+
def extract_destinations(batch_content: str) -> Dict[str, List[Dict]]:
|
|
91
|
+
"""
|
|
92
|
+
Extrai destinos da secao DESTINO DO CONHECIMENTO.
|
|
93
|
+
|
|
94
|
+
Suporta multiplos formatos de batch incluindo:
|
|
95
|
+
- Boxes ASCII com caracteres especiais
|
|
96
|
+
- Formato simples com identacao
|
|
97
|
+
- Blocos de codigo markdown
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Dict com listas de destinos por tipo
|
|
101
|
+
"""
|
|
102
|
+
destinations = {
|
|
103
|
+
'agents': [],
|
|
104
|
+
'playbooks': [],
|
|
105
|
+
'dnas': [],
|
|
106
|
+
'dossiers': []
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
# Encontrar secao DESTINO DO CONHECIMENTO (mais flexivel)
|
|
110
|
+
# Pode estar com emoji ou sem, com # ou ##
|
|
111
|
+
destino_patterns = [
|
|
112
|
+
r'#+\s*.*DESTINO DO CONHECIMENTO.*?\n(.*?)(?=\n#+\s|\Z)',
|
|
113
|
+
r'DESTINO DO CONHECIMENTO[:\s]*\n(.*?)(?=\n#+\s|\Z)',
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
destino_section = None
|
|
117
|
+
for pattern in destino_patterns:
|
|
118
|
+
match = re.search(pattern, batch_content, re.DOTALL | re.IGNORECASE)
|
|
119
|
+
if match:
|
|
120
|
+
destino_section = match.group(1)
|
|
121
|
+
break
|
|
122
|
+
|
|
123
|
+
if not destino_section:
|
|
124
|
+
# Fallback: procurar blocos com AGENTES/playbooks/dna diretamente
|
|
125
|
+
destino_section = batch_content
|
|
126
|
+
|
|
127
|
+
# Funcao auxiliar para limpar linha de caracteres de box
|
|
128
|
+
def clean_line(line: str) -> str:
|
|
129
|
+
# Remove caracteres de box ASCII do INICIO e FIM, e espacos extras
|
|
130
|
+
# Primeiro remove do inicio
|
|
131
|
+
cleaned = re.sub(r'^[\s│├└┌┐┘┬┴┼─\|\-\+]+', '', line)
|
|
132
|
+
# Depois remove do fim
|
|
133
|
+
cleaned = re.sub(r'[\s│├└┌┐┘┬┴┼─\|\-\+]+$', '', cleaned)
|
|
134
|
+
return cleaned.strip()
|
|
135
|
+
|
|
136
|
+
# Funcao para verificar se e um nome de agente (MAIUSCULAS-COM-HIFEN)
|
|
137
|
+
def is_agent_name(text: str) -> bool:
|
|
138
|
+
# Nome em maiusculas, pode ter hifen, sem espacos no meio
|
|
139
|
+
return bool(re.match(r'^[A-Z][A-Z0-9]+(?:-[A-Z0-9]+)*$', text))
|
|
140
|
+
|
|
141
|
+
# === EXTRAIR AGENTES ===
|
|
142
|
+
# Procurar bloco que comeca com AGENTES A ALIMENTAR
|
|
143
|
+
agents_patterns = [
|
|
144
|
+
r'AGENTES?\s*A\s*ALIMENTAR[:\s│]*\n(.*?)(?=\n[│\s]*(?:PLAYBOOK|DNA|DOSSIER|└─+\s*$)|```\s*\n|$)',
|
|
145
|
+
r'AGENTES?\s*A\s*ALIMENTAR[:\s]*\n(.*?)(?=PLAYBOOK|DNA\s*A|$)',
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
for pattern in agents_patterns:
|
|
149
|
+
agents_match = re.search(pattern, destino_section, re.DOTALL | re.IGNORECASE)
|
|
150
|
+
if agents_match:
|
|
151
|
+
agents_block = agents_match.group(1)
|
|
152
|
+
current_agent = None
|
|
153
|
+
frameworks = []
|
|
154
|
+
|
|
155
|
+
for line in agents_block.split('\n'):
|
|
156
|
+
cleaned = clean_line(line)
|
|
157
|
+
if not cleaned:
|
|
158
|
+
continue
|
|
159
|
+
|
|
160
|
+
# Verifica se e um nome de agente
|
|
161
|
+
if is_agent_name(cleaned):
|
|
162
|
+
# Salvar agente anterior
|
|
163
|
+
if current_agent:
|
|
164
|
+
destinations['agents'].append({
|
|
165
|
+
'name': current_agent,
|
|
166
|
+
'frameworks': frameworks
|
|
167
|
+
})
|
|
168
|
+
current_agent = cleaned
|
|
169
|
+
frameworks = []
|
|
170
|
+
elif current_agent:
|
|
171
|
+
# E um framework do agente atual
|
|
172
|
+
if cleaned and not cleaned.startswith(('PLAYBOOK', 'dna', 'DOSSIER')):
|
|
173
|
+
frameworks.append(cleaned)
|
|
174
|
+
|
|
175
|
+
# Salvar ultimo agente
|
|
176
|
+
if current_agent:
|
|
177
|
+
destinations['agents'].append({
|
|
178
|
+
'name': current_agent,
|
|
179
|
+
'frameworks': frameworks
|
|
180
|
+
})
|
|
181
|
+
break
|
|
182
|
+
|
|
183
|
+
# === EXTRAIR PLAYBOOKS ===
|
|
184
|
+
playbooks_patterns = [
|
|
185
|
+
r'PLAYBOOKS?\s*A\s*ENRIQUECER[:\s│]*\n(.*?)(?=\n[│\s]*(?:DNA|DOSSIER|└─+\s*$)|```\s*\n|$)',
|
|
186
|
+
r'PLAYBOOKS?\s*A\s*ENRIQUECER[:\s]*\n(.*?)(?=DNA\s*A|$)',
|
|
187
|
+
]
|
|
188
|
+
|
|
189
|
+
for pattern in playbooks_patterns:
|
|
190
|
+
pb_match = re.search(pattern, destino_section, re.DOTALL | re.IGNORECASE)
|
|
191
|
+
if pb_match:
|
|
192
|
+
pb_block = pb_match.group(1)
|
|
193
|
+
|
|
194
|
+
for line in pb_block.split('\n'):
|
|
195
|
+
cleaned = clean_line(line)
|
|
196
|
+
if not cleaned:
|
|
197
|
+
continue
|
|
198
|
+
|
|
199
|
+
# Procurar nome de playbook (PLAYBOOK-XXX ou apenas XXX em maiusculas)
|
|
200
|
+
if cleaned.startswith('PLAYBOOK'):
|
|
201
|
+
name = cleaned.split()[0] if ' ' in cleaned else cleaned
|
|
202
|
+
# Remover : do final se existir
|
|
203
|
+
name = name.rstrip(':')
|
|
204
|
+
desc = cleaned[len(name):].strip().lstrip(':').strip() if len(cleaned) > len(name) else ''
|
|
205
|
+
destinations['playbooks'].append({
|
|
206
|
+
'name': name,
|
|
207
|
+
'description': desc
|
|
208
|
+
})
|
|
209
|
+
elif is_agent_name(cleaned) and not cleaned.startswith(('dna', 'DOSSIER')):
|
|
210
|
+
# Pode ser um playbook sem prefixo PLAYBOOK-
|
|
211
|
+
destinations['playbooks'].append({
|
|
212
|
+
'name': cleaned,
|
|
213
|
+
'description': ''
|
|
214
|
+
})
|
|
215
|
+
elif cleaned.startswith('"') or cleaned.startswith("'"):
|
|
216
|
+
# E uma descricao do playbook anterior
|
|
217
|
+
if destinations['playbooks']:
|
|
218
|
+
destinations['playbooks'][-1]['description'] = cleaned.strip('"\'')
|
|
219
|
+
break
|
|
220
|
+
|
|
221
|
+
# === EXTRAIR DNAs ===
|
|
222
|
+
dna_patterns = [
|
|
223
|
+
r'DNAS?\s*A\s*CONSOLIDAR[:\s│]*\n(.*?)(?=\n[│\s]*(?:PLAYBOOK|DOSSIER|└─+\s*$)|```\s*\n|$)',
|
|
224
|
+
r'DNAS?\s*A\s*CONSOLIDAR[:\s]*\n(.*?)(?=PLAYBOOK|$)',
|
|
225
|
+
]
|
|
226
|
+
|
|
227
|
+
for pattern in dna_patterns:
|
|
228
|
+
dna_match = re.search(pattern, destino_section, re.DOTALL | re.IGNORECASE)
|
|
229
|
+
if dna_match:
|
|
230
|
+
dna_block = dna_match.group(1)
|
|
231
|
+
|
|
232
|
+
for line in dna_block.split('\n'):
|
|
233
|
+
cleaned = clean_line(line)
|
|
234
|
+
if not cleaned:
|
|
235
|
+
continue
|
|
236
|
+
|
|
237
|
+
# Procurar DNA-NOME e quantidade
|
|
238
|
+
if 'dna' in cleaned.upper():
|
|
239
|
+
dna_name_match = re.search(r'(DNA[-_]?[A-Z0-9\-]+)', cleaned, re.IGNORECASE)
|
|
240
|
+
if dna_name_match:
|
|
241
|
+
name = dna_name_match.group(1).upper().replace('_', '-')
|
|
242
|
+
# Extrair quantidade de elementos
|
|
243
|
+
elements_match = re.search(r'\+?(\d+)\s*elementos?', cleaned, re.IGNORECASE)
|
|
244
|
+
elements = int(elements_match.group(1)) if elements_match else 0
|
|
245
|
+
destinations['dnas'].append({
|
|
246
|
+
'name': name,
|
|
247
|
+
'elements_to_add': elements
|
|
248
|
+
})
|
|
249
|
+
break
|
|
250
|
+
|
|
251
|
+
# === EXTRAIR TEMAS/dossiers ===
|
|
252
|
+
# Procurar na secao de analise de temas
|
|
253
|
+
themes_patterns = [
|
|
254
|
+
r'TEMAS?\s*(?:NOVOS?|CONSOLIDADOS?)[:\s│]*\n(.*?)(?=\n[│\s]*(?:TEMAS?|CROSS|└─+\s*$)|```\s*\n|$)',
|
|
255
|
+
r'TEMAS?\s*NOVOS?[:\s]*\n(.*?)(?=TEMAS?\s*CONSOLIDADOS?|CROSS|$)',
|
|
256
|
+
r'TEMAS?\s*CONSOLIDADOS?[:\s]*\n(.*?)(?=CROSS|$)',
|
|
257
|
+
]
|
|
258
|
+
|
|
259
|
+
for pattern in themes_patterns:
|
|
260
|
+
themes_matches = list(re.finditer(pattern, batch_content, re.DOTALL | re.IGNORECASE))
|
|
261
|
+
if themes_matches:
|
|
262
|
+
for themes_match in themes_matches:
|
|
263
|
+
themes_block = themes_match.group(1)
|
|
264
|
+
for line in themes_block.split('\n'):
|
|
265
|
+
cleaned = clean_line(line)
|
|
266
|
+
if not cleaned:
|
|
267
|
+
continue
|
|
268
|
+
# Verificar se e um nome de tema valido
|
|
269
|
+
if is_agent_name(cleaned):
|
|
270
|
+
theme_name = cleaned
|
|
271
|
+
if not any(d['name'] == theme_name for d in destinations['dossiers']):
|
|
272
|
+
destinations['dossiers'].append({
|
|
273
|
+
'name': theme_name,
|
|
274
|
+
'type': 'theme'
|
|
275
|
+
})
|
|
276
|
+
break # Sair do loop de patterns se encontrou algo
|
|
277
|
+
|
|
278
|
+
return destinations
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def extract_batch_metadata(batch_content: str) -> Dict:
|
|
282
|
+
"""
|
|
283
|
+
Extrai metadados do batch (source, ID, elementos, etc).
|
|
284
|
+
"""
|
|
285
|
+
metadata = {
|
|
286
|
+
'batch_id': '',
|
|
287
|
+
'source': '',
|
|
288
|
+
'elements_count': 0,
|
|
289
|
+
'frameworks': [],
|
|
290
|
+
'frameworks_content': {}, # NOVO: conteudo real dos frameworks
|
|
291
|
+
'heuristics': [],
|
|
292
|
+
'heuristics_content': '', # NOVO: bloco completo de heuristicas
|
|
293
|
+
'methodologies': [],
|
|
294
|
+
'methodologies_content': '', # NOVO: bloco completo de metodologias
|
|
295
|
+
'filosofias_content': '', # NOVO: bloco de filosofias
|
|
296
|
+
'modelos_mentais_content': '' # NOVO: bloco de modelos mentais
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
# Extrair BATCH ID
|
|
300
|
+
batch_match = re.search(r'BATCH[\-_]?(\d+)', batch_content)
|
|
301
|
+
if batch_match:
|
|
302
|
+
metadata['batch_id'] = f"BATCH-{batch_match.group(1)}"
|
|
303
|
+
|
|
304
|
+
# Extrair SOURCE
|
|
305
|
+
source_match = re.search(r'(?:Source|FONTE)[:\s]+([A-Z][A-Z\s\-]+)', batch_content)
|
|
306
|
+
if source_match:
|
|
307
|
+
metadata['source'] = source_match.group(1).strip()
|
|
308
|
+
|
|
309
|
+
# Extrair total de elementos
|
|
310
|
+
elements_match = re.search(r'(?:TOTAL|Elementos?)[:\s]+(\d+)', batch_content)
|
|
311
|
+
if elements_match:
|
|
312
|
+
metadata['elements_count'] = int(elements_match.group(1))
|
|
313
|
+
|
|
314
|
+
#=============================
|
|
315
|
+
# EXTRAIR FRAMEWORKS COM CONTEUDO REAL
|
|
316
|
+
#=============================
|
|
317
|
+
fw_section_match = re.search(
|
|
318
|
+
r'(?:##\s*)?(?:🏗️\s*)?KEY\s*FRAMEWORKS?.*?\n(.*?)(?=\n---|\n##|\Z)',
|
|
319
|
+
batch_content, re.DOTALL | re.IGNORECASE
|
|
320
|
+
)
|
|
321
|
+
if fw_section_match:
|
|
322
|
+
fw_section = fw_section_match.group(1)
|
|
323
|
+
|
|
324
|
+
# Extrair cada framework como bloco ASCII completo
|
|
325
|
+
# Pattern: FRAMEWORK N: NOME seguido de box ate proximo FRAMEWORK ou fim
|
|
326
|
+
framework_blocks = extract_ascii_boxes(fw_section, 'FRAMEWORK')
|
|
327
|
+
|
|
328
|
+
for name, content in framework_blocks.items():
|
|
329
|
+
metadata['frameworks'].append(name)
|
|
330
|
+
metadata['frameworks_content'][name] = content
|
|
331
|
+
|
|
332
|
+
#=============================
|
|
333
|
+
# EXTRAIR HEURISTICAS COM CONTEUDO REAL
|
|
334
|
+
#=============================
|
|
335
|
+
# Buscar secao que comeca com ## HEURISTICAS ou similar
|
|
336
|
+
heur_section_match = re.search(
|
|
337
|
+
r'(?:##\s*)?(?:🔢\s*)?HEUR[IÍ]STICAS?\s*(?:COM\s*N[UÚ]MEROS?)?\s*(?:\(\d+\))?\s*\n(```\n)?(.*?)(?=\n```\n|\n---|\n##[^#]|\Z)',
|
|
338
|
+
batch_content, re.DOTALL | re.IGNORECASE
|
|
339
|
+
)
|
|
340
|
+
if heur_section_match:
|
|
341
|
+
heur_section = heur_section_match.group(2) if heur_section_match.group(2) else heur_section_match.group(1)
|
|
342
|
+
if heur_section:
|
|
343
|
+
# Guardar bloco completo
|
|
344
|
+
metadata['heuristics_content'] = heur_section.strip()
|
|
345
|
+
# Tambem extrair lista simples para compatibilidade
|
|
346
|
+
heuristics = re.findall(r'[├└│]\s*([^\n]+\d+[^\n]*)', heur_section)
|
|
347
|
+
metadata['heuristics'] = [h.strip() for h in heuristics[:10]]
|
|
348
|
+
|
|
349
|
+
#=============================
|
|
350
|
+
# EXTRAIR METODOLOGIAS COM CONTEUDO REAL
|
|
351
|
+
#=============================
|
|
352
|
+
# Buscar secao que comeca com ## METODOLOGIAS ou similar
|
|
353
|
+
meth_section_match = re.search(
|
|
354
|
+
r'(?:##\s*)?(?:📝\s*)?METODOLOGIAS?\s*(?:\(\d+\))?\s*\n(```\n)?(.*?)(?=\n```\s*\n---|\n---|\n##[^#]|\Z)',
|
|
355
|
+
batch_content, re.DOTALL | re.IGNORECASE
|
|
356
|
+
)
|
|
357
|
+
if meth_section_match:
|
|
358
|
+
meth_section = meth_section_match.group(2) if meth_section_match.group(2) else meth_section_match.group(1)
|
|
359
|
+
if meth_section:
|
|
360
|
+
# Verificar se pegou o bloco correto (deve conter STEP ou numeracao)
|
|
361
|
+
if 'STEP' in meth_section.upper() or re.search(r'\d+\.', meth_section):
|
|
362
|
+
# Guardar bloco completo
|
|
363
|
+
metadata['methodologies_content'] = meth_section.strip()
|
|
364
|
+
# Tambem extrair lista para compatibilidade (limpar caracteres de box)
|
|
365
|
+
meth_names = re.findall(r'\d+\.\s*([^\n]+)', meth_section)
|
|
366
|
+
metadata['methodologies'] = [
|
|
367
|
+
re.sub(r'[\s│]+$', '', m).strip()
|
|
368
|
+
for m in meth_names
|
|
369
|
+
]
|
|
370
|
+
|
|
371
|
+
#=============================
|
|
372
|
+
# EXTRAIR FILOSOFIAS COM CONTEUDO REAL
|
|
373
|
+
#=============================
|
|
374
|
+
fil_section_match = re.search(
|
|
375
|
+
r'(?:##\s*)?(?:🧠\s*)?FILOSOFIAS?.*?\n(.*?)(?=\n---|\n##|\Z)',
|
|
376
|
+
batch_content, re.DOTALL | re.IGNORECASE
|
|
377
|
+
)
|
|
378
|
+
if fil_section_match:
|
|
379
|
+
metadata['filosofias_content'] = fil_section_match.group(1).strip()
|
|
380
|
+
|
|
381
|
+
#=============================
|
|
382
|
+
# EXTRAIR MODELOS MENTAIS COM CONTEUDO REAL
|
|
383
|
+
#=============================
|
|
384
|
+
mm_section_match = re.search(
|
|
385
|
+
r'(?:##\s*)?(?:🔄\s*)?MODELOS?\s*MENTAIS?.*?\n(.*?)(?=\n---|\n##|\Z)',
|
|
386
|
+
batch_content, re.DOTALL | re.IGNORECASE
|
|
387
|
+
)
|
|
388
|
+
if mm_section_match:
|
|
389
|
+
metadata['modelos_mentais_content'] = mm_section_match.group(1).strip()
|
|
390
|
+
|
|
391
|
+
return metadata
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def extract_ascii_boxes(content: str, prefix: str = 'FRAMEWORK') -> Dict[str, str]:
|
|
395
|
+
"""
|
|
396
|
+
Extrai blocos ASCII completos de uma secao.
|
|
397
|
+
|
|
398
|
+
Cada bloco comeca com uma linha contendo o prefixo (ex: FRAMEWORK 1: NOME)
|
|
399
|
+
e termina quando encontra outro bloco ou fim da secao.
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
Dict com nome do bloco -> conteudo completo incluindo ASCII art
|
|
403
|
+
"""
|
|
404
|
+
boxes = {}
|
|
405
|
+
|
|
406
|
+
# Estrategia: encontrar todos os headers FRAMEWORK N: e depois extrair ate o proximo
|
|
407
|
+
header_pattern = re.compile(
|
|
408
|
+
rf'{prefix}\s*(\d+)[:\s]+([^\n│]+)',
|
|
409
|
+
re.IGNORECASE
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
# Encontrar posicoes de todos os headers
|
|
413
|
+
headers = list(header_pattern.finditer(content))
|
|
414
|
+
|
|
415
|
+
for i, match in enumerate(headers):
|
|
416
|
+
name = match.group(2).strip()
|
|
417
|
+
# Limpar caracteres de box do nome
|
|
418
|
+
name = re.sub(r'[\s│]+$', '', name).strip()
|
|
419
|
+
|
|
420
|
+
# Encontrar inicio do box (procurar ┌ antes do header)
|
|
421
|
+
start_search = max(0, match.start() - 200) # Buscar ate 200 chars antes
|
|
422
|
+
box_start_match = None
|
|
423
|
+
|
|
424
|
+
# Procurar o ┌ mais proximo antes do header
|
|
425
|
+
section_before = content[start_search:match.start()]
|
|
426
|
+
box_starts = list(re.finditer(r'┌[─┬]+┐', section_before))
|
|
427
|
+
if box_starts:
|
|
428
|
+
# Pegar o ultimo (mais proximo do header)
|
|
429
|
+
box_start_match = box_starts[-1]
|
|
430
|
+
actual_start = start_search + box_start_match.start()
|
|
431
|
+
else:
|
|
432
|
+
actual_start = match.start()
|
|
433
|
+
|
|
434
|
+
# Encontrar fim do box
|
|
435
|
+
# O fim e quando encontra o proximo header ou └──...──┘ final
|
|
436
|
+
if i + 1 < len(headers):
|
|
437
|
+
# Ha proximo header - encontrar └ antes dele
|
|
438
|
+
next_header_pos = headers[i + 1].start()
|
|
439
|
+
section_between = content[match.end():next_header_pos]
|
|
440
|
+
# Procurar ultimo └──...──┘ antes do proximo header
|
|
441
|
+
box_ends = list(re.finditer(r'└[─┴]+┘', section_between))
|
|
442
|
+
if box_ends:
|
|
443
|
+
actual_end = match.end() + box_ends[-1].end()
|
|
444
|
+
else:
|
|
445
|
+
actual_end = next_header_pos
|
|
446
|
+
else:
|
|
447
|
+
# Ultimo header - ir ate fim ou proximo └
|
|
448
|
+
section_after = content[match.end():match.end() + 2000]
|
|
449
|
+
box_end_match = re.search(r'└[─┴]+┘', section_after)
|
|
450
|
+
if box_end_match:
|
|
451
|
+
actual_end = match.end() + box_end_match.end()
|
|
452
|
+
else:
|
|
453
|
+
actual_end = min(match.end() + 1000, len(content))
|
|
454
|
+
|
|
455
|
+
# Extrair bloco completo
|
|
456
|
+
full_box = content[actual_start:actual_end].strip()
|
|
457
|
+
|
|
458
|
+
if name and full_box:
|
|
459
|
+
boxes[name] = full_box
|
|
460
|
+
|
|
461
|
+
# Fallback se nao encontrou nada: tentar extrair boxes individuais
|
|
462
|
+
if not boxes:
|
|
463
|
+
box_blocks = re.findall(
|
|
464
|
+
r'(┌[─┬]+┐.*?└[─┴]+┘)',
|
|
465
|
+
content, re.DOTALL
|
|
466
|
+
)
|
|
467
|
+
for i, block in enumerate(box_blocks, 1):
|
|
468
|
+
header_match = re.search(rf'{prefix}\s*\d*[:\s]+([^│\n]+)', block, re.IGNORECASE)
|
|
469
|
+
if header_match:
|
|
470
|
+
name = header_match.group(1).strip()
|
|
471
|
+
name = re.sub(r'[\s│]+$', '', name).strip()
|
|
472
|
+
else:
|
|
473
|
+
first_line = re.search(r'│\s*([A-Z][^│\n]+)', block)
|
|
474
|
+
name = first_line.group(1).strip() if first_line else f"{prefix} {i}"
|
|
475
|
+
|
|
476
|
+
if name:
|
|
477
|
+
boxes[name] = block
|
|
478
|
+
|
|
479
|
+
return boxes
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def extract_framework_content(batch_content: str, framework_name: str) -> Optional[str]:
|
|
483
|
+
"""
|
|
484
|
+
Extrai o conteudo COMPLETO de um framework especifico do batch.
|
|
485
|
+
|
|
486
|
+
Busca o bloco ASCII que contem o framework e retorna todo o conteudo.
|
|
487
|
+
|
|
488
|
+
Args:
|
|
489
|
+
batch_content: Conteudo completo do batch
|
|
490
|
+
framework_name: Nome do framework a buscar
|
|
491
|
+
|
|
492
|
+
Returns:
|
|
493
|
+
Conteudo completo do framework incluindo ASCII box, ou None se nao encontrado
|
|
494
|
+
"""
|
|
495
|
+
# Normalizar nome para busca
|
|
496
|
+
normalized_name = framework_name.upper().replace('-', ' ').replace('_', ' ')
|
|
497
|
+
|
|
498
|
+
# Buscar na secao de frameworks
|
|
499
|
+
fw_section_match = re.search(
|
|
500
|
+
r'(?:##\s*)?(?:🏗️\s*)?KEY\s*FRAMEWORKS?.*?\n(.*?)(?=\n---|\n##[^#]|\Z)',
|
|
501
|
+
batch_content, re.DOTALL | re.IGNORECASE
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
if not fw_section_match:
|
|
505
|
+
return None
|
|
506
|
+
|
|
507
|
+
fw_section = fw_section_match.group(1)
|
|
508
|
+
|
|
509
|
+
# Extrair todos os boxes
|
|
510
|
+
boxes = extract_ascii_boxes(fw_section, 'FRAMEWORK')
|
|
511
|
+
|
|
512
|
+
# Buscar o framework pelo nome
|
|
513
|
+
for name, content in boxes.items():
|
|
514
|
+
if normalized_name in name.upper().replace('-', ' ').replace('_', ' '):
|
|
515
|
+
return content
|
|
516
|
+
# Busca parcial
|
|
517
|
+
name_words = set(name.upper().split())
|
|
518
|
+
search_words = set(normalized_name.split())
|
|
519
|
+
if search_words & name_words: # Interseção
|
|
520
|
+
return content
|
|
521
|
+
|
|
522
|
+
# Fallback: buscar diretamente no conteudo
|
|
523
|
+
# Pattern: FRAMEWORK [N]: <nome_framework> seguido de box
|
|
524
|
+
direct_pattern = re.compile(
|
|
525
|
+
rf'(┌[─┬]+┐\s*\n\s*│[^│]*FRAMEWORK\s*\d*[:\s]+[^│]*{re.escape(framework_name)}[^└]*└[─┴]+┘)',
|
|
526
|
+
re.DOTALL | re.IGNORECASE
|
|
527
|
+
)
|
|
528
|
+
match = direct_pattern.search(batch_content)
|
|
529
|
+
if match:
|
|
530
|
+
return match.group(1)
|
|
531
|
+
|
|
532
|
+
return None
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
#=================================
|
|
536
|
+
# CASCADING FUNCTIONS
|
|
537
|
+
#=================================
|
|
538
|
+
|
|
539
|
+
def cascade_to_agents(agents: List[Dict], batch_id: str, metadata: Dict,
|
|
540
|
+
batch_content: str = None) -> List[Dict]:
|
|
541
|
+
"""
|
|
542
|
+
Cascateia para agentes (PERSON e CARGO).
|
|
543
|
+
|
|
544
|
+
Para cada agente:
|
|
545
|
+
1. Verifica se existe em /agents/
|
|
546
|
+
2. Se NAO existe -> registra para criacao futura
|
|
547
|
+
3. Se EXISTE -> atualiza MEMORY.md com novos elementos E CONTEUDO REAL
|
|
548
|
+
|
|
549
|
+
IMPORTANTE v2.0: Passa batch_content para extrair conteudo real.
|
|
550
|
+
|
|
551
|
+
Returns:
|
|
552
|
+
Lista de acoes executadas
|
|
553
|
+
"""
|
|
554
|
+
actions = []
|
|
555
|
+
|
|
556
|
+
for agent in agents:
|
|
557
|
+
agent_name = agent['name']
|
|
558
|
+
frameworks = agent.get('frameworks', [])
|
|
559
|
+
|
|
560
|
+
# Mapear nome para caminho
|
|
561
|
+
# OBJECTION-HANDLER -> CARGO/SALES/OBJECTION-HANDLER ou similar
|
|
562
|
+
agent_path = find_agent_path(agent_name)
|
|
563
|
+
|
|
564
|
+
if agent_path:
|
|
565
|
+
# Agente existe - atualizar MEMORY.md
|
|
566
|
+
memory_path = agent_path / 'MEMORY.md'
|
|
567
|
+
|
|
568
|
+
if memory_path.exists():
|
|
569
|
+
update_result = update_agent_memory(
|
|
570
|
+
memory_path,
|
|
571
|
+
batch_id,
|
|
572
|
+
frameworks,
|
|
573
|
+
metadata,
|
|
574
|
+
batch_content # NOVO: passar conteudo do batch
|
|
575
|
+
)
|
|
576
|
+
actions.append({
|
|
577
|
+
'action': 'update_memory',
|
|
578
|
+
'agent': agent_name,
|
|
579
|
+
'path': str(memory_path),
|
|
580
|
+
'frameworks_added': len(frameworks),
|
|
581
|
+
'content_extracted': batch_content is not None,
|
|
582
|
+
'success': update_result
|
|
583
|
+
})
|
|
584
|
+
else:
|
|
585
|
+
# Criar MEMORY.md basico
|
|
586
|
+
create_result = create_agent_memory(
|
|
587
|
+
memory_path,
|
|
588
|
+
agent_name,
|
|
589
|
+
batch_id,
|
|
590
|
+
frameworks,
|
|
591
|
+
metadata,
|
|
592
|
+
batch_content # NOVO: passar conteudo do batch
|
|
593
|
+
)
|
|
594
|
+
actions.append({
|
|
595
|
+
'action': 'create_memory',
|
|
596
|
+
'agent': agent_name,
|
|
597
|
+
'path': str(memory_path),
|
|
598
|
+
'content_extracted': batch_content is not None,
|
|
599
|
+
'success': create_result
|
|
600
|
+
})
|
|
601
|
+
else:
|
|
602
|
+
# Agente nao existe - registrar para criacao futura
|
|
603
|
+
actions.append({
|
|
604
|
+
'action': 'agent_not_found',
|
|
605
|
+
'agent': agent_name,
|
|
606
|
+
'frameworks': frameworks,
|
|
607
|
+
'note': 'Agent should be created in Phase 5.3'
|
|
608
|
+
})
|
|
609
|
+
|
|
610
|
+
log_cascading_action({
|
|
611
|
+
'type': 'agent_cascade',
|
|
612
|
+
'agent': agent_name,
|
|
613
|
+
'batch_id': batch_id,
|
|
614
|
+
'action': actions[-1]
|
|
615
|
+
})
|
|
616
|
+
|
|
617
|
+
return actions
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
def find_agent_path(agent_name: str) -> Optional[Path]:
|
|
621
|
+
"""
|
|
622
|
+
Encontra o caminho de um agente pelo nome.
|
|
623
|
+
|
|
624
|
+
Busca em:
|
|
625
|
+
- /agents/persons/
|
|
626
|
+
- /agents/cargo/
|
|
627
|
+
- /agents/conclave/
|
|
628
|
+
"""
|
|
629
|
+
# Normalizar nome
|
|
630
|
+
normalized = agent_name.upper().replace(' ', '-')
|
|
631
|
+
|
|
632
|
+
# Buscar em PERSONS
|
|
633
|
+
persons_dir = AGENTS_DIR / 'persons'
|
|
634
|
+
if persons_dir.exists():
|
|
635
|
+
for agent_dir in persons_dir.iterdir():
|
|
636
|
+
if agent_dir.is_dir() and normalized in agent_dir.name.upper():
|
|
637
|
+
return agent_dir
|
|
638
|
+
|
|
639
|
+
# Buscar em CARGO (recursivamente)
|
|
640
|
+
cargo_dir = AGENTS_DIR / 'cargo'
|
|
641
|
+
if cargo_dir.exists():
|
|
642
|
+
for category in cargo_dir.iterdir():
|
|
643
|
+
if category.is_dir():
|
|
644
|
+
for agent_dir in category.iterdir():
|
|
645
|
+
if agent_dir.is_dir() and normalized in agent_dir.name.upper():
|
|
646
|
+
return agent_dir
|
|
647
|
+
|
|
648
|
+
# Buscar em CONCLAVE
|
|
649
|
+
conclave_dir = AGENTS_DIR / 'conclave'
|
|
650
|
+
if conclave_dir.exists():
|
|
651
|
+
for agent_dir in conclave_dir.iterdir():
|
|
652
|
+
if agent_dir.is_dir() and normalized in agent_dir.name.upper():
|
|
653
|
+
return agent_dir
|
|
654
|
+
|
|
655
|
+
return None
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def update_agent_memory(memory_path: Path, batch_id: str,
|
|
659
|
+
frameworks: List[str], metadata: Dict,
|
|
660
|
+
batch_content: str = None) -> bool:
|
|
661
|
+
"""
|
|
662
|
+
Atualiza MEMORY.md de um agente com novos frameworks.
|
|
663
|
+
|
|
664
|
+
IMPORTANTE v2.0: Extrai CONTEUDO REAL dos frameworks, nao apenas referencias.
|
|
665
|
+
"""
|
|
666
|
+
try:
|
|
667
|
+
content = memory_path.read_text(encoding='utf-8')
|
|
668
|
+
|
|
669
|
+
# Criar secao de atualizacao
|
|
670
|
+
update_section = f"""
|
|
671
|
+
|
|
672
|
+
---
|
|
673
|
+
|
|
674
|
+
## Atualizacao via Cascading - {batch_id}
|
|
675
|
+
|
|
676
|
+
**Data:** {datetime.now().strftime('%Y-%m-%d %H:%M')}
|
|
677
|
+
**Fonte:** {metadata.get('source', 'Unknown')}
|
|
678
|
+
|
|
679
|
+
### Frameworks Adicionados
|
|
680
|
+
|
|
681
|
+
"""
|
|
682
|
+
# NOVO v2.0: Incluir conteudo REAL dos frameworks
|
|
683
|
+
frameworks_content = metadata.get('frameworks_content', {})
|
|
684
|
+
|
|
685
|
+
for fw in frameworks:
|
|
686
|
+
# Tentar obter conteudo real do framework
|
|
687
|
+
fw_content = frameworks_content.get(fw)
|
|
688
|
+
|
|
689
|
+
if not fw_content and batch_content:
|
|
690
|
+
# Fallback: extrair diretamente do batch
|
|
691
|
+
fw_content = extract_framework_content(batch_content, fw)
|
|
692
|
+
|
|
693
|
+
if fw_content:
|
|
694
|
+
update_section += f"\n#### {fw}\n\n```\n{fw_content}\n```\n\n"
|
|
695
|
+
else:
|
|
696
|
+
# Fallback para referencia se nao conseguir extrair
|
|
697
|
+
update_section += f"- **{fw}** (ver `{batch_id}` para detalhes)\n"
|
|
698
|
+
|
|
699
|
+
update_section += f"""
|
|
700
|
+
### Referencia
|
|
701
|
+
|
|
702
|
+
Batch: `{batch_id}`
|
|
703
|
+
Elementos totais: {metadata.get('elements_count', 'N/A')}
|
|
704
|
+
"""
|
|
705
|
+
|
|
706
|
+
# Adicionar no final do arquivo
|
|
707
|
+
content += update_section
|
|
708
|
+
memory_path.write_text(content, encoding='utf-8')
|
|
709
|
+
|
|
710
|
+
return True
|
|
711
|
+
|
|
712
|
+
except Exception as e:
|
|
713
|
+
log_cascading_action({
|
|
714
|
+
'type': 'error',
|
|
715
|
+
'action': 'update_agent_memory',
|
|
716
|
+
'path': str(memory_path),
|
|
717
|
+
'error': str(e)
|
|
718
|
+
})
|
|
719
|
+
return False
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
def create_agent_memory(memory_path: Path, agent_name: str,
|
|
723
|
+
batch_id: str, frameworks: List[str],
|
|
724
|
+
metadata: Dict, batch_content: str = None) -> bool:
|
|
725
|
+
"""
|
|
726
|
+
Cria MEMORY.md basico para um agente.
|
|
727
|
+
|
|
728
|
+
IMPORTANTE v2.0: Inclui CONTEUDO REAL dos frameworks, nao apenas nomes.
|
|
729
|
+
"""
|
|
730
|
+
try:
|
|
731
|
+
memory_path.parent.mkdir(parents=True, exist_ok=True)
|
|
732
|
+
|
|
733
|
+
content = f"""# MEMORY - {agent_name}
|
|
734
|
+
|
|
735
|
+
> Memoria do agente, alimentada via cascateamento de batches.
|
|
736
|
+
> **VERSAO:** v2.0 - Conteudo real extraido
|
|
737
|
+
|
|
738
|
+
---
|
|
739
|
+
|
|
740
|
+
## Inicializacao
|
|
741
|
+
|
|
742
|
+
**Criado em:** {datetime.now().strftime('%Y-%m-%d %H:%M')}
|
|
743
|
+
**Fonte inicial:** {metadata.get('source', 'Unknown')}
|
|
744
|
+
**Batch inicial:** {batch_id}
|
|
745
|
+
|
|
746
|
+
---
|
|
747
|
+
|
|
748
|
+
## Conhecimento Absorvido
|
|
749
|
+
|
|
750
|
+
### De {batch_id}
|
|
751
|
+
|
|
752
|
+
"""
|
|
753
|
+
# NOVO v2.0: Incluir conteudo REAL dos frameworks
|
|
754
|
+
frameworks_content = metadata.get('frameworks_content', {})
|
|
755
|
+
|
|
756
|
+
for fw in frameworks:
|
|
757
|
+
# Tentar obter conteudo real do framework
|
|
758
|
+
fw_content = frameworks_content.get(fw)
|
|
759
|
+
|
|
760
|
+
if not fw_content and batch_content:
|
|
761
|
+
# Fallback: extrair diretamente do batch
|
|
762
|
+
fw_content = extract_framework_content(batch_content, fw)
|
|
763
|
+
|
|
764
|
+
if fw_content:
|
|
765
|
+
content += f"\n#### {fw}\n\n```\n{fw_content}\n```\n\n"
|
|
766
|
+
else:
|
|
767
|
+
content += f"- **{fw}**\n"
|
|
768
|
+
|
|
769
|
+
content += f"""
|
|
770
|
+
---
|
|
771
|
+
|
|
772
|
+
## Historico de Atualizacoes
|
|
773
|
+
|
|
774
|
+
| Data | Batch | Elementos |
|
|
775
|
+
|------|-------|-----------|
|
|
776
|
+
| {datetime.now().strftime('%Y-%m-%d')} | {batch_id} | {len(frameworks)} |
|
|
777
|
+
|
|
778
|
+
"""
|
|
779
|
+
|
|
780
|
+
memory_path.write_text(content, encoding='utf-8')
|
|
781
|
+
return True
|
|
782
|
+
|
|
783
|
+
except Exception as e:
|
|
784
|
+
log_cascading_action({
|
|
785
|
+
'type': 'error',
|
|
786
|
+
'action': 'create_agent_memory',
|
|
787
|
+
'path': str(memory_path),
|
|
788
|
+
'error': str(e)
|
|
789
|
+
})
|
|
790
|
+
return False
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
def cascade_to_playbooks(playbooks: List[Dict], batch_id: str,
|
|
794
|
+
metadata: Dict, batch_content: str = None) -> List[Dict]:
|
|
795
|
+
"""
|
|
796
|
+
Cascateia para playbooks.
|
|
797
|
+
|
|
798
|
+
Para cada playbook:
|
|
799
|
+
1. Verifica se existe em /knowledge/playbooks/
|
|
800
|
+
2. Se NAO existe -> cria com CONTEUDO REAL dos frameworks do batch
|
|
801
|
+
3. Se EXISTE -> adiciona novos frameworks/metodologias COM CONTEUDO REAL
|
|
802
|
+
|
|
803
|
+
IMPORTANTE v2.0: Passa batch_content para extrair conteudo real.
|
|
804
|
+
"""
|
|
805
|
+
actions = []
|
|
806
|
+
|
|
807
|
+
playbooks_dir = KNOWLEDGE_DIR / 'playbooks'
|
|
808
|
+
playbooks_dir.mkdir(parents=True, exist_ok=True)
|
|
809
|
+
|
|
810
|
+
for playbook in playbooks:
|
|
811
|
+
pb_name = playbook['name']
|
|
812
|
+
pb_desc = playbook.get('description', '')
|
|
813
|
+
|
|
814
|
+
# Normalizar nome do arquivo
|
|
815
|
+
pb_filename = f"{pb_name}.md"
|
|
816
|
+
pb_path = playbooks_dir / pb_filename
|
|
817
|
+
|
|
818
|
+
if pb_path.exists():
|
|
819
|
+
# Atualizar playbook existente
|
|
820
|
+
update_result = update_playbook(
|
|
821
|
+
pb_path, batch_id, pb_desc, metadata, batch_content
|
|
822
|
+
)
|
|
823
|
+
actions.append({
|
|
824
|
+
'action': 'update_playbook',
|
|
825
|
+
'playbook': pb_name,
|
|
826
|
+
'path': str(pb_path),
|
|
827
|
+
'content_extracted': batch_content is not None,
|
|
828
|
+
'success': update_result
|
|
829
|
+
})
|
|
830
|
+
else:
|
|
831
|
+
# Criar novo playbook
|
|
832
|
+
create_result = create_playbook(
|
|
833
|
+
pb_path, pb_name, batch_id, pb_desc, metadata, batch_content
|
|
834
|
+
)
|
|
835
|
+
actions.append({
|
|
836
|
+
'action': 'create_playbook',
|
|
837
|
+
'playbook': pb_name,
|
|
838
|
+
'path': str(pb_path),
|
|
839
|
+
'content_extracted': batch_content is not None,
|
|
840
|
+
'success': create_result
|
|
841
|
+
})
|
|
842
|
+
|
|
843
|
+
log_cascading_action({
|
|
844
|
+
'type': 'playbook_cascade',
|
|
845
|
+
'playbook': pb_name,
|
|
846
|
+
'batch_id': batch_id,
|
|
847
|
+
'action': actions[-1]
|
|
848
|
+
})
|
|
849
|
+
|
|
850
|
+
return actions
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
def update_playbook(pb_path: Path, batch_id: str,
|
|
854
|
+
description: str, metadata: Dict,
|
|
855
|
+
batch_content: str = None) -> bool:
|
|
856
|
+
"""
|
|
857
|
+
Atualiza playbook existente com novos frameworks.
|
|
858
|
+
|
|
859
|
+
IMPORTANTE v2.0: Inclui CONTEUDO REAL dos frameworks.
|
|
860
|
+
"""
|
|
861
|
+
try:
|
|
862
|
+
content = pb_path.read_text(encoding='utf-8')
|
|
863
|
+
|
|
864
|
+
# Adicionar secao de atualizacao
|
|
865
|
+
update_section = f"""
|
|
866
|
+
|
|
867
|
+
---
|
|
868
|
+
|
|
869
|
+
## Atualizacao - {batch_id}
|
|
870
|
+
|
|
871
|
+
**Data:** {datetime.now().strftime('%Y-%m-%d %H:%M')}
|
|
872
|
+
**Fonte:** {metadata.get('source', 'Unknown')}
|
|
873
|
+
|
|
874
|
+
### Novos Elementos
|
|
875
|
+
|
|
876
|
+
{description if description else ''}
|
|
877
|
+
|
|
878
|
+
"""
|
|
879
|
+
# NOVO v2.0: Incluir conteudo REAL dos frameworks
|
|
880
|
+
frameworks_content = metadata.get('frameworks_content', {})
|
|
881
|
+
frameworks = metadata.get('frameworks', [])[:5]
|
|
882
|
+
|
|
883
|
+
if frameworks_content or batch_content:
|
|
884
|
+
update_section += "### Frameworks Detalhados\n\n"
|
|
885
|
+
for fw in frameworks:
|
|
886
|
+
fw_content = frameworks_content.get(fw)
|
|
887
|
+
|
|
888
|
+
if not fw_content and batch_content:
|
|
889
|
+
fw_content = extract_framework_content(batch_content, fw)
|
|
890
|
+
|
|
891
|
+
if fw_content:
|
|
892
|
+
update_section += f"#### {fw}\n\n```\n{fw_content}\n```\n\n"
|
|
893
|
+
else:
|
|
894
|
+
update_section += f"- **{fw}**\n"
|
|
895
|
+
else:
|
|
896
|
+
update_section += "### Frameworks Relacionados\n\n"
|
|
897
|
+
for fw in frameworks:
|
|
898
|
+
update_section += f"- {fw}\n"
|
|
899
|
+
|
|
900
|
+
# Incluir heuristicas se disponivel
|
|
901
|
+
heur_content = metadata.get('heuristics_content', '')
|
|
902
|
+
if heur_content:
|
|
903
|
+
update_section += f"\n### Heuristicas\n\n```\n{heur_content}\n```\n\n"
|
|
904
|
+
|
|
905
|
+
# Incluir metodologias se disponivel
|
|
906
|
+
meth_content = metadata.get('methodologies_content', '')
|
|
907
|
+
if meth_content:
|
|
908
|
+
update_section += f"\n### Metodologias\n\n```\n{meth_content}\n```\n\n"
|
|
909
|
+
|
|
910
|
+
update_section += f"\n**Referencia:** `{batch_id}`\n"
|
|
911
|
+
|
|
912
|
+
content += update_section
|
|
913
|
+
pb_path.write_text(content, encoding='utf-8')
|
|
914
|
+
|
|
915
|
+
return True
|
|
916
|
+
|
|
917
|
+
except Exception as e:
|
|
918
|
+
log_cascading_action({
|
|
919
|
+
'type': 'error',
|
|
920
|
+
'action': 'update_playbook',
|
|
921
|
+
'path': str(pb_path),
|
|
922
|
+
'error': str(e)
|
|
923
|
+
})
|
|
924
|
+
return False
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
def create_playbook(pb_path: Path, name: str, batch_id: str,
|
|
928
|
+
description: str, metadata: Dict,
|
|
929
|
+
batch_content: str = None) -> bool:
|
|
930
|
+
"""
|
|
931
|
+
Cria novo playbook.
|
|
932
|
+
|
|
933
|
+
IMPORTANTE v2.0: Inclui CONTEUDO REAL dos frameworks, heuristicas e metodologias.
|
|
934
|
+
"""
|
|
935
|
+
try:
|
|
936
|
+
content = f"""# {name}
|
|
937
|
+
|
|
938
|
+
> Playbook gerado via cascateamento automatico.
|
|
939
|
+
> **Versao:** 2.0.0 (com conteudo real extraido)
|
|
940
|
+
> **Criado em:** {datetime.now().strftime('%Y-%m-%d')}
|
|
941
|
+
> **Fonte inicial:** {metadata.get('source', 'Unknown')}
|
|
942
|
+
|
|
943
|
+
---
|
|
944
|
+
|
|
945
|
+
## Objetivo
|
|
946
|
+
|
|
947
|
+
{description if description else 'Definir durante revisao manual.'}
|
|
948
|
+
|
|
949
|
+
---
|
|
950
|
+
|
|
951
|
+
## Frameworks Incluidos
|
|
952
|
+
|
|
953
|
+
"""
|
|
954
|
+
# NOVO v2.0: Incluir conteudo REAL dos frameworks
|
|
955
|
+
frameworks_content = metadata.get('frameworks_content', {})
|
|
956
|
+
|
|
957
|
+
for fw in metadata.get('frameworks', []):
|
|
958
|
+
fw_content = frameworks_content.get(fw)
|
|
959
|
+
|
|
960
|
+
if not fw_content and batch_content:
|
|
961
|
+
fw_content = extract_framework_content(batch_content, fw)
|
|
962
|
+
|
|
963
|
+
if fw_content:
|
|
964
|
+
content += f"### {fw}\n\n```\n{fw_content}\n```\n\n"
|
|
965
|
+
else:
|
|
966
|
+
content += f"### {fw}\n\n*Detalhes em `{batch_id}`*\n\n"
|
|
967
|
+
|
|
968
|
+
content += f"""
|
|
969
|
+
---
|
|
970
|
+
|
|
971
|
+
## Heuristicas
|
|
972
|
+
|
|
973
|
+
"""
|
|
974
|
+
# Incluir bloco de heuristicas
|
|
975
|
+
heur_content = metadata.get('heuristics_content', '')
|
|
976
|
+
if heur_content:
|
|
977
|
+
content += f"```\n{heur_content}\n```\n\n"
|
|
978
|
+
else:
|
|
979
|
+
for heur in metadata.get('heuristics', []):
|
|
980
|
+
content += f"- {heur}\n"
|
|
981
|
+
|
|
982
|
+
content += f"""
|
|
983
|
+
---
|
|
984
|
+
|
|
985
|
+
## Metodologias
|
|
986
|
+
|
|
987
|
+
"""
|
|
988
|
+
# Incluir bloco de metodologias
|
|
989
|
+
meth_content = metadata.get('methodologies_content', '')
|
|
990
|
+
if meth_content:
|
|
991
|
+
content += f"```\n{meth_content}\n```\n\n"
|
|
992
|
+
else:
|
|
993
|
+
for meth in metadata.get('methodologies', []):
|
|
994
|
+
content += f"- {meth}\n"
|
|
995
|
+
|
|
996
|
+
# Incluir filosofias se disponivel
|
|
997
|
+
fil_content = metadata.get('filosofias_content', '')
|
|
998
|
+
if fil_content:
|
|
999
|
+
content += f"""
|
|
1000
|
+
---
|
|
1001
|
+
|
|
1002
|
+
## Filosofias
|
|
1003
|
+
|
|
1004
|
+
```
|
|
1005
|
+
{fil_content}
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
"""
|
|
1009
|
+
|
|
1010
|
+
# Incluir modelos mentais se disponivel
|
|
1011
|
+
mm_content = metadata.get('modelos_mentais_content', '')
|
|
1012
|
+
if mm_content:
|
|
1013
|
+
content += f"""
|
|
1014
|
+
---
|
|
1015
|
+
|
|
1016
|
+
## Modelos Mentais
|
|
1017
|
+
|
|
1018
|
+
```
|
|
1019
|
+
{mm_content}
|
|
1020
|
+
```
|
|
1021
|
+
|
|
1022
|
+
"""
|
|
1023
|
+
|
|
1024
|
+
content += f"""
|
|
1025
|
+
---
|
|
1026
|
+
|
|
1027
|
+
## Historico
|
|
1028
|
+
|
|
1029
|
+
| Data | Batch | Acao |
|
|
1030
|
+
|------|-------|------|
|
|
1031
|
+
| {datetime.now().strftime('%Y-%m-%d')} | {batch_id} | Criacao inicial |
|
|
1032
|
+
|
|
1033
|
+
---
|
|
1034
|
+
|
|
1035
|
+
## Referencias
|
|
1036
|
+
|
|
1037
|
+
- Batch: `{batch_id}`
|
|
1038
|
+
- Fonte: {metadata.get('source', 'Unknown')}
|
|
1039
|
+
"""
|
|
1040
|
+
|
|
1041
|
+
pb_path.write_text(content, encoding='utf-8')
|
|
1042
|
+
return True
|
|
1043
|
+
|
|
1044
|
+
except Exception as e:
|
|
1045
|
+
log_cascading_action({
|
|
1046
|
+
'type': 'error',
|
|
1047
|
+
'action': 'create_playbook',
|
|
1048
|
+
'path': str(pb_path),
|
|
1049
|
+
'error': str(e)
|
|
1050
|
+
})
|
|
1051
|
+
return False
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
def cascade_to_dnas(dnas: List[Dict], batch_id: str, metadata: Dict) -> List[Dict]:
|
|
1055
|
+
"""
|
|
1056
|
+
Cascateia para DNA-CONFIG.yaml dos agentes.
|
|
1057
|
+
|
|
1058
|
+
Atualiza contadores de elementos nas 5 camadas.
|
|
1059
|
+
"""
|
|
1060
|
+
actions = []
|
|
1061
|
+
|
|
1062
|
+
for dna in dnas:
|
|
1063
|
+
dna_name = dna['name']
|
|
1064
|
+
elements_to_add = dna.get('elements_to_add', 0)
|
|
1065
|
+
|
|
1066
|
+
# Extrair nome do agente do DNA (DNA-JEREMY-HAYNES -> JEREMY-HAYNES)
|
|
1067
|
+
agent_name = dna_name.replace('DNA-', '')
|
|
1068
|
+
agent_path = find_agent_path(agent_name)
|
|
1069
|
+
|
|
1070
|
+
if agent_path:
|
|
1071
|
+
config_path = agent_path / 'DNA-CONFIG.yaml'
|
|
1072
|
+
|
|
1073
|
+
if config_path.exists():
|
|
1074
|
+
update_result = update_dna_config(
|
|
1075
|
+
config_path,
|
|
1076
|
+
batch_id,
|
|
1077
|
+
elements_to_add,
|
|
1078
|
+
metadata
|
|
1079
|
+
)
|
|
1080
|
+
actions.append({
|
|
1081
|
+
'action': 'update_dna_config',
|
|
1082
|
+
'dna': dna_name,
|
|
1083
|
+
'path': str(config_path),
|
|
1084
|
+
'elements_added': elements_to_add,
|
|
1085
|
+
'success': update_result
|
|
1086
|
+
})
|
|
1087
|
+
else:
|
|
1088
|
+
actions.append({
|
|
1089
|
+
'action': 'dna_config_not_found',
|
|
1090
|
+
'dna': dna_name,
|
|
1091
|
+
'expected_path': str(config_path),
|
|
1092
|
+
'note': 'DNA-CONFIG.yaml should exist for this agent'
|
|
1093
|
+
})
|
|
1094
|
+
else:
|
|
1095
|
+
actions.append({
|
|
1096
|
+
'action': 'agent_not_found',
|
|
1097
|
+
'dna': dna_name,
|
|
1098
|
+
'note': 'Agent for this DNA not found'
|
|
1099
|
+
})
|
|
1100
|
+
|
|
1101
|
+
log_cascading_action({
|
|
1102
|
+
'type': 'dna_cascade',
|
|
1103
|
+
'dna': dna_name,
|
|
1104
|
+
'batch_id': batch_id,
|
|
1105
|
+
'action': actions[-1]
|
|
1106
|
+
})
|
|
1107
|
+
|
|
1108
|
+
return actions
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
def update_dna_config(config_path: Path, batch_id: str,
|
|
1112
|
+
elements_to_add: int, metadata: Dict) -> bool:
|
|
1113
|
+
"""
|
|
1114
|
+
Atualiza DNA-CONFIG.yaml com novos elementos.
|
|
1115
|
+
"""
|
|
1116
|
+
try:
|
|
1117
|
+
with open(config_path, 'r', encoding='utf-8') as f:
|
|
1118
|
+
config = yaml.safe_load(f) or {}
|
|
1119
|
+
|
|
1120
|
+
# Atualizar batches processados
|
|
1121
|
+
if 'batches_processed' not in config:
|
|
1122
|
+
config['batches_processed'] = []
|
|
1123
|
+
config['batches_processed'].append({
|
|
1124
|
+
'batch_id': batch_id,
|
|
1125
|
+
'date': datetime.now().strftime('%Y-%m-%d'),
|
|
1126
|
+
'elements': elements_to_add
|
|
1127
|
+
})
|
|
1128
|
+
|
|
1129
|
+
# Atualizar total de elementos
|
|
1130
|
+
if 'total_elements' not in config:
|
|
1131
|
+
config['total_elements'] = 0
|
|
1132
|
+
config['total_elements'] += elements_to_add
|
|
1133
|
+
|
|
1134
|
+
# Atualizar timestamp
|
|
1135
|
+
config['last_updated'] = datetime.now().isoformat()
|
|
1136
|
+
config['last_batch'] = batch_id
|
|
1137
|
+
|
|
1138
|
+
with open(config_path, 'w', encoding='utf-8') as f:
|
|
1139
|
+
yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
|
|
1140
|
+
|
|
1141
|
+
return True
|
|
1142
|
+
|
|
1143
|
+
except Exception as e:
|
|
1144
|
+
log_cascading_action({
|
|
1145
|
+
'type': 'error',
|
|
1146
|
+
'action': 'update_dna_config',
|
|
1147
|
+
'path': str(config_path),
|
|
1148
|
+
'error': str(e)
|
|
1149
|
+
})
|
|
1150
|
+
return False
|
|
1151
|
+
|
|
1152
|
+
|
|
1153
|
+
def cascade_to_dossiers(themes: List[Dict], batch_id: str,
|
|
1154
|
+
metadata: Dict, batch_content: str = None) -> List[Dict]:
|
|
1155
|
+
"""
|
|
1156
|
+
Cascateia para theme dossiers.
|
|
1157
|
+
|
|
1158
|
+
Aplica REGRA #21: dossiers existentes devem ser ATUALIZADOS, nao ignorados.
|
|
1159
|
+
|
|
1160
|
+
IMPORTANTE v2.0: Passa batch_content para extrair conteudo real.
|
|
1161
|
+
"""
|
|
1162
|
+
actions = []
|
|
1163
|
+
|
|
1164
|
+
DOSSIERS_DIR.mkdir(parents=True, exist_ok=True)
|
|
1165
|
+
|
|
1166
|
+
for theme in themes:
|
|
1167
|
+
theme_name = theme['name']
|
|
1168
|
+
dossier_name = f"DOSSIER-{theme_name}.md"
|
|
1169
|
+
dossier_path = DOSSIERS_DIR / dossier_name
|
|
1170
|
+
|
|
1171
|
+
if dossier_path.exists():
|
|
1172
|
+
# REGRA #21: Comparar versao do dossier vs batch
|
|
1173
|
+
update_result = update_theme_dossier(
|
|
1174
|
+
dossier_path, batch_id, metadata, batch_content
|
|
1175
|
+
)
|
|
1176
|
+
actions.append({
|
|
1177
|
+
'action': 'update_dossier',
|
|
1178
|
+
'theme': theme_name,
|
|
1179
|
+
'path': str(dossier_path),
|
|
1180
|
+
'content_extracted': batch_content is not None,
|
|
1181
|
+
'success': update_result,
|
|
1182
|
+
'rule': 'REGRA #21 applied'
|
|
1183
|
+
})
|
|
1184
|
+
else:
|
|
1185
|
+
# Criar novo dossier
|
|
1186
|
+
create_result = create_theme_dossier(
|
|
1187
|
+
dossier_path, theme_name, batch_id, metadata, batch_content
|
|
1188
|
+
)
|
|
1189
|
+
actions.append({
|
|
1190
|
+
'action': 'create_dossier',
|
|
1191
|
+
'theme': theme_name,
|
|
1192
|
+
'path': str(dossier_path),
|
|
1193
|
+
'content_extracted': batch_content is not None,
|
|
1194
|
+
'success': create_result
|
|
1195
|
+
})
|
|
1196
|
+
|
|
1197
|
+
log_cascading_action({
|
|
1198
|
+
'type': 'dossier_cascade',
|
|
1199
|
+
'theme': theme_name,
|
|
1200
|
+
'batch_id': batch_id,
|
|
1201
|
+
'action': actions[-1]
|
|
1202
|
+
})
|
|
1203
|
+
|
|
1204
|
+
return actions
|
|
1205
|
+
|
|
1206
|
+
|
|
1207
|
+
def update_theme_dossier(dossier_path: Path, batch_id: str, metadata: Dict,
|
|
1208
|
+
batch_content: str = None) -> bool:
|
|
1209
|
+
"""
|
|
1210
|
+
Atualiza theme dossier existente (REGRA #21).
|
|
1211
|
+
|
|
1212
|
+
IMPORTANTE v2.0: Inclui CONTEUDO REAL dos frameworks, heuristicas e metodologias.
|
|
1213
|
+
"""
|
|
1214
|
+
try:
|
|
1215
|
+
content = dossier_path.read_text(encoding='utf-8')
|
|
1216
|
+
|
|
1217
|
+
# Verificar versao atual
|
|
1218
|
+
version_match = re.search(r'Vers[aã]o[:\s]+v?(\d+\.\d+\.?\d*)', content)
|
|
1219
|
+
current_version = version_match.group(1) if version_match else '1.0.0'
|
|
1220
|
+
|
|
1221
|
+
# Incrementar versao
|
|
1222
|
+
parts = current_version.split('.')
|
|
1223
|
+
if len(parts) >= 2:
|
|
1224
|
+
parts[1] = str(int(parts[1]) + 1)
|
|
1225
|
+
new_version = '.'.join(parts)
|
|
1226
|
+
|
|
1227
|
+
# Adicionar secao de atualizacao
|
|
1228
|
+
update_section = f"""
|
|
1229
|
+
|
|
1230
|
+
---
|
|
1231
|
+
|
|
1232
|
+
## Atualizacao v{new_version} - {batch_id}
|
|
1233
|
+
|
|
1234
|
+
**Data:** {datetime.now().strftime('%Y-%m-%d %H:%M')}
|
|
1235
|
+
**Fonte:** {metadata.get('source', 'Unknown')}
|
|
1236
|
+
**Regra aplicada:** REGRA #21 (Cascateamento de Theme Dossiers)
|
|
1237
|
+
**Versao Hook:** v2.0 (conteudo real extraido)
|
|
1238
|
+
|
|
1239
|
+
"""
|
|
1240
|
+
# NOVO v2.0: Incluir conteudo REAL dos frameworks
|
|
1241
|
+
frameworks_content = metadata.get('frameworks_content', {})
|
|
1242
|
+
frameworks = metadata.get('frameworks', [])[:5]
|
|
1243
|
+
|
|
1244
|
+
if frameworks_content:
|
|
1245
|
+
update_section += "### Frameworks Detalhados\n\n"
|
|
1246
|
+
for fw in frameworks:
|
|
1247
|
+
fw_content = frameworks_content.get(fw)
|
|
1248
|
+
if not fw_content and batch_content:
|
|
1249
|
+
fw_content = extract_framework_content(batch_content, fw)
|
|
1250
|
+
if fw_content:
|
|
1251
|
+
update_section += f"#### {fw}\n\n```\n{fw_content}\n```\n\n"
|
|
1252
|
+
else:
|
|
1253
|
+
update_section += f"- **{fw}**\n"
|
|
1254
|
+
else:
|
|
1255
|
+
update_section += "### Novos Frameworks\n\n"
|
|
1256
|
+
for fw in frameworks:
|
|
1257
|
+
update_section += f"- {fw}\n"
|
|
1258
|
+
|
|
1259
|
+
# Incluir bloco de heuristicas
|
|
1260
|
+
heur_content = metadata.get('heuristics_content', '')
|
|
1261
|
+
if heur_content:
|
|
1262
|
+
update_section += f"\n### Heuristicas\n\n```\n{heur_content}\n```\n\n"
|
|
1263
|
+
else:
|
|
1264
|
+
heuristics = metadata.get('heuristics', [])[:5]
|
|
1265
|
+
if heuristics:
|
|
1266
|
+
update_section += "\n### Novas Heuristicas\n\n"
|
|
1267
|
+
for heur in heuristics:
|
|
1268
|
+
update_section += f"- {heur}\n"
|
|
1269
|
+
|
|
1270
|
+
# Incluir metodologias
|
|
1271
|
+
meth_content = metadata.get('methodologies_content', '')
|
|
1272
|
+
if meth_content:
|
|
1273
|
+
update_section += f"\n### Metodologias\n\n```\n{meth_content}\n```\n\n"
|
|
1274
|
+
|
|
1275
|
+
update_section += f"""
|
|
1276
|
+
### Referencia
|
|
1277
|
+
|
|
1278
|
+
- Batch: `{batch_id}`
|
|
1279
|
+
- Elementos: {metadata.get('elements_count', 'N/A')}
|
|
1280
|
+
"""
|
|
1281
|
+
|
|
1282
|
+
# Atualizar versao no header
|
|
1283
|
+
content = re.sub(
|
|
1284
|
+
r'(Vers[aã]o[:\s]+v?)(\d+\.\d+\.?\d*)',
|
|
1285
|
+
f'\\g<1>{new_version}',
|
|
1286
|
+
content
|
|
1287
|
+
)
|
|
1288
|
+
|
|
1289
|
+
content += update_section
|
|
1290
|
+
dossier_path.write_text(content, encoding='utf-8')
|
|
1291
|
+
|
|
1292
|
+
return True
|
|
1293
|
+
|
|
1294
|
+
except Exception as e:
|
|
1295
|
+
log_cascading_action({
|
|
1296
|
+
'type': 'error',
|
|
1297
|
+
'action': 'update_theme_dossier',
|
|
1298
|
+
'path': str(dossier_path),
|
|
1299
|
+
'error': str(e)
|
|
1300
|
+
})
|
|
1301
|
+
return False
|
|
1302
|
+
|
|
1303
|
+
|
|
1304
|
+
def create_theme_dossier(dossier_path: Path, theme_name: str,
|
|
1305
|
+
batch_id: str, metadata: Dict,
|
|
1306
|
+
batch_content: str = None) -> bool:
|
|
1307
|
+
"""
|
|
1308
|
+
Cria novo theme dossier.
|
|
1309
|
+
|
|
1310
|
+
IMPORTANTE v2.0: Inclui CONTEUDO REAL dos frameworks, heuristicas e metodologias.
|
|
1311
|
+
"""
|
|
1312
|
+
try:
|
|
1313
|
+
content = f"""# DOSSIER - {theme_name}
|
|
1314
|
+
|
|
1315
|
+
> Dossier tematico gerado via cascateamento automatico.
|
|
1316
|
+
> **Versao Hook:** v2.0 (conteudo real extraido)
|
|
1317
|
+
|
|
1318
|
+
---
|
|
1319
|
+
|
|
1320
|
+
## Metadata
|
|
1321
|
+
|
|
1322
|
+
- **Versao:** v2.0.0
|
|
1323
|
+
- **Criado em:** {datetime.now().strftime('%Y-%m-%d')}
|
|
1324
|
+
- **Fonte inicial:** {metadata.get('source', 'Unknown')}
|
|
1325
|
+
- **Batch inicial:** {batch_id}
|
|
1326
|
+
|
|
1327
|
+
---
|
|
1328
|
+
|
|
1329
|
+
## Visao Geral
|
|
1330
|
+
|
|
1331
|
+
Este dossier consolida conhecimento sobre **{theme_name.replace('-', ' ').title()}**.
|
|
1332
|
+
|
|
1333
|
+
---
|
|
1334
|
+
|
|
1335
|
+
## Frameworks
|
|
1336
|
+
|
|
1337
|
+
"""
|
|
1338
|
+
# NOVO v2.0: Incluir conteudo REAL dos frameworks
|
|
1339
|
+
frameworks_content = metadata.get('frameworks_content', {})
|
|
1340
|
+
|
|
1341
|
+
for fw in metadata.get('frameworks', []):
|
|
1342
|
+
fw_content = frameworks_content.get(fw)
|
|
1343
|
+
if not fw_content and batch_content:
|
|
1344
|
+
fw_content = extract_framework_content(batch_content, fw)
|
|
1345
|
+
|
|
1346
|
+
if fw_content:
|
|
1347
|
+
content += f"### {fw}\n\n```\n{fw_content}\n```\n\n"
|
|
1348
|
+
else:
|
|
1349
|
+
content += f"### {fw}\n\n*Fonte: {batch_id}*\n\n"
|
|
1350
|
+
|
|
1351
|
+
content += f"""
|
|
1352
|
+
---
|
|
1353
|
+
|
|
1354
|
+
## Heuristicas
|
|
1355
|
+
|
|
1356
|
+
"""
|
|
1357
|
+
# Incluir bloco completo de heuristicas
|
|
1358
|
+
heur_content = metadata.get('heuristics_content', '')
|
|
1359
|
+
if heur_content:
|
|
1360
|
+
content += f"```\n{heur_content}\n```\n\n"
|
|
1361
|
+
else:
|
|
1362
|
+
for heur in metadata.get('heuristics', []):
|
|
1363
|
+
content += f"- {heur}\n"
|
|
1364
|
+
|
|
1365
|
+
content += f"""
|
|
1366
|
+
---
|
|
1367
|
+
|
|
1368
|
+
## Metodologias
|
|
1369
|
+
|
|
1370
|
+
"""
|
|
1371
|
+
# Incluir bloco completo de metodologias
|
|
1372
|
+
meth_content = metadata.get('methodologies_content', '')
|
|
1373
|
+
if meth_content:
|
|
1374
|
+
content += f"```\n{meth_content}\n```\n\n"
|
|
1375
|
+
else:
|
|
1376
|
+
for meth in metadata.get('methodologies', []):
|
|
1377
|
+
content += f"- {meth}\n"
|
|
1378
|
+
|
|
1379
|
+
# Incluir filosofias se disponivel
|
|
1380
|
+
fil_content = metadata.get('filosofias_content', '')
|
|
1381
|
+
if fil_content:
|
|
1382
|
+
content += f"""
|
|
1383
|
+
---
|
|
1384
|
+
|
|
1385
|
+
## Filosofias
|
|
1386
|
+
|
|
1387
|
+
```
|
|
1388
|
+
{fil_content}
|
|
1389
|
+
```
|
|
1390
|
+
|
|
1391
|
+
"""
|
|
1392
|
+
|
|
1393
|
+
# Incluir modelos mentais se disponivel
|
|
1394
|
+
mm_content = metadata.get('modelos_mentais_content', '')
|
|
1395
|
+
if mm_content:
|
|
1396
|
+
content += f"""
|
|
1397
|
+
---
|
|
1398
|
+
|
|
1399
|
+
## Modelos Mentais
|
|
1400
|
+
|
|
1401
|
+
```
|
|
1402
|
+
{mm_content}
|
|
1403
|
+
```
|
|
1404
|
+
|
|
1405
|
+
"""
|
|
1406
|
+
|
|
1407
|
+
content += f"""
|
|
1408
|
+
---
|
|
1409
|
+
|
|
1410
|
+
## Fontes
|
|
1411
|
+
|
|
1412
|
+
| Fonte | Batch | Data |
|
|
1413
|
+
|-------|-------|------|
|
|
1414
|
+
| {metadata.get('source', 'Unknown')} | {batch_id} | {datetime.now().strftime('%Y-%m-%d')} |
|
|
1415
|
+
|
|
1416
|
+
---
|
|
1417
|
+
|
|
1418
|
+
## Cross-References
|
|
1419
|
+
|
|
1420
|
+
*Conexoes com outros temas serao adicionadas em atualizacoes futuras.*
|
|
1421
|
+
"""
|
|
1422
|
+
|
|
1423
|
+
dossier_path.write_text(content, encoding='utf-8')
|
|
1424
|
+
return True
|
|
1425
|
+
|
|
1426
|
+
except Exception as e:
|
|
1427
|
+
log_cascading_action({
|
|
1428
|
+
'type': 'error',
|
|
1429
|
+
'action': 'create_theme_dossier',
|
|
1430
|
+
'path': str(dossier_path),
|
|
1431
|
+
'error': str(e)
|
|
1432
|
+
})
|
|
1433
|
+
return False
|
|
1434
|
+
|
|
1435
|
+
|
|
1436
|
+
#=================================
|
|
1437
|
+
# BATCH UPDATE
|
|
1438
|
+
#=================================
|
|
1439
|
+
|
|
1440
|
+
def mark_cascading_complete(batch_path: str, cascaded_items: Dict) -> bool:
|
|
1441
|
+
"""
|
|
1442
|
+
Adiciona secao 'Cascateamento Executado' ao batch.
|
|
1443
|
+
"""
|
|
1444
|
+
try:
|
|
1445
|
+
batch_file = Path(batch_path)
|
|
1446
|
+
content = batch_file.read_text(encoding='utf-8')
|
|
1447
|
+
|
|
1448
|
+
# Verificar se ja tem secao de cascateamento
|
|
1449
|
+
if 'Cascateamento Executado' in content:
|
|
1450
|
+
return True # Ja executado
|
|
1451
|
+
|
|
1452
|
+
# Criar secao de cascateamento
|
|
1453
|
+
cascade_section = f"""
|
|
1454
|
+
|
|
1455
|
+
---
|
|
1456
|
+
|
|
1457
|
+
## Cascateamento Executado
|
|
1458
|
+
|
|
1459
|
+
**Data:** {datetime.now().strftime('%Y-%m-%d %H:%M')}
|
|
1460
|
+
**Regra aplicada:** REGRA #22 (Cascateamento Multi-Destino)
|
|
1461
|
+
|
|
1462
|
+
### Resumo
|
|
1463
|
+
|
|
1464
|
+
| Tipo | Quantidade | Sucesso |
|
|
1465
|
+
|------|------------|---------|
|
|
1466
|
+
| Agentes | {len(cascaded_items.get('agents', []))} | {sum(1 for a in cascaded_items.get('agents', []) if a.get('success', False) or 'update' in a.get('action', ''))} |
|
|
1467
|
+
| Playbooks | {len(cascaded_items.get('playbooks', []))} | {sum(1 for p in cascaded_items.get('playbooks', []) if p.get('success', False))} |
|
|
1468
|
+
| DNAs | {len(cascaded_items.get('dnas', []))} | {sum(1 for d in cascaded_items.get('dnas', []) if d.get('success', False))} |
|
|
1469
|
+
| Dossiers | {len(cascaded_items.get('dossiers', []))} | {sum(1 for d in cascaded_items.get('dossiers', []) if d.get('success', False))} |
|
|
1470
|
+
|
|
1471
|
+
### Detalhes
|
|
1472
|
+
|
|
1473
|
+
"""
|
|
1474
|
+
|
|
1475
|
+
# Filtrar apenas chaves de cascateamento
|
|
1476
|
+
cascade_keys = ['agents', 'playbooks', 'dnas', 'dossiers']
|
|
1477
|
+
for action_type in cascade_keys:
|
|
1478
|
+
actions = cascaded_items.get(action_type, [])
|
|
1479
|
+
if actions and isinstance(actions, list):
|
|
1480
|
+
cascade_section += f"**{action_type.upper()}:**\n"
|
|
1481
|
+
for action in actions:
|
|
1482
|
+
if isinstance(action, dict):
|
|
1483
|
+
status = "OK" if action.get('success', False) else action.get('action', 'pending')
|
|
1484
|
+
name = action.get('agent') or action.get('playbook') or action.get('dna') or action.get('theme', 'unknown')
|
|
1485
|
+
cascade_section += f"- [{status}] {name}\n"
|
|
1486
|
+
cascade_section += "\n"
|
|
1487
|
+
|
|
1488
|
+
cascade_section += f"""
|
|
1489
|
+
---
|
|
1490
|
+
|
|
1491
|
+
*Cascateamento automatico via `post_batch_cascading.py`*
|
|
1492
|
+
"""
|
|
1493
|
+
|
|
1494
|
+
content += cascade_section
|
|
1495
|
+
batch_file.write_text(content, encoding='utf-8')
|
|
1496
|
+
|
|
1497
|
+
return True
|
|
1498
|
+
|
|
1499
|
+
except Exception as e:
|
|
1500
|
+
log_cascading_action({
|
|
1501
|
+
'type': 'error',
|
|
1502
|
+
'action': 'mark_cascading_complete',
|
|
1503
|
+
'path': batch_path,
|
|
1504
|
+
'error': str(e)
|
|
1505
|
+
})
|
|
1506
|
+
return False
|
|
1507
|
+
|
|
1508
|
+
|
|
1509
|
+
#=================================
|
|
1510
|
+
# MAIN ENTRY POINT
|
|
1511
|
+
#=================================
|
|
1512
|
+
|
|
1513
|
+
def process_batch(batch_path: str) -> Dict:
|
|
1514
|
+
"""
|
|
1515
|
+
Processa um batch e executa cascateamento completo.
|
|
1516
|
+
|
|
1517
|
+
IMPORTANTE v2.0: Passa batch_content para extrair CONTEUDO REAL dos frameworks.
|
|
1518
|
+
|
|
1519
|
+
Returns:
|
|
1520
|
+
Dicionario com resultados do cascateamento
|
|
1521
|
+
"""
|
|
1522
|
+
result = {
|
|
1523
|
+
'batch_path': batch_path,
|
|
1524
|
+
'success': False,
|
|
1525
|
+
'version': '2.0.0', # NOVO: versao do hook
|
|
1526
|
+
'content_extraction': True, # NOVO: indica que extrai conteudo real
|
|
1527
|
+
'agents': [],
|
|
1528
|
+
'playbooks': [],
|
|
1529
|
+
'dnas': [],
|
|
1530
|
+
'dossiers': [],
|
|
1531
|
+
'errors': []
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
try:
|
|
1535
|
+
# Ler conteudo do batch
|
|
1536
|
+
batch_file = Path(batch_path)
|
|
1537
|
+
if not batch_file.exists():
|
|
1538
|
+
result['errors'].append(f"Batch file not found: {batch_path}")
|
|
1539
|
+
return result
|
|
1540
|
+
|
|
1541
|
+
batch_content = batch_file.read_text(encoding='utf-8')
|
|
1542
|
+
|
|
1543
|
+
# Extrair metadados (agora inclui conteudo real dos frameworks)
|
|
1544
|
+
metadata = extract_batch_metadata(batch_content)
|
|
1545
|
+
batch_id = metadata.get('batch_id', batch_file.stem)
|
|
1546
|
+
|
|
1547
|
+
log_cascading_action({
|
|
1548
|
+
'type': 'batch_cascade_start',
|
|
1549
|
+
'batch_id': batch_id,
|
|
1550
|
+
'batch_path': batch_path,
|
|
1551
|
+
'version': '2.0.0',
|
|
1552
|
+
'frameworks_extracted': len(metadata.get('frameworks_content', {}))
|
|
1553
|
+
})
|
|
1554
|
+
|
|
1555
|
+
# Extrair destinos
|
|
1556
|
+
destinations = extract_destinations(batch_content)
|
|
1557
|
+
|
|
1558
|
+
# Executar cascateamento para cada tipo
|
|
1559
|
+
# NOVO v2.0: Passa batch_content para extrair conteudo real
|
|
1560
|
+
if destinations['agents']:
|
|
1561
|
+
result['agents'] = cascade_to_agents(
|
|
1562
|
+
destinations['agents'],
|
|
1563
|
+
batch_id,
|
|
1564
|
+
metadata,
|
|
1565
|
+
batch_content # NOVO
|
|
1566
|
+
)
|
|
1567
|
+
|
|
1568
|
+
if destinations['playbooks']:
|
|
1569
|
+
result['playbooks'] = cascade_to_playbooks(
|
|
1570
|
+
destinations['playbooks'],
|
|
1571
|
+
batch_id,
|
|
1572
|
+
metadata,
|
|
1573
|
+
batch_content # NOVO
|
|
1574
|
+
)
|
|
1575
|
+
|
|
1576
|
+
if destinations['dnas']:
|
|
1577
|
+
result['dnas'] = cascade_to_dnas(
|
|
1578
|
+
destinations['dnas'],
|
|
1579
|
+
batch_id,
|
|
1580
|
+
metadata
|
|
1581
|
+
)
|
|
1582
|
+
|
|
1583
|
+
if destinations['dossiers']:
|
|
1584
|
+
result['dossiers'] = cascade_to_dossiers(
|
|
1585
|
+
destinations['dossiers'],
|
|
1586
|
+
batch_id,
|
|
1587
|
+
metadata,
|
|
1588
|
+
batch_content # NOVO v2.0
|
|
1589
|
+
)
|
|
1590
|
+
|
|
1591
|
+
#=========================
|
|
1592
|
+
# REGRA #26: VALIDAÇÃO DE INTEGRIDADE DO CASCATEAMENTO
|
|
1593
|
+
# Só marca como completo se validação passar
|
|
1594
|
+
#=========================
|
|
1595
|
+
try:
|
|
1596
|
+
import sys
|
|
1597
|
+
scripts_path = str(Path(PROJECT_DIR) / 'scripts')
|
|
1598
|
+
if scripts_path not in sys.path:
|
|
1599
|
+
sys.path.insert(0, scripts_path)
|
|
1600
|
+
from validate_cascading_integrity import validate_batch_integrity
|
|
1601
|
+
|
|
1602
|
+
validation = validate_batch_integrity(batch_id)
|
|
1603
|
+
result['validation'] = {
|
|
1604
|
+
'status': validation['status'],
|
|
1605
|
+
'destinations_total': validation.get('destinations_total', 0),
|
|
1606
|
+
'destinations_exist': validation.get('destinations_exist', 0),
|
|
1607
|
+
'reference_count': validation.get('reference_count', 0)
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
if validation['status'] == 'FAILED':
|
|
1611
|
+
result['errors'].append(
|
|
1612
|
+
f"REGRA #26 Validation failed: {validation.get('error', 'Unknown')}"
|
|
1613
|
+
)
|
|
1614
|
+
log_cascading_action({
|
|
1615
|
+
'type': 'validation_failed',
|
|
1616
|
+
'batch_id': batch_id,
|
|
1617
|
+
'validation': validation
|
|
1618
|
+
})
|
|
1619
|
+
# Não marca como completo, retorna com erro
|
|
1620
|
+
return result
|
|
1621
|
+
|
|
1622
|
+
log_cascading_action({
|
|
1623
|
+
'type': 'validation_passed',
|
|
1624
|
+
'batch_id': batch_id,
|
|
1625
|
+
'status': validation['status']
|
|
1626
|
+
})
|
|
1627
|
+
|
|
1628
|
+
except ImportError as e:
|
|
1629
|
+
# Script não disponível - log warning mas continua
|
|
1630
|
+
log_cascading_action({
|
|
1631
|
+
'type': 'validation_warning',
|
|
1632
|
+
'batch_id': batch_id,
|
|
1633
|
+
'warning': f"Validation script not available: {e}"
|
|
1634
|
+
})
|
|
1635
|
+
except Exception as e:
|
|
1636
|
+
# Erro na validação - log warning mas continua (não bloqueia)
|
|
1637
|
+
log_cascading_action({
|
|
1638
|
+
'type': 'validation_error',
|
|
1639
|
+
'batch_id': batch_id,
|
|
1640
|
+
'error': str(e)
|
|
1641
|
+
})
|
|
1642
|
+
|
|
1643
|
+
# Marcar cascateamento como completo no batch
|
|
1644
|
+
mark_cascading_complete(batch_path, result)
|
|
1645
|
+
|
|
1646
|
+
result['success'] = True
|
|
1647
|
+
log_batch_result(batch_id, result)
|
|
1648
|
+
|
|
1649
|
+
except Exception as e:
|
|
1650
|
+
result['errors'].append(str(e))
|
|
1651
|
+
log_cascading_action({
|
|
1652
|
+
'type': 'error',
|
|
1653
|
+
'action': 'process_batch',
|
|
1654
|
+
'path': batch_path,
|
|
1655
|
+
'error': str(e)
|
|
1656
|
+
})
|
|
1657
|
+
|
|
1658
|
+
return result
|
|
1659
|
+
|
|
1660
|
+
|
|
1661
|
+
def main(batch_path: str = None):
|
|
1662
|
+
"""
|
|
1663
|
+
Entry point do hook.
|
|
1664
|
+
|
|
1665
|
+
Pode ser chamado de duas formas:
|
|
1666
|
+
1. Como hook: recebe input via stdin
|
|
1667
|
+
2. Diretamente: recebe batch_path como argumento
|
|
1668
|
+
"""
|
|
1669
|
+
import sys
|
|
1670
|
+
|
|
1671
|
+
if batch_path:
|
|
1672
|
+
# Chamada direta com path
|
|
1673
|
+
result = process_batch(batch_path)
|
|
1674
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
1675
|
+
return result
|
|
1676
|
+
|
|
1677
|
+
# Chamada como hook - ler stdin
|
|
1678
|
+
try:
|
|
1679
|
+
input_data = sys.stdin.read()
|
|
1680
|
+
hook_input = json.loads(input_data) if input_data else {}
|
|
1681
|
+
|
|
1682
|
+
# Extrair path do batch do input
|
|
1683
|
+
batch_path = hook_input.get('batch_path')
|
|
1684
|
+
|
|
1685
|
+
if not batch_path:
|
|
1686
|
+
# Tentar extrair de tool_input
|
|
1687
|
+
tool_input = hook_input.get('tool_input', {})
|
|
1688
|
+
batch_path = tool_input.get('file_path', '')
|
|
1689
|
+
|
|
1690
|
+
# Verificar se e um arquivo de batch
|
|
1691
|
+
if 'BATCH' not in batch_path.upper():
|
|
1692
|
+
output = {
|
|
1693
|
+
'continue': True,
|
|
1694
|
+
'feedback': None,
|
|
1695
|
+
'note': 'Not a batch file, skipping cascading'
|
|
1696
|
+
}
|
|
1697
|
+
print(json.dumps(output))
|
|
1698
|
+
return
|
|
1699
|
+
|
|
1700
|
+
# Processar batch
|
|
1701
|
+
result = process_batch(batch_path)
|
|
1702
|
+
|
|
1703
|
+
# Preparar output do hook
|
|
1704
|
+
feedback = None
|
|
1705
|
+
if result['success']:
|
|
1706
|
+
total_cascaded = (
|
|
1707
|
+
len(result['agents']) +
|
|
1708
|
+
len(result['playbooks']) +
|
|
1709
|
+
len(result['dnas']) +
|
|
1710
|
+
len(result['dossiers'])
|
|
1711
|
+
)
|
|
1712
|
+
if total_cascaded > 0:
|
|
1713
|
+
feedback = f"[JARVIS] REGRA #22: Cascateamento executado - {total_cascaded} destinos processados"
|
|
1714
|
+
else:
|
|
1715
|
+
if result['errors']:
|
|
1716
|
+
feedback = f"[JARVIS] REGRA #22: Erro no cascateamento - {result['errors'][0]}"
|
|
1717
|
+
|
|
1718
|
+
output = {
|
|
1719
|
+
'continue': True,
|
|
1720
|
+
'feedback': feedback,
|
|
1721
|
+
'result': result
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
print(json.dumps(output))
|
|
1725
|
+
|
|
1726
|
+
except Exception as e:
|
|
1727
|
+
error_output = {
|
|
1728
|
+
'continue': True,
|
|
1729
|
+
'feedback': f"[JARVIS] Erro no hook de cascateamento: {str(e)}",
|
|
1730
|
+
'error': str(e)
|
|
1731
|
+
}
|
|
1732
|
+
print(json.dumps(error_output))
|
|
1733
|
+
|
|
1734
|
+
|
|
1735
|
+
if __name__ == "__main__":
|
|
1736
|
+
import sys
|
|
1737
|
+
if len(sys.argv) > 1:
|
|
1738
|
+
main(sys.argv[1])
|
|
1739
|
+
else:
|
|
1740
|
+
main()
|