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,1135 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
SESSION AUTOSAVE V2 - REGRA #11 ENFORCEMENT
|
|
4
|
+
============================================
|
|
5
|
+
|
|
6
|
+
Sistema de auto-save robusto para sessoes do JARVIS.
|
|
7
|
+
Garante que NUNCA mais se perde contexto entre sessoes.
|
|
8
|
+
|
|
9
|
+
TRIGGERS DE AUTO-SAVE:
|
|
10
|
+
- Apos completar qualquer batch
|
|
11
|
+
- Apos qualquer tarefa significativa
|
|
12
|
+
- A cada 30 minutos de atividade
|
|
13
|
+
- Antes de operacoes destrutivas
|
|
14
|
+
- Quando detectar pausa prolongada (>10 min sem atividade)
|
|
15
|
+
- Quando usuario mencionar que vai sair
|
|
16
|
+
- Manualmente via /save
|
|
17
|
+
|
|
18
|
+
CONTEUDO DO SESSION LOG:
|
|
19
|
+
- Estado da missao (fase, progresso)
|
|
20
|
+
- Resumo da conversa atual
|
|
21
|
+
- Acoes executadas com detalhes
|
|
22
|
+
- Arquivos modificados
|
|
23
|
+
- Pendencias identificadas
|
|
24
|
+
- Decisoes tomadas e razoes
|
|
25
|
+
- Proximos passos planejados
|
|
26
|
+
- Notas importantes
|
|
27
|
+
|
|
28
|
+
Author: JARVIS
|
|
29
|
+
Version: 2.0.0
|
|
30
|
+
Date: 2026-01-11
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
import os
|
|
34
|
+
import json
|
|
35
|
+
import hashlib
|
|
36
|
+
from pathlib import Path
|
|
37
|
+
from datetime import datetime, timedelta
|
|
38
|
+
from typing import Optional, List, Dict, Any
|
|
39
|
+
from dataclasses import dataclass, field, asdict
|
|
40
|
+
from enum import Enum
|
|
41
|
+
import threading
|
|
42
|
+
import atexit
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
#=================================
|
|
46
|
+
# CONFIGURATION
|
|
47
|
+
#=================================
|
|
48
|
+
|
|
49
|
+
class Config:
|
|
50
|
+
"""Configuracao centralizada do sistema de autosave."""
|
|
51
|
+
|
|
52
|
+
# Diretorios
|
|
53
|
+
PROJECT_DIR = Path(os.environ.get('CLAUDE_PROJECT_DIR', '.'))
|
|
54
|
+
SESSIONS_DIR = PROJECT_DIR / ".claude" / "sessions"
|
|
55
|
+
MISSION_CONTROL_DIR = PROJECT_DIR / ".claude" / "mission-control"
|
|
56
|
+
LOGS_DIR = PROJECT_DIR / "logs"
|
|
57
|
+
HANDOFFS_DIR = LOGS_DIR / "handoffs"
|
|
58
|
+
|
|
59
|
+
# Arquivos principais
|
|
60
|
+
LATEST_SESSION = SESSIONS_DIR / "LATEST-SESSION.md"
|
|
61
|
+
MISSION_STATE = MISSION_CONTROL_DIR / "MISSION-STATE.json"
|
|
62
|
+
JARVIS_STATE = PROJECT_DIR / "system" / "JARVIS-STATE.json"
|
|
63
|
+
AUTOSAVE_STATE = MISSION_CONTROL_DIR / "AUTOSAVE-STATE.json"
|
|
64
|
+
|
|
65
|
+
# Timings (em segundos)
|
|
66
|
+
AUTO_SAVE_INTERVAL = 1800 # 30 minutos
|
|
67
|
+
PAUSE_DETECTION_THRESHOLD = 600 # 10 minutos
|
|
68
|
+
MIN_SAVE_INTERVAL = 60 # Minimo 1 minuto entre saves
|
|
69
|
+
|
|
70
|
+
# Thresholds
|
|
71
|
+
MAX_UNSAVED_ACTIONS = 10 # Salva se tiver mais que isso
|
|
72
|
+
MAX_UNSAVED_FILES = 5 # Salva se modificar mais que isso
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class SaveTrigger(Enum):
|
|
76
|
+
"""Tipos de trigger para auto-save."""
|
|
77
|
+
BATCH_COMPLETE = "batch_complete"
|
|
78
|
+
TASK_COMPLETE = "task_complete"
|
|
79
|
+
TIME_INTERVAL = "time_interval"
|
|
80
|
+
DESTRUCTIVE_OP = "destructive_operation"
|
|
81
|
+
PAUSE_DETECTED = "pause_detected"
|
|
82
|
+
USER_EXIT = "user_exit"
|
|
83
|
+
MANUAL = "manual"
|
|
84
|
+
ACTION_THRESHOLD = "action_threshold"
|
|
85
|
+
FILE_THRESHOLD = "file_threshold"
|
|
86
|
+
SESSION_START = "session_start"
|
|
87
|
+
SESSION_END = "session_end"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class ActionType(Enum):
|
|
91
|
+
"""Tipos de acao registraveis."""
|
|
92
|
+
BATCH_PROCESS = "batch_process"
|
|
93
|
+
FILE_CREATE = "file_create"
|
|
94
|
+
FILE_MODIFY = "file_modify"
|
|
95
|
+
FILE_DELETE = "file_delete"
|
|
96
|
+
PHASE_CHANGE = "phase_change"
|
|
97
|
+
DECISION = "decision"
|
|
98
|
+
COMMAND = "command"
|
|
99
|
+
SEARCH = "search"
|
|
100
|
+
ANALYSIS = "analysis"
|
|
101
|
+
OTHER = "other"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
#=================================
|
|
105
|
+
# DATA CLASSES
|
|
106
|
+
#=================================
|
|
107
|
+
|
|
108
|
+
@dataclass
|
|
109
|
+
class Action:
|
|
110
|
+
"""Representa uma acao registrada na sessao."""
|
|
111
|
+
timestamp: str
|
|
112
|
+
action_type: str
|
|
113
|
+
description: str
|
|
114
|
+
details: Dict[str, Any] = field(default_factory=dict)
|
|
115
|
+
files_affected: List[str] = field(default_factory=list)
|
|
116
|
+
|
|
117
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
118
|
+
return asdict(self)
|
|
119
|
+
|
|
120
|
+
@classmethod
|
|
121
|
+
def from_dict(cls, data: Dict[str, Any]) -> 'Action':
|
|
122
|
+
return cls(**data)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@dataclass
|
|
126
|
+
class FileModification:
|
|
127
|
+
"""Representa uma modificacao de arquivo."""
|
|
128
|
+
filepath: str
|
|
129
|
+
operation: str # created, modified, deleted
|
|
130
|
+
timestamp: str
|
|
131
|
+
size_before: Optional[int] = None
|
|
132
|
+
size_after: Optional[int] = None
|
|
133
|
+
|
|
134
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
135
|
+
return asdict(self)
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
def from_dict(cls, data: Dict[str, Any]) -> 'FileModification':
|
|
139
|
+
return cls(**data)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@dataclass
|
|
143
|
+
class SessionData:
|
|
144
|
+
"""Dados completos de uma sessao."""
|
|
145
|
+
session_id: str
|
|
146
|
+
started_at: str
|
|
147
|
+
last_activity: str
|
|
148
|
+
last_save: Optional[str]
|
|
149
|
+
save_count: int
|
|
150
|
+
mission_state: Dict[str, Any]
|
|
151
|
+
actions: List[Action]
|
|
152
|
+
files_modified: List[FileModification]
|
|
153
|
+
pending_tasks: List[str]
|
|
154
|
+
decisions: List[Dict[str, Any]]
|
|
155
|
+
next_steps: List[str]
|
|
156
|
+
notes: List[str]
|
|
157
|
+
conversation_summary: str
|
|
158
|
+
|
|
159
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
160
|
+
data = asdict(self)
|
|
161
|
+
data['actions'] = [a.to_dict() if isinstance(a, Action) else a for a in self.actions]
|
|
162
|
+
data['files_modified'] = [f.to_dict() if isinstance(f, FileModification) else f for f in self.files_modified]
|
|
163
|
+
return data
|
|
164
|
+
|
|
165
|
+
@classmethod
|
|
166
|
+
def from_dict(cls, data: Dict[str, Any]) -> 'SessionData':
|
|
167
|
+
data['actions'] = [Action.from_dict(a) if isinstance(a, dict) else a for a in data.get('actions', [])]
|
|
168
|
+
data['files_modified'] = [FileModification.from_dict(f) if isinstance(f, dict) else f for f in data.get('files_modified', [])]
|
|
169
|
+
return cls(**data)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
#=================================
|
|
173
|
+
# SESSION MANAGER
|
|
174
|
+
#=================================
|
|
175
|
+
|
|
176
|
+
class SessionManager:
|
|
177
|
+
"""
|
|
178
|
+
Gerenciador principal de sessoes.
|
|
179
|
+
Implementa REGRA #11 do CLAUDE.md.
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
_instance: Optional['SessionManager'] = None
|
|
183
|
+
_lock = threading.Lock()
|
|
184
|
+
|
|
185
|
+
def __new__(cls):
|
|
186
|
+
"""Singleton pattern para garantir uma unica instancia."""
|
|
187
|
+
if cls._instance is None:
|
|
188
|
+
with cls._lock:
|
|
189
|
+
if cls._instance is None:
|
|
190
|
+
cls._instance = super().__new__(cls)
|
|
191
|
+
cls._instance._initialized = False
|
|
192
|
+
return cls._instance
|
|
193
|
+
|
|
194
|
+
def __init__(self):
|
|
195
|
+
if self._initialized:
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
self._initialized = True
|
|
199
|
+
self._ensure_directories()
|
|
200
|
+
self._load_or_create_session()
|
|
201
|
+
|
|
202
|
+
# Registrar save no encerramento
|
|
203
|
+
atexit.register(self._on_exit)
|
|
204
|
+
|
|
205
|
+
def _ensure_directories(self):
|
|
206
|
+
"""Garante que todos os diretorios existam."""
|
|
207
|
+
for directory in [Config.SESSIONS_DIR, Config.MISSION_CONTROL_DIR,
|
|
208
|
+
Config.LOGS_DIR, Config.HANDOFFS_DIR]:
|
|
209
|
+
directory.mkdir(parents=True, exist_ok=True)
|
|
210
|
+
|
|
211
|
+
def _generate_session_id(self) -> str:
|
|
212
|
+
"""Gera ID unico para a sessao."""
|
|
213
|
+
now = datetime.now()
|
|
214
|
+
return f"SESSION-{now.strftime('%Y-%m-%d-%H%M')}"
|
|
215
|
+
|
|
216
|
+
def _load_or_create_session(self):
|
|
217
|
+
"""Carrega sessao existente ou cria nova."""
|
|
218
|
+
if Config.AUTOSAVE_STATE.exists():
|
|
219
|
+
try:
|
|
220
|
+
with open(Config.AUTOSAVE_STATE, 'r', encoding='utf-8') as f:
|
|
221
|
+
state = json.load(f)
|
|
222
|
+
|
|
223
|
+
# Verificar se sessao ainda e valida (menos de 2 horas)
|
|
224
|
+
last_activity = datetime.fromisoformat(state.get('last_activity', '2000-01-01'))
|
|
225
|
+
if datetime.now() - last_activity < timedelta(hours=2):
|
|
226
|
+
self.session = SessionData.from_dict(state)
|
|
227
|
+
self.session.last_activity = datetime.now().isoformat()
|
|
228
|
+
return
|
|
229
|
+
except Exception:
|
|
230
|
+
pass
|
|
231
|
+
|
|
232
|
+
# Criar nova sessao
|
|
233
|
+
self.session = self._create_new_session()
|
|
234
|
+
|
|
235
|
+
def _create_new_session(self) -> SessionData:
|
|
236
|
+
"""Cria uma nova sessao."""
|
|
237
|
+
now = datetime.now().isoformat()
|
|
238
|
+
mission_state = self._load_mission_state()
|
|
239
|
+
|
|
240
|
+
return SessionData(
|
|
241
|
+
session_id=self._generate_session_id(),
|
|
242
|
+
started_at=now,
|
|
243
|
+
last_activity=now,
|
|
244
|
+
last_save=None,
|
|
245
|
+
save_count=0,
|
|
246
|
+
mission_state=mission_state,
|
|
247
|
+
actions=[],
|
|
248
|
+
files_modified=[],
|
|
249
|
+
pending_tasks=[],
|
|
250
|
+
decisions=[],
|
|
251
|
+
next_steps=[],
|
|
252
|
+
notes=[],
|
|
253
|
+
conversation_summary=""
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
def _load_mission_state(self) -> Dict[str, Any]:
|
|
257
|
+
"""Carrega estado da missao do MISSION-STATE.json."""
|
|
258
|
+
if Config.MISSION_STATE.exists():
|
|
259
|
+
try:
|
|
260
|
+
with open(Config.MISSION_STATE, 'r', encoding='utf-8') as f:
|
|
261
|
+
return json.load(f)
|
|
262
|
+
except Exception:
|
|
263
|
+
pass
|
|
264
|
+
return {"status": "unknown", "message": "MISSION-STATE.json nao encontrado"}
|
|
265
|
+
|
|
266
|
+
def _load_jarvis_state(self) -> Dict[str, Any]:
|
|
267
|
+
"""Carrega estado do JARVIS."""
|
|
268
|
+
if Config.JARVIS_STATE.exists():
|
|
269
|
+
try:
|
|
270
|
+
with open(Config.JARVIS_STATE, 'r', encoding='utf-8') as f:
|
|
271
|
+
return json.load(f)
|
|
272
|
+
except Exception:
|
|
273
|
+
pass
|
|
274
|
+
return {}
|
|
275
|
+
|
|
276
|
+
#=============================
|
|
277
|
+
# LOGGING ACTIONS
|
|
278
|
+
#=============================
|
|
279
|
+
|
|
280
|
+
def log_action(self,
|
|
281
|
+
action_type: ActionType,
|
|
282
|
+
description: str,
|
|
283
|
+
details: Dict[str, Any] = None,
|
|
284
|
+
files_affected: List[str] = None) -> None:
|
|
285
|
+
"""
|
|
286
|
+
Registra uma acao na sessao.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
action_type: Tipo da acao (ActionType enum)
|
|
290
|
+
description: Descricao legivel da acao
|
|
291
|
+
details: Detalhes adicionais (opcional)
|
|
292
|
+
files_affected: Lista de arquivos afetados (opcional)
|
|
293
|
+
"""
|
|
294
|
+
action = Action(
|
|
295
|
+
timestamp=datetime.now().isoformat(),
|
|
296
|
+
action_type=action_type.value if isinstance(action_type, ActionType) else str(action_type),
|
|
297
|
+
description=description,
|
|
298
|
+
details=details or {},
|
|
299
|
+
files_affected=files_affected or []
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
self.session.actions.append(action)
|
|
303
|
+
self.session.last_activity = datetime.now().isoformat()
|
|
304
|
+
|
|
305
|
+
# Verificar se deve salvar (threshold de acoes)
|
|
306
|
+
if len(self.session.actions) >= Config.MAX_UNSAVED_ACTIONS:
|
|
307
|
+
self._check_and_save(SaveTrigger.ACTION_THRESHOLD)
|
|
308
|
+
|
|
309
|
+
# Persistir estado temporario
|
|
310
|
+
self._save_autosave_state()
|
|
311
|
+
|
|
312
|
+
def log_file_modified(self,
|
|
313
|
+
filepath: str,
|
|
314
|
+
operation: str = "modified",
|
|
315
|
+
size_before: int = None,
|
|
316
|
+
size_after: int = None) -> None:
|
|
317
|
+
"""
|
|
318
|
+
Registra modificacao de arquivo.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
filepath: Caminho do arquivo
|
|
322
|
+
operation: Tipo de operacao (created, modified, deleted)
|
|
323
|
+
size_before: Tamanho antes (opcional)
|
|
324
|
+
size_after: Tamanho depois (opcional)
|
|
325
|
+
"""
|
|
326
|
+
mod = FileModification(
|
|
327
|
+
filepath=filepath,
|
|
328
|
+
operation=operation,
|
|
329
|
+
timestamp=datetime.now().isoformat(),
|
|
330
|
+
size_before=size_before,
|
|
331
|
+
size_after=size_after
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
self.session.files_modified.append(mod)
|
|
335
|
+
self.session.last_activity = datetime.now().isoformat()
|
|
336
|
+
|
|
337
|
+
# Verificar se deve salvar (threshold de arquivos)
|
|
338
|
+
if len(self.session.files_modified) >= Config.MAX_UNSAVED_FILES:
|
|
339
|
+
self._check_and_save(SaveTrigger.FILE_THRESHOLD)
|
|
340
|
+
|
|
341
|
+
self._save_autosave_state()
|
|
342
|
+
|
|
343
|
+
def log_decision(self,
|
|
344
|
+
decision: str,
|
|
345
|
+
reasoning: str,
|
|
346
|
+
alternatives: List[str] = None) -> None:
|
|
347
|
+
"""
|
|
348
|
+
Registra uma decisao tomada.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
decision: A decisao tomada
|
|
352
|
+
reasoning: Raciocinio por tras
|
|
353
|
+
alternatives: Alternativas consideradas
|
|
354
|
+
"""
|
|
355
|
+
self.session.decisions.append({
|
|
356
|
+
'timestamp': datetime.now().isoformat(),
|
|
357
|
+
'decision': decision,
|
|
358
|
+
'reasoning': reasoning,
|
|
359
|
+
'alternatives': alternatives or []
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
self.session.last_activity = datetime.now().isoformat()
|
|
363
|
+
self._save_autosave_state()
|
|
364
|
+
|
|
365
|
+
def add_pending_task(self, task: str) -> None:
|
|
366
|
+
"""Adiciona tarefa pendente."""
|
|
367
|
+
if task not in self.session.pending_tasks:
|
|
368
|
+
self.session.pending_tasks.append(task)
|
|
369
|
+
self._save_autosave_state()
|
|
370
|
+
|
|
371
|
+
def complete_pending_task(self, task: str) -> None:
|
|
372
|
+
"""Marca tarefa como completa."""
|
|
373
|
+
if task in self.session.pending_tasks:
|
|
374
|
+
self.session.pending_tasks.remove(task)
|
|
375
|
+
self._save_autosave_state()
|
|
376
|
+
|
|
377
|
+
def add_next_step(self, step: str) -> None:
|
|
378
|
+
"""Adiciona proximo passo planejado."""
|
|
379
|
+
if step not in self.session.next_steps:
|
|
380
|
+
self.session.next_steps.append(step)
|
|
381
|
+
self._save_autosave_state()
|
|
382
|
+
|
|
383
|
+
def add_note(self, note: str) -> None:
|
|
384
|
+
"""Adiciona nota importante."""
|
|
385
|
+
timestamped_note = f"[{datetime.now().strftime('%H:%M')}] {note}"
|
|
386
|
+
self.session.notes.append(timestamped_note)
|
|
387
|
+
self._save_autosave_state()
|
|
388
|
+
|
|
389
|
+
def update_conversation_summary(self, summary: str) -> None:
|
|
390
|
+
"""Atualiza resumo da conversa."""
|
|
391
|
+
self.session.conversation_summary = summary
|
|
392
|
+
self._save_autosave_state()
|
|
393
|
+
|
|
394
|
+
#=============================
|
|
395
|
+
# SAVE TRIGGERS
|
|
396
|
+
#=============================
|
|
397
|
+
|
|
398
|
+
def trigger_batch_complete(self, batch_id: str, details: Dict = None) -> str:
|
|
399
|
+
"""Trigger: Batch completado."""
|
|
400
|
+
self.log_action(
|
|
401
|
+
ActionType.BATCH_PROCESS,
|
|
402
|
+
f"Batch {batch_id} completado",
|
|
403
|
+
details
|
|
404
|
+
)
|
|
405
|
+
return self.save(SaveTrigger.BATCH_COMPLETE)
|
|
406
|
+
|
|
407
|
+
def trigger_task_complete(self, task_name: str, details: Dict = None) -> str:
|
|
408
|
+
"""Trigger: Tarefa significativa completada."""
|
|
409
|
+
self.log_action(
|
|
410
|
+
ActionType.OTHER,
|
|
411
|
+
f"Tarefa completada: {task_name}",
|
|
412
|
+
details
|
|
413
|
+
)
|
|
414
|
+
return self.save(SaveTrigger.TASK_COMPLETE)
|
|
415
|
+
|
|
416
|
+
def trigger_destructive_operation(self, operation: str) -> str:
|
|
417
|
+
"""Trigger: Antes de operacao destrutiva."""
|
|
418
|
+
self.add_note(f"ALERTA: Operacao destrutiva iminente - {operation}")
|
|
419
|
+
return self.save(SaveTrigger.DESTRUCTIVE_OP)
|
|
420
|
+
|
|
421
|
+
def trigger_user_exit(self) -> str:
|
|
422
|
+
"""Trigger: Usuario mencionou que vai sair."""
|
|
423
|
+
return self.save(SaveTrigger.USER_EXIT)
|
|
424
|
+
|
|
425
|
+
def trigger_phase_change(self, old_phase: int, new_phase: int) -> str:
|
|
426
|
+
"""Trigger: Mudanca de fase."""
|
|
427
|
+
self.log_action(
|
|
428
|
+
ActionType.PHASE_CHANGE,
|
|
429
|
+
f"Mudanca de fase: {old_phase} -> {new_phase}"
|
|
430
|
+
)
|
|
431
|
+
return self.save(SaveTrigger.TASK_COMPLETE)
|
|
432
|
+
|
|
433
|
+
#=============================
|
|
434
|
+
# CORE SAVE LOGIC
|
|
435
|
+
#=============================
|
|
436
|
+
|
|
437
|
+
def should_save(self, trigger: SaveTrigger = None) -> bool:
|
|
438
|
+
"""
|
|
439
|
+
Verifica se deve salvar baseado em triggers.
|
|
440
|
+
|
|
441
|
+
Returns:
|
|
442
|
+
True se deve salvar, False caso contrario
|
|
443
|
+
"""
|
|
444
|
+
# Sempre salva em triggers criticos
|
|
445
|
+
critical_triggers = [
|
|
446
|
+
SaveTrigger.BATCH_COMPLETE,
|
|
447
|
+
SaveTrigger.DESTRUCTIVE_OP,
|
|
448
|
+
SaveTrigger.USER_EXIT,
|
|
449
|
+
SaveTrigger.SESSION_END,
|
|
450
|
+
SaveTrigger.MANUAL
|
|
451
|
+
]
|
|
452
|
+
|
|
453
|
+
if trigger in critical_triggers:
|
|
454
|
+
return True
|
|
455
|
+
|
|
456
|
+
# Verificar intervalo minimo
|
|
457
|
+
if self.session.last_save:
|
|
458
|
+
last_save_time = datetime.fromisoformat(self.session.last_save)
|
|
459
|
+
if datetime.now() - last_save_time < timedelta(seconds=Config.MIN_SAVE_INTERVAL):
|
|
460
|
+
return False
|
|
461
|
+
|
|
462
|
+
# Verificar intervalo de tempo (30 min)
|
|
463
|
+
if self.session.last_save:
|
|
464
|
+
last_save_time = datetime.fromisoformat(self.session.last_save)
|
|
465
|
+
if datetime.now() - last_save_time > timedelta(seconds=Config.AUTO_SAVE_INTERVAL):
|
|
466
|
+
return True
|
|
467
|
+
else:
|
|
468
|
+
# Nunca salvou, e passou tempo desde inicio
|
|
469
|
+
start_time = datetime.fromisoformat(self.session.started_at)
|
|
470
|
+
if datetime.now() - start_time > timedelta(seconds=Config.AUTO_SAVE_INTERVAL):
|
|
471
|
+
return True
|
|
472
|
+
|
|
473
|
+
# Verificar threshold de acoes
|
|
474
|
+
if len(self.session.actions) >= Config.MAX_UNSAVED_ACTIONS:
|
|
475
|
+
return True
|
|
476
|
+
|
|
477
|
+
# Verificar threshold de arquivos
|
|
478
|
+
if len(self.session.files_modified) >= Config.MAX_UNSAVED_FILES:
|
|
479
|
+
return True
|
|
480
|
+
|
|
481
|
+
# Verificar pausa prolongada
|
|
482
|
+
last_activity = datetime.fromisoformat(self.session.last_activity)
|
|
483
|
+
if datetime.now() - last_activity > timedelta(seconds=Config.PAUSE_DETECTION_THRESHOLD):
|
|
484
|
+
return True
|
|
485
|
+
|
|
486
|
+
return False
|
|
487
|
+
|
|
488
|
+
def _check_and_save(self, trigger: SaveTrigger) -> Optional[str]:
|
|
489
|
+
"""Verifica e salva se necessario."""
|
|
490
|
+
if self.should_save(trigger):
|
|
491
|
+
return self.save(trigger)
|
|
492
|
+
return None
|
|
493
|
+
|
|
494
|
+
def save(self, trigger: SaveTrigger = SaveTrigger.MANUAL) -> str:
|
|
495
|
+
"""
|
|
496
|
+
Salva estado da sessao.
|
|
497
|
+
|
|
498
|
+
Args:
|
|
499
|
+
trigger: O que disparou o save
|
|
500
|
+
|
|
501
|
+
Returns:
|
|
502
|
+
Caminho do arquivo de sessao salvo
|
|
503
|
+
"""
|
|
504
|
+
now = datetime.now()
|
|
505
|
+
|
|
506
|
+
# Atualizar estado da missao
|
|
507
|
+
self.session.mission_state = self._load_mission_state()
|
|
508
|
+
self.session.last_save = now.isoformat()
|
|
509
|
+
self.session.save_count += 1
|
|
510
|
+
|
|
511
|
+
# Gerar conteudo do arquivo de sessao
|
|
512
|
+
session_content = self._format_session_markdown(trigger)
|
|
513
|
+
|
|
514
|
+
# Salvar arquivo da sessao
|
|
515
|
+
session_filename = f"{self.session.session_id}.md"
|
|
516
|
+
session_filepath = Config.SESSIONS_DIR / session_filename
|
|
517
|
+
|
|
518
|
+
with open(session_filepath, 'w', encoding='utf-8') as f:
|
|
519
|
+
f.write(session_content)
|
|
520
|
+
|
|
521
|
+
# Atualizar LATEST-SESSION.md
|
|
522
|
+
self._update_latest_session(session_content, trigger)
|
|
523
|
+
|
|
524
|
+
# Salvar estado do autosave
|
|
525
|
+
self._save_autosave_state()
|
|
526
|
+
|
|
527
|
+
# Criar HANDOFF se trigger critico
|
|
528
|
+
if trigger in [SaveTrigger.USER_EXIT, SaveTrigger.SESSION_END]:
|
|
529
|
+
self._create_handoff()
|
|
530
|
+
|
|
531
|
+
return str(session_filepath)
|
|
532
|
+
|
|
533
|
+
def _save_autosave_state(self):
|
|
534
|
+
"""Salva estado temporario do autosave."""
|
|
535
|
+
try:
|
|
536
|
+
with open(Config.AUTOSAVE_STATE, 'w', encoding='utf-8') as f:
|
|
537
|
+
json.dump(self.session.to_dict(), f, indent=2, ensure_ascii=False)
|
|
538
|
+
except Exception as e:
|
|
539
|
+
print(f"[JARVIS] Erro ao salvar autosave state: {e}")
|
|
540
|
+
|
|
541
|
+
def _update_latest_session(self, content: str, trigger: SaveTrigger):
|
|
542
|
+
"""Atualiza LATEST-SESSION.md."""
|
|
543
|
+
latest_content = f"""# LATEST SESSION - Auto-Updated
|
|
544
|
+
|
|
545
|
+
**Session ID:** {self.session.session_id}
|
|
546
|
+
**Last Save:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
|
547
|
+
**Trigger:** {trigger.value}
|
|
548
|
+
**Save Count:** {self.session.save_count}
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
{content}
|
|
553
|
+
"""
|
|
554
|
+
|
|
555
|
+
with open(Config.LATEST_SESSION, 'w', encoding='utf-8') as f:
|
|
556
|
+
f.write(latest_content)
|
|
557
|
+
|
|
558
|
+
def _create_handoff(self):
|
|
559
|
+
"""Cria arquivo HANDOFF para proxima sessao."""
|
|
560
|
+
timestamp = datetime.now().strftime('%Y%m%d-%H%M%S')
|
|
561
|
+
handoff_file = Config.HANDOFFS_DIR / f"HANDOFF-{timestamp}.md"
|
|
562
|
+
|
|
563
|
+
mission = self.session.mission_state
|
|
564
|
+
current_state = mission.get('current_state', {})
|
|
565
|
+
|
|
566
|
+
content = f"""# HANDOFF - {datetime.now().strftime('%Y-%m-%d %H:%M')}
|
|
567
|
+
|
|
568
|
+
> **Gerado por:** Session Autosave V2
|
|
569
|
+
> **Session ID:** {self.session.session_id}
|
|
570
|
+
> **Save Count:** {self.session.save_count}
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
## ESTADO ATUAL DA MISSAO
|
|
575
|
+
|
|
576
|
+
| Campo | Valor |
|
|
577
|
+
|-------|-------|
|
|
578
|
+
| Fase | {current_state.get('phase', 'N/A')} - {current_state.get('phase_name', 'N/A')} |
|
|
579
|
+
| Status | {current_state.get('status', 'N/A')} |
|
|
580
|
+
| Progresso | {current_state.get('percent_complete', 0):.1f}% |
|
|
581
|
+
| Fonte Atual | {current_state.get('source_code', 'N/A')} |
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## ULTIMAS ACOES ({len(self.session.actions)})
|
|
586
|
+
|
|
587
|
+
"""
|
|
588
|
+
# Ultimas 10 acoes
|
|
589
|
+
for action in self.session.actions[-10:]:
|
|
590
|
+
if isinstance(action, Action):
|
|
591
|
+
content += f"- [{action.timestamp[-8:-3]}] {action.description}\n"
|
|
592
|
+
else:
|
|
593
|
+
content += f"- {action.get('description', 'Acao')}\n"
|
|
594
|
+
|
|
595
|
+
content += f"""
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## ARQUIVOS MODIFICADOS ({len(self.session.files_modified)})
|
|
600
|
+
|
|
601
|
+
"""
|
|
602
|
+
# Ultimos 10 arquivos
|
|
603
|
+
for mod in self.session.files_modified[-10:]:
|
|
604
|
+
if isinstance(mod, FileModification):
|
|
605
|
+
content += f"- `{mod.operation}`: {mod.filepath}\n"
|
|
606
|
+
else:
|
|
607
|
+
content += f"- `{mod.get('operation', 'mod')}`: {mod.get('filepath', '')}\n"
|
|
608
|
+
|
|
609
|
+
content += f"""
|
|
610
|
+
|
|
611
|
+
---
|
|
612
|
+
|
|
613
|
+
## PENDENCIAS ({len(self.session.pending_tasks)})
|
|
614
|
+
|
|
615
|
+
"""
|
|
616
|
+
for task in self.session.pending_tasks:
|
|
617
|
+
content += f"- [ ] {task}\n"
|
|
618
|
+
|
|
619
|
+
content += f"""
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
## PROXIMOS PASSOS ({len(self.session.next_steps)})
|
|
624
|
+
|
|
625
|
+
"""
|
|
626
|
+
for i, step in enumerate(self.session.next_steps, 1):
|
|
627
|
+
content += f"{i}. {step}\n"
|
|
628
|
+
|
|
629
|
+
content += f"""
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
## NOTAS IMPORTANTES
|
|
634
|
+
|
|
635
|
+
"""
|
|
636
|
+
for note in self.session.notes:
|
|
637
|
+
content += f"- {note}\n"
|
|
638
|
+
|
|
639
|
+
content += f"""
|
|
640
|
+
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
## PARA CONTINUAR
|
|
644
|
+
|
|
645
|
+
1. Execute `/resume` para carregar este contexto
|
|
646
|
+
2. Pergunte "onde paramos?" para status detalhado
|
|
647
|
+
3. JARVIS carregara memoria automaticamente
|
|
648
|
+
|
|
649
|
+
---
|
|
650
|
+
|
|
651
|
+
*Ready when you are, sir.*
|
|
652
|
+
*Auto-generated by Session Autosave V2*
|
|
653
|
+
"""
|
|
654
|
+
|
|
655
|
+
with open(handoff_file, 'w', encoding='utf-8') as f:
|
|
656
|
+
f.write(content)
|
|
657
|
+
|
|
658
|
+
# Atualizar link para ultimo HANDOFF
|
|
659
|
+
latest_handoff = Config.HANDOFFS_DIR / "HANDOFF-LATEST.md"
|
|
660
|
+
with open(latest_handoff, 'w', encoding='utf-8') as f:
|
|
661
|
+
f.write(content)
|
|
662
|
+
|
|
663
|
+
def _format_session_markdown(self, trigger: SaveTrigger) -> str:
|
|
664
|
+
"""Formata sessao em Markdown estruturado."""
|
|
665
|
+
now = datetime.now()
|
|
666
|
+
mission = self.session.mission_state
|
|
667
|
+
current_state = mission.get('current_state', {})
|
|
668
|
+
|
|
669
|
+
# Calcular estatisticas
|
|
670
|
+
actions_by_type = {}
|
|
671
|
+
for action in self.session.actions:
|
|
672
|
+
atype = action.action_type if isinstance(action, Action) else action.get('action_type', 'other')
|
|
673
|
+
actions_by_type[atype] = actions_by_type.get(atype, 0) + 1
|
|
674
|
+
|
|
675
|
+
files_by_op = {}
|
|
676
|
+
for mod in self.session.files_modified:
|
|
677
|
+
op = mod.operation if isinstance(mod, FileModification) else mod.get('operation', 'modified')
|
|
678
|
+
files_by_op[op] = files_by_op.get(op, 0) + 1
|
|
679
|
+
|
|
680
|
+
md = f"""# {self.session.session_id}
|
|
681
|
+
|
|
682
|
+
> **JARVIS Session Log - Autosave V2**
|
|
683
|
+
> **REGRA #11 Enforcement: Persistencia de Sessao Obrigatoria**
|
|
684
|
+
|
|
685
|
+
---
|
|
686
|
+
|
|
687
|
+
## META INFORMACAO
|
|
688
|
+
|
|
689
|
+
| Campo | Valor |
|
|
690
|
+
|-------|-------|
|
|
691
|
+
| **Session ID** | `{self.session.session_id}` |
|
|
692
|
+
| **Iniciada** | {self.session.started_at} |
|
|
693
|
+
| **Ultima Atividade** | {self.session.last_activity} |
|
|
694
|
+
| **Este Save** | {now.isoformat()} |
|
|
695
|
+
| **Trigger** | `{trigger.value}` |
|
|
696
|
+
| **Save Count** | {self.session.save_count} |
|
|
697
|
+
|
|
698
|
+
---
|
|
699
|
+
|
|
700
|
+
## ESTADO DA MISSAO
|
|
701
|
+
|
|
702
|
+
```
|
|
703
|
+
+{'='*70}+
|
|
704
|
+
|{'MISSION STATE':^70}|
|
|
705
|
+
+{'='*70}+
|
|
706
|
+
| Fase: {str(current_state.get('phase', 'N/A')):>3} - {current_state.get('phase_name', 'N/A'):<54} |
|
|
707
|
+
| Status: {current_state.get('status', 'N/A'):<60} |
|
|
708
|
+
| Progresso: {str(current_state.get('percent_complete', 0)) + '%':<58} |
|
|
709
|
+
| Fonte: {current_state.get('source_code', 'N/A'):<61} |
|
|
710
|
+
+{'='*70}+
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
---
|
|
714
|
+
|
|
715
|
+
## RESUMO DA CONVERSA
|
|
716
|
+
|
|
717
|
+
{self.session.conversation_summary or '_Nenhum resumo registrado nesta sessao._'}
|
|
718
|
+
|
|
719
|
+
---
|
|
720
|
+
|
|
721
|
+
## ACOES EXECUTADAS ({len(self.session.actions)})
|
|
722
|
+
|
|
723
|
+
### Por Tipo
|
|
724
|
+
"""
|
|
725
|
+
|
|
726
|
+
for atype, count in sorted(actions_by_type.items(), key=lambda x: -x[1]):
|
|
727
|
+
md += f"- **{atype}**: {count}\n"
|
|
728
|
+
|
|
729
|
+
md += "\n### Cronologia\n\n"
|
|
730
|
+
md += "| Timestamp | Tipo | Descricao |\n"
|
|
731
|
+
md += "|-----------|------|----------|\n"
|
|
732
|
+
|
|
733
|
+
for action in self.session.actions[-20:]: # Ultimas 20
|
|
734
|
+
if isinstance(action, Action):
|
|
735
|
+
ts = action.timestamp[-8:-3] if len(action.timestamp) > 8 else action.timestamp
|
|
736
|
+
md += f"| {ts} | {action.action_type} | {action.description[:50]} |\n"
|
|
737
|
+
else:
|
|
738
|
+
md += f"| - | - | {action.get('description', '-')[:50]} |\n"
|
|
739
|
+
|
|
740
|
+
if len(self.session.actions) > 20:
|
|
741
|
+
md += f"\n_... e mais {len(self.session.actions) - 20} acoes anteriores_\n"
|
|
742
|
+
|
|
743
|
+
md += f"""
|
|
744
|
+
|
|
745
|
+
---
|
|
746
|
+
|
|
747
|
+
## ARQUIVOS MODIFICADOS ({len(self.session.files_modified)})
|
|
748
|
+
|
|
749
|
+
### Por Operacao
|
|
750
|
+
"""
|
|
751
|
+
|
|
752
|
+
for op, count in sorted(files_by_op.items(), key=lambda x: -x[1]):
|
|
753
|
+
md += f"- **{op}**: {count}\n"
|
|
754
|
+
|
|
755
|
+
md += "\n### Lista\n\n"
|
|
756
|
+
|
|
757
|
+
for mod in self.session.files_modified[-15:]: # Ultimos 15
|
|
758
|
+
if isinstance(mod, FileModification):
|
|
759
|
+
md += f"- `{mod.operation}` {mod.filepath}\n"
|
|
760
|
+
else:
|
|
761
|
+
md += f"- `{mod.get('operation', 'mod')}` {mod.get('filepath', '')}\n"
|
|
762
|
+
|
|
763
|
+
if len(self.session.files_modified) > 15:
|
|
764
|
+
md += f"\n_... e mais {len(self.session.files_modified) - 15} arquivos anteriores_\n"
|
|
765
|
+
|
|
766
|
+
md += f"""
|
|
767
|
+
|
|
768
|
+
---
|
|
769
|
+
|
|
770
|
+
## DECISOES TOMADAS ({len(self.session.decisions)})
|
|
771
|
+
|
|
772
|
+
"""
|
|
773
|
+
|
|
774
|
+
for decision in self.session.decisions:
|
|
775
|
+
md += f"""### {decision.get('decision', 'Decisao')[:50]}
|
|
776
|
+
|
|
777
|
+
- **Raciocinio:** {decision.get('reasoning', '-')}
|
|
778
|
+
- **Alternativas:** {', '.join(decision.get('alternatives', [])) or 'Nenhuma'}
|
|
779
|
+
- **Quando:** {decision.get('timestamp', '-')}
|
|
780
|
+
|
|
781
|
+
"""
|
|
782
|
+
|
|
783
|
+
if not self.session.decisions:
|
|
784
|
+
md += "_Nenhuma decisao registrada nesta sessao._\n"
|
|
785
|
+
|
|
786
|
+
md += f"""
|
|
787
|
+
|
|
788
|
+
---
|
|
789
|
+
|
|
790
|
+
## PENDENCIAS ({len(self.session.pending_tasks)})
|
|
791
|
+
|
|
792
|
+
"""
|
|
793
|
+
|
|
794
|
+
for task in self.session.pending_tasks:
|
|
795
|
+
md += f"- [ ] {task}\n"
|
|
796
|
+
|
|
797
|
+
if not self.session.pending_tasks:
|
|
798
|
+
md += "_Nenhuma pendencia registrada._\n"
|
|
799
|
+
|
|
800
|
+
md += f"""
|
|
801
|
+
|
|
802
|
+
---
|
|
803
|
+
|
|
804
|
+
## PROXIMOS PASSOS PLANEJADOS ({len(self.session.next_steps)})
|
|
805
|
+
|
|
806
|
+
"""
|
|
807
|
+
|
|
808
|
+
for i, step in enumerate(self.session.next_steps, 1):
|
|
809
|
+
md += f"{i}. {step}\n"
|
|
810
|
+
|
|
811
|
+
if not self.session.next_steps:
|
|
812
|
+
md += "_Nenhum proximo passo definido._\n"
|
|
813
|
+
|
|
814
|
+
md += f"""
|
|
815
|
+
|
|
816
|
+
---
|
|
817
|
+
|
|
818
|
+
## NOTAS IMPORTANTES
|
|
819
|
+
|
|
820
|
+
"""
|
|
821
|
+
|
|
822
|
+
for note in self.session.notes:
|
|
823
|
+
md += f"- {note}\n"
|
|
824
|
+
|
|
825
|
+
if not self.session.notes:
|
|
826
|
+
md += "_Nenhuma nota registrada._\n"
|
|
827
|
+
|
|
828
|
+
md += f"""
|
|
829
|
+
|
|
830
|
+
---
|
|
831
|
+
|
|
832
|
+
## INFORMACOES TECNICAS
|
|
833
|
+
|
|
834
|
+
```json
|
|
835
|
+
{{
|
|
836
|
+
"session_id": "{self.session.session_id}",
|
|
837
|
+
"started_at": "{self.session.started_at}",
|
|
838
|
+
"last_save": "{self.session.last_save}",
|
|
839
|
+
"save_count": {self.session.save_count},
|
|
840
|
+
"trigger": "{trigger.value}",
|
|
841
|
+
"total_actions": {len(self.session.actions)},
|
|
842
|
+
"total_files_modified": {len(self.session.files_modified)},
|
|
843
|
+
"total_decisions": {len(self.session.decisions)},
|
|
844
|
+
"total_pending": {len(self.session.pending_tasks)},
|
|
845
|
+
"total_next_steps": {len(self.session.next_steps)}
|
|
846
|
+
}}
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
---
|
|
850
|
+
|
|
851
|
+
*Auto-saved by JARVIS Session Autosave V2*
|
|
852
|
+
*REGRA #11: Contexto perdido = Trabalho perdido*
|
|
853
|
+
*Timestamp: {now.isoformat()}*
|
|
854
|
+
"""
|
|
855
|
+
|
|
856
|
+
return md
|
|
857
|
+
|
|
858
|
+
def _on_exit(self):
|
|
859
|
+
"""Handler para encerramento."""
|
|
860
|
+
try:
|
|
861
|
+
self.save(SaveTrigger.SESSION_END)
|
|
862
|
+
except Exception:
|
|
863
|
+
pass
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
#=================================
|
|
867
|
+
# GLOBAL API
|
|
868
|
+
#=================================
|
|
869
|
+
|
|
870
|
+
_session_manager: Optional[SessionManager] = None
|
|
871
|
+
|
|
872
|
+
|
|
873
|
+
def get_session() -> SessionManager:
|
|
874
|
+
"""Obtem instancia do SessionManager."""
|
|
875
|
+
global _session_manager
|
|
876
|
+
if _session_manager is None:
|
|
877
|
+
_session_manager = SessionManager()
|
|
878
|
+
return _session_manager
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
def trigger_save(reason: str = "manual") -> str:
|
|
882
|
+
"""
|
|
883
|
+
Trigger para salvar sessao manualmente.
|
|
884
|
+
|
|
885
|
+
Args:
|
|
886
|
+
reason: Motivo do save
|
|
887
|
+
|
|
888
|
+
Returns:
|
|
889
|
+
Caminho do arquivo salvo
|
|
890
|
+
"""
|
|
891
|
+
session = get_session()
|
|
892
|
+
trigger = SaveTrigger.MANUAL
|
|
893
|
+
|
|
894
|
+
# Mapear reason para trigger
|
|
895
|
+
reason_map = {
|
|
896
|
+
'batch_complete': SaveTrigger.BATCH_COMPLETE,
|
|
897
|
+
'task_complete': SaveTrigger.TASK_COMPLETE,
|
|
898
|
+
'destructive': SaveTrigger.DESTRUCTIVE_OP,
|
|
899
|
+
'user_exit': SaveTrigger.USER_EXIT,
|
|
900
|
+
'pause': SaveTrigger.PAUSE_DETECTED,
|
|
901
|
+
'time': SaveTrigger.TIME_INTERVAL
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
for key, val in reason_map.items():
|
|
905
|
+
if key in reason.lower():
|
|
906
|
+
trigger = val
|
|
907
|
+
break
|
|
908
|
+
|
|
909
|
+
return session.save(trigger)
|
|
910
|
+
|
|
911
|
+
|
|
912
|
+
def log_action(action: str,
|
|
913
|
+
action_type: str = "other",
|
|
914
|
+
details: dict = None,
|
|
915
|
+
files: list = None) -> None:
|
|
916
|
+
"""
|
|
917
|
+
API para registrar acao.
|
|
918
|
+
|
|
919
|
+
Args:
|
|
920
|
+
action: Descricao da acao
|
|
921
|
+
action_type: Tipo (batch_process, file_create, etc)
|
|
922
|
+
details: Detalhes adicionais
|
|
923
|
+
files: Arquivos afetados
|
|
924
|
+
"""
|
|
925
|
+
session = get_session()
|
|
926
|
+
|
|
927
|
+
# Converter string para enum
|
|
928
|
+
try:
|
|
929
|
+
atype = ActionType(action_type)
|
|
930
|
+
except ValueError:
|
|
931
|
+
atype = ActionType.OTHER
|
|
932
|
+
|
|
933
|
+
session.log_action(atype, action, details, files)
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
def log_file(filepath: str, operation: str = "modified") -> None:
|
|
937
|
+
"""
|
|
938
|
+
API para registrar arquivo modificado.
|
|
939
|
+
|
|
940
|
+
Args:
|
|
941
|
+
filepath: Caminho do arquivo
|
|
942
|
+
operation: Tipo (created, modified, deleted)
|
|
943
|
+
"""
|
|
944
|
+
get_session().log_file_modified(filepath, operation)
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
def log_decision(decision: str, reasoning: str, alternatives: list = None) -> None:
|
|
948
|
+
"""
|
|
949
|
+
API para registrar decisao.
|
|
950
|
+
|
|
951
|
+
Args:
|
|
952
|
+
decision: A decisao tomada
|
|
953
|
+
reasoning: Raciocinio
|
|
954
|
+
alternatives: Alternativas consideradas
|
|
955
|
+
"""
|
|
956
|
+
get_session().log_decision(decision, reasoning, alternatives)
|
|
957
|
+
|
|
958
|
+
|
|
959
|
+
def add_pending(task: str) -> None:
|
|
960
|
+
"""Adiciona tarefa pendente."""
|
|
961
|
+
get_session().add_pending_task(task)
|
|
962
|
+
|
|
963
|
+
|
|
964
|
+
def complete_pending(task: str) -> None:
|
|
965
|
+
"""Marca tarefa como completa."""
|
|
966
|
+
get_session().complete_pending_task(task)
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
def add_next_step(step: str) -> None:
|
|
970
|
+
"""Adiciona proximo passo."""
|
|
971
|
+
get_session().add_next_step(step)
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
def add_note(note: str) -> None:
|
|
975
|
+
"""Adiciona nota importante."""
|
|
976
|
+
get_session().add_note(note)
|
|
977
|
+
|
|
978
|
+
|
|
979
|
+
def update_summary(summary: str) -> None:
|
|
980
|
+
"""Atualiza resumo da conversa."""
|
|
981
|
+
get_session().update_conversation_summary(summary)
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
def on_batch_complete(batch_id: str, details: dict = None) -> str:
|
|
985
|
+
"""Trigger para batch completado."""
|
|
986
|
+
return get_session().trigger_batch_complete(batch_id, details)
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
def on_task_complete(task_name: str, details: dict = None) -> str:
|
|
990
|
+
"""Trigger para tarefa completada."""
|
|
991
|
+
return get_session().trigger_task_complete(task_name, details)
|
|
992
|
+
|
|
993
|
+
|
|
994
|
+
def on_destructive_operation(operation: str) -> str:
|
|
995
|
+
"""Trigger antes de operacao destrutiva."""
|
|
996
|
+
return get_session().trigger_destructive_operation(operation)
|
|
997
|
+
|
|
998
|
+
|
|
999
|
+
def on_user_exit() -> str:
|
|
1000
|
+
"""Trigger quando usuario vai sair."""
|
|
1001
|
+
return get_session().trigger_user_exit()
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
def on_phase_change(old_phase: int, new_phase: int) -> str:
|
|
1005
|
+
"""Trigger para mudanca de fase."""
|
|
1006
|
+
return get_session().trigger_phase_change(old_phase, new_phase)
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
def get_session_status() -> dict:
|
|
1010
|
+
"""Retorna status atual da sessao."""
|
|
1011
|
+
session = get_session()
|
|
1012
|
+
return {
|
|
1013
|
+
'session_id': session.session.session_id,
|
|
1014
|
+
'started_at': session.session.started_at,
|
|
1015
|
+
'last_activity': session.session.last_activity,
|
|
1016
|
+
'last_save': session.session.last_save,
|
|
1017
|
+
'save_count': session.session.save_count,
|
|
1018
|
+
'actions_count': len(session.session.actions),
|
|
1019
|
+
'files_modified_count': len(session.session.files_modified),
|
|
1020
|
+
'pending_tasks': len(session.session.pending_tasks),
|
|
1021
|
+
'should_save': session.should_save()
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
|
|
1025
|
+
#=================================
|
|
1026
|
+
# CLI INTERFACE
|
|
1027
|
+
#=================================
|
|
1028
|
+
|
|
1029
|
+
def main():
|
|
1030
|
+
"""Interface de linha de comando."""
|
|
1031
|
+
import sys
|
|
1032
|
+
|
|
1033
|
+
if len(sys.argv) < 2:
|
|
1034
|
+
print("JARVIS Session Autosave V2")
|
|
1035
|
+
print("-" * 40)
|
|
1036
|
+
print("Uso: session_autosave_v2.py <comando>")
|
|
1037
|
+
print("")
|
|
1038
|
+
print("Comandos:")
|
|
1039
|
+
print(" save [reason] - Salvar sessao")
|
|
1040
|
+
print(" status - Status da sessao")
|
|
1041
|
+
print(" log <action> - Registrar acao")
|
|
1042
|
+
print(" file <path> <op> - Registrar arquivo")
|
|
1043
|
+
print(" pending <task> - Adicionar pendencia")
|
|
1044
|
+
print(" note <note> - Adicionar nota")
|
|
1045
|
+
print(" test - Executar teste")
|
|
1046
|
+
return
|
|
1047
|
+
|
|
1048
|
+
cmd = sys.argv[1].lower()
|
|
1049
|
+
|
|
1050
|
+
if cmd == 'save':
|
|
1051
|
+
reason = sys.argv[2] if len(sys.argv) > 2 else 'manual'
|
|
1052
|
+
result = trigger_save(reason)
|
|
1053
|
+
print(f"[JARVIS] Sessao salva: {result}")
|
|
1054
|
+
|
|
1055
|
+
elif cmd == 'status':
|
|
1056
|
+
status = get_session_status()
|
|
1057
|
+
print("[JARVIS] Status da Sessao:")
|
|
1058
|
+
print("-" * 40)
|
|
1059
|
+
for key, val in status.items():
|
|
1060
|
+
print(f" {key}: {val}")
|
|
1061
|
+
|
|
1062
|
+
elif cmd == 'log':
|
|
1063
|
+
action = ' '.join(sys.argv[2:]) if len(sys.argv) > 2 else 'Acao generica'
|
|
1064
|
+
log_action(action)
|
|
1065
|
+
print(f"[JARVIS] Acao registrada: {action}")
|
|
1066
|
+
|
|
1067
|
+
elif cmd == 'file':
|
|
1068
|
+
if len(sys.argv) < 3:
|
|
1069
|
+
print("Uso: file <path> [operation]")
|
|
1070
|
+
return
|
|
1071
|
+
filepath = sys.argv[2]
|
|
1072
|
+
operation = sys.argv[3] if len(sys.argv) > 3 else 'modified'
|
|
1073
|
+
log_file(filepath, operation)
|
|
1074
|
+
print(f"[JARVIS] Arquivo registrado: {operation} - {filepath}")
|
|
1075
|
+
|
|
1076
|
+
elif cmd == 'pending':
|
|
1077
|
+
task = ' '.join(sys.argv[2:]) if len(sys.argv) > 2 else 'Tarefa pendente'
|
|
1078
|
+
add_pending(task)
|
|
1079
|
+
print(f"[JARVIS] Pendencia adicionada: {task}")
|
|
1080
|
+
|
|
1081
|
+
elif cmd == 'note':
|
|
1082
|
+
note = ' '.join(sys.argv[2:]) if len(sys.argv) > 2 else 'Nota importante'
|
|
1083
|
+
add_note(note)
|
|
1084
|
+
print(f"[JARVIS] Nota adicionada: {note}")
|
|
1085
|
+
|
|
1086
|
+
elif cmd == 'test':
|
|
1087
|
+
print("[JARVIS] Executando teste do Session Autosave V2...")
|
|
1088
|
+
print("-" * 40)
|
|
1089
|
+
|
|
1090
|
+
# Teste completo
|
|
1091
|
+
session = get_session()
|
|
1092
|
+
|
|
1093
|
+
# Registrar acoes
|
|
1094
|
+
log_action("Teste de acao 1", "other", {"teste": True})
|
|
1095
|
+
log_action("Teste de acao 2", "batch_process", {"batch": "TEST-001"})
|
|
1096
|
+
|
|
1097
|
+
# Registrar arquivos
|
|
1098
|
+
log_file("/test/arquivo1.md", "created")
|
|
1099
|
+
log_file("/test/arquivo2.txt", "modified")
|
|
1100
|
+
|
|
1101
|
+
# Registrar decisao
|
|
1102
|
+
log_decision(
|
|
1103
|
+
"Usar formato Markdown para logs",
|
|
1104
|
+
"Melhor legibilidade e compatibilidade",
|
|
1105
|
+
["JSON puro", "YAML", "Plain text"]
|
|
1106
|
+
)
|
|
1107
|
+
|
|
1108
|
+
# Pendencias e notas
|
|
1109
|
+
add_pending("Finalizar documentacao")
|
|
1110
|
+
add_next_step("Testar em producao")
|
|
1111
|
+
add_note("Sistema funcionando corretamente")
|
|
1112
|
+
|
|
1113
|
+
# Atualizar resumo
|
|
1114
|
+
update_summary("Sessao de teste do autosave v2. Todas as funcionalidades testadas.")
|
|
1115
|
+
|
|
1116
|
+
# Salvar
|
|
1117
|
+
result = trigger_save("test")
|
|
1118
|
+
|
|
1119
|
+
print(f"[JARVIS] Teste concluido!")
|
|
1120
|
+
print(f"[JARVIS] Sessao salva em: {result}")
|
|
1121
|
+
print("-" * 40)
|
|
1122
|
+
|
|
1123
|
+
# Mostrar status
|
|
1124
|
+
status = get_session_status()
|
|
1125
|
+
print("[JARVIS] Status Final:")
|
|
1126
|
+
for key, val in status.items():
|
|
1127
|
+
print(f" {key}: {val}")
|
|
1128
|
+
|
|
1129
|
+
else:
|
|
1130
|
+
print(f"[JARVIS] Comando desconhecido: {cmd}")
|
|
1131
|
+
print("Use 'session_autosave_v2.py' sem argumentos para ver ajuda.")
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
if __name__ == "__main__":
|
|
1135
|
+
main()
|