bps-kit 1.0.1 → 1.0.2
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/package.json +1 -1
- package/templates/.agents/agents/backend-specialist.md +263 -0
- package/templates/.agents/agents/code-archaeologist.md +106 -0
- package/templates/.agents/agents/database-architect.md +226 -0
- package/templates/.agents/agents/debugger.md +225 -0
- package/templates/.agents/agents/devops-engineer.md +242 -0
- package/templates/.agents/agents/documentation-writer.md +104 -0
- package/templates/.agents/agents/explorer-agent.md +73 -0
- package/templates/.agents/agents/frontend-specialist.md +593 -0
- package/templates/.agents/agents/game-developer.md +162 -0
- package/templates/.agents/agents/mobile-developer.md +377 -0
- package/templates/.agents/agents/orchestrator.md +416 -0
- package/templates/.agents/agents/penetration-tester.md +188 -0
- package/templates/.agents/agents/performance-optimizer.md +187 -0
- package/templates/.agents/agents/product-manager.md +112 -0
- package/templates/.agents/agents/product-owner.md +95 -0
- package/templates/.agents/agents/project-planner.md +406 -0
- package/templates/.agents/agents/qa-automation-engineer.md +103 -0
- package/templates/.agents/agents/security-auditor.md +170 -0
- package/templates/.agents/agents/seo-specialist.md +111 -0
- package/templates/.agents/agents/test-engineer.md +158 -0
- package/templates/.agents/rules/GEMINI.md +219 -0
- package/templates/.agents/scripts/auto_preview.py +148 -0
- package/templates/.agents/scripts/checklist.py +217 -0
- package/templates/.agents/scripts/session_manager.py +120 -0
- package/templates/.agents/scripts/verify_all.py +327 -0
- package/templates/.agents/workflows/brainstorm.md +113 -0
- package/templates/.agents/workflows/create.md +59 -0
- package/templates/.agents/workflows/debug.md +103 -0
- package/templates/.agents/workflows/deploy.md +176 -0
- package/templates/.agents/workflows/enhance.md +63 -0
- package/templates/.agents/workflows/orchestrate.md +237 -0
- package/templates/.agents/workflows/plan.md +89 -0
- package/templates/.agents/workflows/preview.md +81 -0
- package/templates/.agents/workflows/setup-brain.md +39 -0
- package/templates/.agents/workflows/status.md +86 -0
- package/templates/.agents/workflows/test.md +144 -0
- package/templates/.agents/workflows/ui-ux-pro-max.md +296 -0
- package/templates/skills_normal/api-patterns/scripts/api_validator.py +211 -0
- package/templates/skills_normal/database-design/scripts/schema_validator.py +172 -0
- package/templates/skills_normal/frontend-design/scripts/accessibility_checker.py +183 -0
- package/templates/skills_normal/frontend-design/scripts/ux_audit.py +722 -0
- package/templates/skills_normal/git-pushing/scripts/smart_commit.sh +19 -0
- package/templates/skills_normal/lint-and-validate/scripts/lint_runner.py +184 -0
- package/templates/skills_normal/lint-and-validate/scripts/type_coverage.py +173 -0
- package/templates/skills_normal/performance-profiling/scripts/lighthouse_audit.py +76 -0
- package/templates/skills_normal/senior-fullstack/scripts/code_quality_analyzer.py +114 -0
- package/templates/skills_normal/senior-fullstack/scripts/fullstack_scaffolder.py +114 -0
- package/templates/skills_normal/senior-fullstack/scripts/project_scaffolder.py +114 -0
- package/templates/skills_normal/seo-fundamentals/scripts/seo_checker.py +219 -0
- package/templates/skills_normal/testing-patterns/scripts/test_runner.py +219 -0
- package/templates/skills_normal/vulnerability-scanner/scripts/security_scan.py +458 -0
- package/templates/vault/007/scripts/config.py +472 -0
- package/templates/vault/007/scripts/full_audit.py +1306 -0
- package/templates/vault/007/scripts/quick_scan.py +481 -0
- package/templates/vault/007/scripts/requirements.txt +26 -0
- package/templates/vault/007/scripts/scanners/__init__.py +0 -0
- package/templates/vault/007/scripts/scanners/dependency_scanner.py +1305 -0
- package/templates/vault/007/scripts/scanners/injection_scanner.py +1104 -0
- package/templates/vault/007/scripts/scanners/secrets_scanner.py +1008 -0
- package/templates/vault/007/scripts/score_calculator.py +693 -0
- package/templates/vault/agent-orchestrator/scripts/match_skills.py +329 -0
- package/templates/vault/agent-orchestrator/scripts/orchestrate.py +304 -0
- package/templates/vault/agent-orchestrator/scripts/requirements.txt +1 -0
- package/templates/vault/agent-orchestrator/scripts/scan_registry.py +508 -0
- package/templates/vault/ai-studio-image/scripts/config.py +613 -0
- package/templates/vault/ai-studio-image/scripts/generate.py +630 -0
- package/templates/vault/ai-studio-image/scripts/prompt_engine.py +424 -0
- package/templates/vault/ai-studio-image/scripts/requirements.txt +4 -0
- package/templates/vault/ai-studio-image/scripts/templates.py +349 -0
- package/templates/vault/android_ui_verification/scripts/verify_ui.sh +32 -0
- package/templates/vault/apify-audience-analysis/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-brand-reputation-monitoring/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-competitor-intelligence/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-content-analytics/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-ecommerce/reference/scripts/package.json +3 -0
- package/templates/vault/apify-ecommerce/reference/scripts/run_actor.js +369 -0
- package/templates/vault/apify-influencer-discovery/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-lead-generation/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-market-research/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-trend-analysis/reference/scripts/run_actor.js +363 -0
- package/templates/vault/apify-ultimate-scraper/reference/scripts/run_actor.js +363 -0
- package/templates/vault/audio-transcriber/scripts/install-requirements.sh +190 -0
- package/templates/vault/audio-transcriber/scripts/transcribe.py +486 -0
- package/templates/vault/claude-monitor/scripts/api_bench.py +240 -0
- package/templates/vault/claude-monitor/scripts/config.py +69 -0
- package/templates/vault/claude-monitor/scripts/health_check.py +362 -0
- package/templates/vault/claude-monitor/scripts/monitor.py +296 -0
- package/templates/vault/content-creator/scripts/brand_voice_analyzer.py +185 -0
- package/templates/vault/content-creator/scripts/seo_optimizer.py +419 -0
- package/templates/vault/context-agent/scripts/active_context.py +227 -0
- package/templates/vault/context-agent/scripts/compressor.py +149 -0
- package/templates/vault/context-agent/scripts/config.py +69 -0
- package/templates/vault/context-agent/scripts/context_loader.py +155 -0
- package/templates/vault/context-agent/scripts/context_manager.py +302 -0
- package/templates/vault/context-agent/scripts/models.py +103 -0
- package/templates/vault/context-agent/scripts/project_registry.py +132 -0
- package/templates/vault/context-agent/scripts/requirements.txt +6 -0
- package/templates/vault/context-agent/scripts/search.py +115 -0
- package/templates/vault/context-agent/scripts/session_parser.py +206 -0
- package/templates/vault/context-agent/scripts/session_summary.py +319 -0
- package/templates/vault/context-guardian/scripts/context_snapshot.py +229 -0
- package/templates/vault/docx/ooxml/scripts/pack.py +159 -0
- package/templates/vault/docx/ooxml/scripts/unpack.py +29 -0
- package/templates/vault/docx/ooxml/scripts/validate.py +69 -0
- package/templates/vault/docx/ooxml/scripts/validation/__init__.py +15 -0
- package/templates/vault/docx/ooxml/scripts/validation/base.py +951 -0
- package/templates/vault/docx/ooxml/scripts/validation/docx.py +274 -0
- package/templates/vault/docx/ooxml/scripts/validation/pptx.py +315 -0
- package/templates/vault/docx/ooxml/scripts/validation/redlining.py +279 -0
- package/templates/vault/docx/scripts/__init__.py +1 -0
- package/templates/vault/docx/scripts/document.py +1276 -0
- package/templates/vault/docx/scripts/templates/comments.xml +3 -0
- package/templates/vault/docx/scripts/templates/commentsExtended.xml +3 -0
- package/templates/vault/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/templates/vault/docx/scripts/templates/commentsIds.xml +3 -0
- package/templates/vault/docx/scripts/templates/people.xml +3 -0
- package/templates/vault/docx/scripts/utilities.py +374 -0
- package/templates/vault/docx-official/ooxml/scripts/pack.py +159 -0
- package/templates/vault/docx-official/ooxml/scripts/unpack.py +29 -0
- package/templates/vault/docx-official/ooxml/scripts/validate.py +69 -0
- package/templates/vault/docx-official/ooxml/scripts/validation/__init__.py +15 -0
- package/templates/vault/docx-official/ooxml/scripts/validation/base.py +951 -0
- package/templates/vault/docx-official/ooxml/scripts/validation/docx.py +274 -0
- package/templates/vault/docx-official/ooxml/scripts/validation/pptx.py +315 -0
- package/templates/vault/docx-official/ooxml/scripts/validation/redlining.py +279 -0
- package/templates/vault/docx-official/scripts/__init__.py +1 -0
- package/templates/vault/docx-official/scripts/document.py +1276 -0
- package/templates/vault/docx-official/scripts/templates/comments.xml +3 -0
- package/templates/vault/docx-official/scripts/templates/commentsExtended.xml +3 -0
- package/templates/vault/docx-official/scripts/templates/commentsExtensible.xml +3 -0
- package/templates/vault/docx-official/scripts/templates/commentsIds.xml +3 -0
- package/templates/vault/docx-official/scripts/templates/people.xml +3 -0
- package/templates/vault/docx-official/scripts/utilities.py +374 -0
- package/templates/vault/geo-fundamentals/scripts/geo_checker.py +289 -0
- package/templates/vault/helm-chart-scaffolding/scripts/validate-chart.sh +244 -0
- package/templates/vault/i18n-localization/scripts/i18n_checker.py +241 -0
- package/templates/vault/instagram/scripts/account_setup.py +233 -0
- package/templates/vault/instagram/scripts/analyze.py +221 -0
- package/templates/vault/instagram/scripts/api_client.py +444 -0
- package/templates/vault/instagram/scripts/auth.py +411 -0
- package/templates/vault/instagram/scripts/comments.py +160 -0
- package/templates/vault/instagram/scripts/config.py +111 -0
- package/templates/vault/instagram/scripts/db.py +467 -0
- package/templates/vault/instagram/scripts/export.py +138 -0
- package/templates/vault/instagram/scripts/governance.py +233 -0
- package/templates/vault/instagram/scripts/hashtags.py +114 -0
- package/templates/vault/instagram/scripts/insights.py +170 -0
- package/templates/vault/instagram/scripts/media.py +65 -0
- package/templates/vault/instagram/scripts/messages.py +103 -0
- package/templates/vault/instagram/scripts/profile.py +58 -0
- package/templates/vault/instagram/scripts/publish.py +449 -0
- package/templates/vault/instagram/scripts/requirements.txt +5 -0
- package/templates/vault/instagram/scripts/run_all.py +189 -0
- package/templates/vault/instagram/scripts/schedule.py +189 -0
- package/templates/vault/instagram/scripts/serve_api.py +234 -0
- package/templates/vault/instagram/scripts/templates.py +155 -0
- package/templates/vault/junta-leiloeiros/scripts/db.py +216 -0
- package/templates/vault/junta-leiloeiros/scripts/export.py +137 -0
- package/templates/vault/junta-leiloeiros/scripts/requirements.txt +15 -0
- package/templates/vault/junta-leiloeiros/scripts/run_all.py +190 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/__init__.py +4 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/base_scraper.py +209 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/generic_scraper.py +110 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucap.py +110 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/juceac.py +72 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/juceal.py +72 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/juceb.py +68 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucec.py +63 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucema.py +211 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucemg.py +218 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucep.py +70 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucepa.py +74 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucepar.py +80 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucepe.py +78 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucepi.py +69 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucer.py +256 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucerja.py +170 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucern.py +71 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucesc.py +89 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucesp.py +233 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucetins.py +134 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucis_df.py +63 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/jucisrs.py +299 -0
- package/templates/vault/junta-leiloeiros/scripts/scraper/states.py +99 -0
- package/templates/vault/junta-leiloeiros/scripts/serve_api.py +164 -0
- package/templates/vault/junta-leiloeiros/scripts/web_scraper_fallback.py +233 -0
- package/templates/vault/last30days/scripts/last30days.py +521 -0
- package/templates/vault/last30days/scripts/lib/__init__.py +1 -0
- package/templates/vault/last30days/scripts/lib/cache.py +152 -0
- package/templates/vault/last30days/scripts/lib/dates.py +124 -0
- package/templates/vault/last30days/scripts/lib/dedupe.py +120 -0
- package/templates/vault/last30days/scripts/lib/env.py +149 -0
- package/templates/vault/last30days/scripts/lib/http.py +152 -0
- package/templates/vault/last30days/scripts/lib/models.py +175 -0
- package/templates/vault/last30days/scripts/lib/normalize.py +160 -0
- package/templates/vault/last30days/scripts/lib/openai_reddit.py +230 -0
- package/templates/vault/last30days/scripts/lib/reddit_enrich.py +232 -0
- package/templates/vault/last30days/scripts/lib/render.py +383 -0
- package/templates/vault/last30days/scripts/lib/schema.py +336 -0
- package/templates/vault/last30days/scripts/lib/score.py +311 -0
- package/templates/vault/last30days/scripts/lib/ui.py +324 -0
- package/templates/vault/last30days/scripts/lib/websearch.py +401 -0
- package/templates/vault/last30days/scripts/lib/xai_x.py +217 -0
- package/templates/vault/leiloeiro-avaliacao/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-avaliacao/scripts/requirements.txt +1 -0
- package/templates/vault/leiloeiro-edital/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-edital/scripts/requirements.txt +1 -0
- package/templates/vault/leiloeiro-ia/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-ia/scripts/requirements.txt +1 -0
- package/templates/vault/leiloeiro-juridico/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-juridico/scripts/requirements.txt +1 -0
- package/templates/vault/leiloeiro-mercado/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-mercado/scripts/requirements.txt +1 -0
- package/templates/vault/leiloeiro-risco/scripts/governance.py +106 -0
- package/templates/vault/leiloeiro-risco/scripts/requirements.txt +1 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/database.ts +24 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/db.ts +35 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/index.ts +2 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/migrations.ts +31 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/schema.sql +8 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/index.ts +44 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/routes/todos.ts +155 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/types/index.ts +35 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/App.css +384 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/App.tsx +81 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/api/todos.ts +57 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/ConfirmDialog.tsx +26 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/EmptyState.tsx +8 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoForm.tsx +43 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoItem.tsx +36 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoList.tsx +27 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/hooks/useTodos.ts +81 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/index.css +48 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/main.tsx +10 -0
- package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/vite-env.d.ts +1 -0
- package/templates/vault/loki-mode/scripts/export-to-vibe-kanban.sh +178 -0
- package/templates/vault/loki-mode/scripts/loki-wrapper.sh +281 -0
- package/templates/vault/loki-mode/scripts/take-screenshots.js +55 -0
- package/templates/vault/matematico-tao/scripts/complexity_analyzer.py +544 -0
- package/templates/vault/matematico-tao/scripts/dependency_graph.py +538 -0
- package/templates/vault/mcp-builder/scripts/connections.py +151 -0
- package/templates/vault/mcp-builder/scripts/evaluation.py +373 -0
- package/templates/vault/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/templates/vault/mcp-builder/scripts/requirements.txt +2 -0
- package/templates/vault/mobile-design/scripts/mobile_audit.py +670 -0
- package/templates/vault/notebooklm/scripts/__init__.py +81 -0
- package/templates/vault/notebooklm/scripts/ask_question.py +256 -0
- package/templates/vault/notebooklm/scripts/auth_manager.py +358 -0
- package/templates/vault/notebooklm/scripts/browser_session.py +255 -0
- package/templates/vault/notebooklm/scripts/browser_utils.py +107 -0
- package/templates/vault/notebooklm/scripts/cleanup_manager.py +302 -0
- package/templates/vault/notebooklm/scripts/config.py +44 -0
- package/templates/vault/notebooklm/scripts/notebook_manager.py +410 -0
- package/templates/vault/notebooklm/scripts/run.py +102 -0
- package/templates/vault/notebooklm/scripts/setup_environment.py +204 -0
- package/templates/vault/pdf/scripts/check_bounding_boxes.py +70 -0
- package/templates/vault/pdf/scripts/check_bounding_boxes_test.py +226 -0
- package/templates/vault/pdf/scripts/check_fillable_fields.py +12 -0
- package/templates/vault/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/templates/vault/pdf/scripts/create_validation_image.py +41 -0
- package/templates/vault/pdf/scripts/extract_form_field_info.py +152 -0
- package/templates/vault/pdf/scripts/fill_fillable_fields.py +114 -0
- package/templates/vault/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/templates/vault/pdf-official/scripts/check_bounding_boxes.py +70 -0
- package/templates/vault/pdf-official/scripts/check_bounding_boxes_test.py +226 -0
- package/templates/vault/pdf-official/scripts/check_fillable_fields.py +12 -0
- package/templates/vault/pdf-official/scripts/convert_pdf_to_images.py +35 -0
- package/templates/vault/pdf-official/scripts/create_validation_image.py +41 -0
- package/templates/vault/pdf-official/scripts/extract_form_field_info.py +152 -0
- package/templates/vault/pdf-official/scripts/fill_fillable_fields.py +114 -0
- package/templates/vault/pdf-official/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/templates/vault/planning-with-files/scripts/check-complete.sh +44 -0
- package/templates/vault/planning-with-files/scripts/init-session.sh +120 -0
- package/templates/vault/pptx/ooxml/scripts/pack.py +159 -0
- package/templates/vault/pptx/ooxml/scripts/unpack.py +29 -0
- package/templates/vault/pptx/ooxml/scripts/validate.py +69 -0
- package/templates/vault/pptx/ooxml/scripts/validation/__init__.py +15 -0
- package/templates/vault/pptx/ooxml/scripts/validation/base.py +951 -0
- package/templates/vault/pptx/ooxml/scripts/validation/docx.py +274 -0
- package/templates/vault/pptx/ooxml/scripts/validation/pptx.py +315 -0
- package/templates/vault/pptx/ooxml/scripts/validation/redlining.py +279 -0
- package/templates/vault/pptx/scripts/html2pptx.js +979 -0
- package/templates/vault/pptx/scripts/inventory.py +1020 -0
- package/templates/vault/pptx/scripts/rearrange.py +231 -0
- package/templates/vault/pptx/scripts/replace.py +385 -0
- package/templates/vault/pptx/scripts/thumbnail.py +450 -0
- package/templates/vault/pptx-official/ooxml/scripts/pack.py +159 -0
- package/templates/vault/pptx-official/ooxml/scripts/unpack.py +29 -0
- package/templates/vault/pptx-official/ooxml/scripts/validate.py +69 -0
- package/templates/vault/pptx-official/ooxml/scripts/validation/__init__.py +15 -0
- package/templates/vault/pptx-official/ooxml/scripts/validation/base.py +951 -0
- package/templates/vault/pptx-official/ooxml/scripts/validation/docx.py +274 -0
- package/templates/vault/pptx-official/ooxml/scripts/validation/pptx.py +315 -0
- package/templates/vault/pptx-official/ooxml/scripts/validation/redlining.py +279 -0
- package/templates/vault/pptx-official/scripts/html2pptx.js +979 -0
- package/templates/vault/pptx-official/scripts/inventory.py +1020 -0
- package/templates/vault/pptx-official/scripts/rearrange.py +231 -0
- package/templates/vault/pptx-official/scripts/replace.py +385 -0
- package/templates/vault/pptx-official/scripts/thumbnail.py +450 -0
- package/templates/vault/product-manager-toolkit/scripts/customer_interview_analyzer.py +441 -0
- package/templates/vault/product-manager-toolkit/scripts/rice_prioritizer.py +296 -0
- package/templates/vault/prompt-engineering-patterns/scripts/optimize-prompt.py +279 -0
- package/templates/vault/scripts/.skill_cache.json +7538 -0
- package/templates/vault/scripts/skill_search.py +228 -0
- package/templates/vault/senior-architect/scripts/architecture_diagram_generator.py +114 -0
- package/templates/vault/senior-architect/scripts/dependency_analyzer.py +114 -0
- package/templates/vault/senior-architect/scripts/project_architect.py +114 -0
- package/templates/vault/shopify-development/scripts/requirements.txt +19 -0
- package/templates/vault/shopify-development/scripts/shopify_graphql.py +428 -0
- package/templates/vault/shopify-development/scripts/shopify_init.py +441 -0
- package/templates/vault/shopify-development/scripts/tests/test_shopify_init.py +379 -0
- package/templates/vault/skill-creator/scripts/init_skill.py +303 -0
- package/templates/vault/skill-creator/scripts/package_skill.py +110 -0
- package/templates/vault/skill-creator/scripts/quick_validate.py +95 -0
- package/templates/vault/skill-installer/scripts/detect_skills.py +318 -0
- package/templates/vault/skill-installer/scripts/install_skill.py +1708 -0
- package/templates/vault/skill-installer/scripts/package_skill.py +417 -0
- package/templates/vault/skill-installer/scripts/requirements.txt +1 -0
- package/templates/vault/skill-installer/scripts/validate_skill.py +430 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/__init__.py +13 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/code_quality.py +247 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/cross_skill.py +134 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/dependencies.py +121 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/documentation.py +189 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/governance_audit.py +153 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/performance.py +164 -0
- package/templates/vault/skill-sentinel/scripts/analyzers/security.py +189 -0
- package/templates/vault/skill-sentinel/scripts/config.py +158 -0
- package/templates/vault/skill-sentinel/scripts/cost_optimizer.py +146 -0
- package/templates/vault/skill-sentinel/scripts/db.py +354 -0
- package/templates/vault/skill-sentinel/scripts/governance.py +58 -0
- package/templates/vault/skill-sentinel/scripts/recommender.py +228 -0
- package/templates/vault/skill-sentinel/scripts/report_generator.py +224 -0
- package/templates/vault/skill-sentinel/scripts/requirements.txt +1 -0
- package/templates/vault/skill-sentinel/scripts/run_audit.py +290 -0
- package/templates/vault/skill-sentinel/scripts/scanner.py +271 -0
- package/templates/vault/stability-ai/scripts/config.py +266 -0
- package/templates/vault/stability-ai/scripts/generate.py +687 -0
- package/templates/vault/stability-ai/scripts/requirements.txt +4 -0
- package/templates/vault/stability-ai/scripts/styles.py +174 -0
- package/templates/vault/telegram/assets/boilerplate/nodejs/src/bot-client.ts +86 -0
- package/templates/vault/telegram/assets/boilerplate/nodejs/src/handlers.ts +79 -0
- package/templates/vault/telegram/assets/boilerplate/nodejs/src/index.ts +32 -0
- package/templates/vault/telegram/scripts/send_message.py +143 -0
- package/templates/vault/telegram/scripts/setup_project.py +103 -0
- package/templates/vault/telegram/scripts/test_bot.py +144 -0
- package/templates/vault/typescript-expert/scripts/ts_diagnostic.py +203 -0
- package/templates/vault/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
- package/templates/vault/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
- package/templates/vault/ui-ux-pro-max/scripts/core.py +257 -0
- package/templates/vault/ui-ux-pro-max/scripts/design_system.py +487 -0
- package/templates/vault/ui-ux-pro-max/scripts/search.py +76 -0
- package/templates/vault/videodb/scripts/ws_listener.py +204 -0
- package/templates/vault/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
- package/templates/vault/web-artifacts-builder/scripts/init-artifact.sh +322 -0
- package/templates/vault/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- package/templates/vault/webapp-testing/scripts/with_server.py +106 -0
- package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/index.ts +125 -0
- package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/template-manager.ts +67 -0
- package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/types.ts +216 -0
- package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/webhook-handler.ts +173 -0
- package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/whatsapp-client.ts +193 -0
- package/templates/vault/whatsapp-cloud-api/scripts/send_test_message.py +137 -0
- package/templates/vault/whatsapp-cloud-api/scripts/setup_project.py +118 -0
- package/templates/vault/whatsapp-cloud-api/scripts/validate_config.py +190 -0
- package/templates/vault/youtube-summarizer/scripts/extract-transcript.py +65 -0
- package/templates/vault/youtube-summarizer/scripts/install-dependencies.sh +28 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Gerador de resumos estruturados de sessão.
|
|
3
|
+
Analisa mensagens e gera session-NNN.md.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import re
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from config import (
|
|
11
|
+
SESSIONS_DIR,
|
|
12
|
+
DECISION_MARKERS,
|
|
13
|
+
PENDING_MARKERS,
|
|
14
|
+
)
|
|
15
|
+
from models import SessionSummary, PendingTask, SessionEntry
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_next_session_number() -> int:
|
|
19
|
+
"""Retorna o próximo número de sessão disponível."""
|
|
20
|
+
SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
|
|
21
|
+
existing = list(SESSIONS_DIR.glob("session-*.md"))
|
|
22
|
+
if not existing:
|
|
23
|
+
return 1
|
|
24
|
+
numbers = []
|
|
25
|
+
for f in existing:
|
|
26
|
+
try:
|
|
27
|
+
num = int(f.stem.split("-")[1])
|
|
28
|
+
numbers.append(num)
|
|
29
|
+
except (IndexError, ValueError):
|
|
30
|
+
continue
|
|
31
|
+
return max(numbers) + 1 if numbers else 1
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def generate_summary(
|
|
35
|
+
entries: list[SessionEntry],
|
|
36
|
+
session_number: int,
|
|
37
|
+
metadata: dict,
|
|
38
|
+
) -> SessionSummary:
|
|
39
|
+
"""Gera um resumo estruturado a partir das entradas da sessão."""
|
|
40
|
+
user_messages = [e.content for e in entries if e.role == "user" and e.content.strip()]
|
|
41
|
+
assistant_messages = [e.content for e in entries if e.role == "assistant" and e.content.strip()]
|
|
42
|
+
all_messages = user_messages + assistant_messages
|
|
43
|
+
all_tool_calls = []
|
|
44
|
+
all_files_modified = []
|
|
45
|
+
|
|
46
|
+
for e in entries:
|
|
47
|
+
all_tool_calls.extend(e.tool_calls)
|
|
48
|
+
all_files_modified.extend(e.files_modified)
|
|
49
|
+
|
|
50
|
+
# Deduplicate files
|
|
51
|
+
seen_files = set()
|
|
52
|
+
unique_files = []
|
|
53
|
+
for f in all_files_modified:
|
|
54
|
+
if f["path"] not in seen_files:
|
|
55
|
+
seen_files.add(f["path"])
|
|
56
|
+
unique_files.append(f)
|
|
57
|
+
|
|
58
|
+
# Extrair data
|
|
59
|
+
date_str = ""
|
|
60
|
+
start_time = metadata.get("start_time", "")
|
|
61
|
+
if start_time:
|
|
62
|
+
try:
|
|
63
|
+
dt = datetime.fromisoformat(start_time.replace("Z", "+00:00"))
|
|
64
|
+
date_str = dt.strftime("%Y-%m-%d")
|
|
65
|
+
except ValueError:
|
|
66
|
+
date_str = datetime.now().strftime("%Y-%m-%d")
|
|
67
|
+
else:
|
|
68
|
+
date_str = datetime.now().strftime("%Y-%m-%d")
|
|
69
|
+
|
|
70
|
+
summary = SessionSummary(
|
|
71
|
+
session_number=session_number,
|
|
72
|
+
session_id=metadata.get("session_id", ""),
|
|
73
|
+
slug=metadata.get("slug", ""),
|
|
74
|
+
date=date_str,
|
|
75
|
+
start_time=start_time,
|
|
76
|
+
end_time=metadata.get("end_time", ""),
|
|
77
|
+
duration_minutes=metadata.get("duration_minutes", 0),
|
|
78
|
+
model=metadata.get("model", ""),
|
|
79
|
+
total_input_tokens=metadata.get("total_input_tokens", 0),
|
|
80
|
+
total_output_tokens=metadata.get("total_output_tokens", 0),
|
|
81
|
+
total_cache_tokens=metadata.get("total_cache_tokens", 0),
|
|
82
|
+
message_count=metadata.get("message_count", 0),
|
|
83
|
+
tool_call_count=metadata.get("tool_call_count", 0),
|
|
84
|
+
files_modified=unique_files,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Extrair tópicos das mensagens do usuário
|
|
88
|
+
summary.topics = _extract_topics(user_messages)
|
|
89
|
+
|
|
90
|
+
# Extrair decisões
|
|
91
|
+
summary.decisions = _extract_decisions(all_messages)
|
|
92
|
+
|
|
93
|
+
# Extrair tarefas
|
|
94
|
+
summary.tasks_completed = _extract_completed_tasks(all_messages)
|
|
95
|
+
summary.tasks_pending = _extract_pending_tasks(all_messages, session_number, date_str)
|
|
96
|
+
|
|
97
|
+
# Extrair erros
|
|
98
|
+
summary.errors_resolved = _extract_errors(assistant_messages)
|
|
99
|
+
|
|
100
|
+
# Extrair findings
|
|
101
|
+
summary.key_findings = _extract_findings(assistant_messages)
|
|
102
|
+
|
|
103
|
+
return summary
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _extract_topics(user_messages: list[str]) -> list[str]:
|
|
107
|
+
"""Identifica tópicos principais das mensagens do usuário."""
|
|
108
|
+
topics = []
|
|
109
|
+
for msg in user_messages:
|
|
110
|
+
# Limpar mensagens muito longas
|
|
111
|
+
msg_clean = msg[:500] if len(msg) > 500 else msg
|
|
112
|
+
# Pegar a primeira frase significativa como tópico
|
|
113
|
+
sentences = re.split(r'[.!?\n]', msg_clean)
|
|
114
|
+
for s in sentences:
|
|
115
|
+
s = s.strip()
|
|
116
|
+
if len(s) > 10 and len(s) < 200:
|
|
117
|
+
topics.append(s)
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
# Deduplicate e limitar
|
|
121
|
+
seen = set()
|
|
122
|
+
unique = []
|
|
123
|
+
for t in topics:
|
|
124
|
+
t_lower = t.lower()
|
|
125
|
+
if t_lower not in seen:
|
|
126
|
+
seen.add(t_lower)
|
|
127
|
+
unique.append(t)
|
|
128
|
+
|
|
129
|
+
return unique[:10]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _extract_decisions(messages: list[str]) -> list[str]:
|
|
133
|
+
"""Encontra decisões nas mensagens."""
|
|
134
|
+
decisions = []
|
|
135
|
+
for msg in messages:
|
|
136
|
+
for line in msg.split("\n"):
|
|
137
|
+
line_lower = line.lower().strip()
|
|
138
|
+
for marker in DECISION_MARKERS:
|
|
139
|
+
if marker in line_lower:
|
|
140
|
+
clean = line.strip()
|
|
141
|
+
if 15 < len(clean) < 300:
|
|
142
|
+
decisions.append(clean)
|
|
143
|
+
break
|
|
144
|
+
return list(dict.fromkeys(decisions))[:10] # Deduplicate, max 10
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _extract_completed_tasks(messages: list[str]) -> list[str]:
|
|
148
|
+
"""Encontra tarefas concluídas."""
|
|
149
|
+
completed = []
|
|
150
|
+
patterns = [
|
|
151
|
+
r"- \[x\]\s+(.+)",
|
|
152
|
+
r"✅\s+(.+)",
|
|
153
|
+
r"(?:concluí|completei|terminei|finalizei|done|completed|finished)\s+(.+)",
|
|
154
|
+
]
|
|
155
|
+
for msg in messages:
|
|
156
|
+
for line in msg.split("\n"):
|
|
157
|
+
for pattern in patterns:
|
|
158
|
+
m = re.search(pattern, line, re.IGNORECASE)
|
|
159
|
+
if m:
|
|
160
|
+
task = m.group(1).strip()
|
|
161
|
+
if len(task) > 5:
|
|
162
|
+
completed.append(task)
|
|
163
|
+
return list(dict.fromkeys(completed))[:15]
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _extract_pending_tasks(
|
|
167
|
+
messages: list[str],
|
|
168
|
+
session_number: int,
|
|
169
|
+
date: str,
|
|
170
|
+
) -> list[PendingTask]:
|
|
171
|
+
"""Encontra tarefas pendentes. Foca em checkboxes não marcados nas mensagens do user."""
|
|
172
|
+
tasks = []
|
|
173
|
+
for msg in messages:
|
|
174
|
+
# Ignorar mensagens muito longas (provavelmente tool results, não conversação)
|
|
175
|
+
if len(msg) > 5000:
|
|
176
|
+
continue
|
|
177
|
+
|
|
178
|
+
for line in msg.split("\n"):
|
|
179
|
+
stripped = line.strip()
|
|
180
|
+
|
|
181
|
+
# Checkbox não marcado — sinal claro de tarefa
|
|
182
|
+
m = re.match(r"- \[ \]\s+(.+)", stripped)
|
|
183
|
+
if m:
|
|
184
|
+
desc = m.group(1).strip()
|
|
185
|
+
# Filtrar descrições que parecem código/documentação
|
|
186
|
+
if 10 < len(desc) < 200 and not desc.startswith("`") and not desc.startswith("-"):
|
|
187
|
+
tasks.append(PendingTask(
|
|
188
|
+
description=desc,
|
|
189
|
+
source_session=session_number,
|
|
190
|
+
created_date=date,
|
|
191
|
+
))
|
|
192
|
+
|
|
193
|
+
# Deduplicate
|
|
194
|
+
seen = set()
|
|
195
|
+
unique = []
|
|
196
|
+
for t in tasks:
|
|
197
|
+
if t.description not in seen:
|
|
198
|
+
seen.add(t.description)
|
|
199
|
+
unique.append(t)
|
|
200
|
+
|
|
201
|
+
return unique[:10]
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _extract_errors(assistant_messages: list[str]) -> list[dict]:
|
|
205
|
+
"""Encontra erros e suas soluções."""
|
|
206
|
+
errors = []
|
|
207
|
+
error_patterns = [
|
|
208
|
+
r"(?:error|erro|falha|failed|exception)[\s:]+(.+)",
|
|
209
|
+
]
|
|
210
|
+
for msg in assistant_messages:
|
|
211
|
+
for pattern in error_patterns:
|
|
212
|
+
matches = re.findall(pattern, msg, re.IGNORECASE)
|
|
213
|
+
for match in matches:
|
|
214
|
+
if len(match) > 10:
|
|
215
|
+
errors.append({"error": match[:200], "solution": ""})
|
|
216
|
+
return errors[:5]
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _extract_findings(assistant_messages: list[str]) -> list[str]:
|
|
220
|
+
"""Extrai descobertas/findings importantes."""
|
|
221
|
+
findings = []
|
|
222
|
+
markers = [
|
|
223
|
+
"descobri que", "encontrei", "notei que", "importante:",
|
|
224
|
+
"found that", "noticed that", "important:", "key finding",
|
|
225
|
+
]
|
|
226
|
+
for msg in assistant_messages:
|
|
227
|
+
for line in msg.split("\n"):
|
|
228
|
+
line_lower = line.lower().strip()
|
|
229
|
+
for marker in markers:
|
|
230
|
+
if marker in line_lower and len(line.strip()) > 20:
|
|
231
|
+
findings.append(line.strip()[:200])
|
|
232
|
+
break
|
|
233
|
+
return list(dict.fromkeys(findings))[:5]
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def save_session_summary(summary: SessionSummary):
|
|
237
|
+
"""Salva resumo como arquivo markdown."""
|
|
238
|
+
SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
|
|
239
|
+
path = SESSIONS_DIR / f"session-{summary.session_number:03d}.md"
|
|
240
|
+
|
|
241
|
+
lines = [
|
|
242
|
+
f"# Sessão {summary.session_number:03d} — {summary.date}",
|
|
243
|
+
f"**Slug:** {summary.slug} | **Duração:** ~{summary.duration_minutes}min | **Modelo:** {summary.model}",
|
|
244
|
+
"",
|
|
245
|
+
]
|
|
246
|
+
|
|
247
|
+
if summary.topics:
|
|
248
|
+
lines.append("## Tópicos")
|
|
249
|
+
for t in summary.topics:
|
|
250
|
+
lines.append(f"- {t}")
|
|
251
|
+
lines.append("")
|
|
252
|
+
|
|
253
|
+
if summary.decisions:
|
|
254
|
+
lines.append("## Decisões")
|
|
255
|
+
for d in summary.decisions:
|
|
256
|
+
lines.append(f"- {d}")
|
|
257
|
+
lines.append("")
|
|
258
|
+
|
|
259
|
+
if summary.tasks_completed:
|
|
260
|
+
lines.append("## Tarefas Concluídas")
|
|
261
|
+
for t in summary.tasks_completed:
|
|
262
|
+
lines.append(f"- [x] {t}")
|
|
263
|
+
lines.append("")
|
|
264
|
+
|
|
265
|
+
if summary.tasks_pending:
|
|
266
|
+
lines.append("## Tarefas Pendentes")
|
|
267
|
+
for t in summary.tasks_pending:
|
|
268
|
+
if isinstance(t, PendingTask):
|
|
269
|
+
lines.append(f"- [ ] {t.description} (prioridade: {t.priority})")
|
|
270
|
+
else:
|
|
271
|
+
lines.append(f"- [ ] {t}")
|
|
272
|
+
lines.append("")
|
|
273
|
+
|
|
274
|
+
if summary.files_modified:
|
|
275
|
+
lines.append("## Arquivos Modificados")
|
|
276
|
+
for f in summary.files_modified:
|
|
277
|
+
lines.append(f"- `{f['path']}` — {f['action']}")
|
|
278
|
+
lines.append("")
|
|
279
|
+
|
|
280
|
+
if summary.key_findings:
|
|
281
|
+
lines.append("## Descobertas")
|
|
282
|
+
for f in summary.key_findings:
|
|
283
|
+
lines.append(f"- {f}")
|
|
284
|
+
lines.append("")
|
|
285
|
+
|
|
286
|
+
if summary.errors_resolved:
|
|
287
|
+
lines.append("## Erros Resolvidos")
|
|
288
|
+
for e in summary.errors_resolved:
|
|
289
|
+
lines.append(f"- {e['error']}")
|
|
290
|
+
lines.append("")
|
|
291
|
+
|
|
292
|
+
if summary.open_questions:
|
|
293
|
+
lines.append("## Questões em Aberto")
|
|
294
|
+
for q in summary.open_questions:
|
|
295
|
+
lines.append(f"- {q}")
|
|
296
|
+
lines.append("")
|
|
297
|
+
|
|
298
|
+
if summary.technical_debt:
|
|
299
|
+
lines.append("## Dívida Técnica")
|
|
300
|
+
for d in summary.technical_debt:
|
|
301
|
+
lines.append(f"- {d}")
|
|
302
|
+
lines.append("")
|
|
303
|
+
|
|
304
|
+
lines.append("## Métricas")
|
|
305
|
+
lines.append(f"- Input tokens: {summary.total_input_tokens:,}")
|
|
306
|
+
lines.append(f"- Output tokens: {summary.total_output_tokens:,}")
|
|
307
|
+
lines.append(f"- Cache tokens: {summary.total_cache_tokens:,}")
|
|
308
|
+
lines.append(f"- Mensagens: {summary.message_count}")
|
|
309
|
+
lines.append(f"- Tool calls: {summary.tool_call_count}")
|
|
310
|
+
lines.append("")
|
|
311
|
+
|
|
312
|
+
# Link para sessão anterior
|
|
313
|
+
if summary.session_number > 1:
|
|
314
|
+
prev = summary.session_number - 1
|
|
315
|
+
lines.append("---")
|
|
316
|
+
lines.append(f"*Sessão anterior: [session-{prev:03d}](session-{prev:03d}.md)*")
|
|
317
|
+
|
|
318
|
+
path.write_text("\n".join(lines), encoding="utf-8")
|
|
319
|
+
return path
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Context Guardian — Snapshot Manager.
|
|
4
|
+
|
|
5
|
+
Cria, lista e le snapshots de contexto para preservacao
|
|
6
|
+
pre-compactacao. Os snapshots sao arquivos .md estruturados
|
|
7
|
+
com todas as informacoes criticas de uma sessao.
|
|
8
|
+
|
|
9
|
+
Uso:
|
|
10
|
+
python context_snapshot.py save --project "nome" --phase "fase" --summary "resumo"
|
|
11
|
+
python context_snapshot.py list
|
|
12
|
+
python context_snapshot.py latest
|
|
13
|
+
python context_snapshot.py read <snapshot-file>
|
|
14
|
+
python context_snapshot.py prune --keep 10
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import sys
|
|
19
|
+
import os
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
# ── Paths ──────────────────────────────────────────────────────────────────
|
|
24
|
+
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
25
|
+
SKILL_DIR = SCRIPT_DIR.parent
|
|
26
|
+
DATA_DIR = SKILL_DIR / "data"
|
|
27
|
+
|
|
28
|
+
# ── Functions ──────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
def ensure_data_dir():
|
|
31
|
+
"""Create data directory if it doesn't exist."""
|
|
32
|
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def save_snapshot(project: str = "", phase: str = "", summary: str = "") -> str:
|
|
36
|
+
"""
|
|
37
|
+
Create a new snapshot file with metadata header.
|
|
38
|
+
Returns the path to the created file.
|
|
39
|
+
|
|
40
|
+
The Claude agent is expected to APPEND the actual content
|
|
41
|
+
(extracted from the conversation) after this header is created.
|
|
42
|
+
"""
|
|
43
|
+
ensure_data_dir()
|
|
44
|
+
|
|
45
|
+
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
|
46
|
+
filename = f"snapshot-{timestamp}.md"
|
|
47
|
+
filepath = DATA_DIR / filename
|
|
48
|
+
|
|
49
|
+
header = f"""# Context Guardian Snapshot — {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
|
50
|
+
**Projeto**: {project or 'nao especificado'}
|
|
51
|
+
**Fase**: {phase or 'nao especificada'}
|
|
52
|
+
**Resumo**: {summary or 'snapshot pre-compactacao'}
|
|
53
|
+
**Modelo**: claude-opus-4-6
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
<!-- O Claude deve preencher as secoes abaixo seguindo references/extraction-protocol.md -->
|
|
58
|
+
|
|
59
|
+
## Arquivos Tocados
|
|
60
|
+
| Arquivo | Acao | Detalhes |
|
|
61
|
+
|---------|------|----------|
|
|
62
|
+
| | | |
|
|
63
|
+
|
|
64
|
+
## Decisoes
|
|
65
|
+
- (preencher)
|
|
66
|
+
|
|
67
|
+
## Correcoes
|
|
68
|
+
- (preencher)
|
|
69
|
+
|
|
70
|
+
## Progresso
|
|
71
|
+
- Total de tarefas:
|
|
72
|
+
- Concluidas:
|
|
73
|
+
- Pendentes:
|
|
74
|
+
|
|
75
|
+
## Trechos Criticos
|
|
76
|
+
- (preencher)
|
|
77
|
+
|
|
78
|
+
## Padroes Observados
|
|
79
|
+
- (preencher)
|
|
80
|
+
|
|
81
|
+
## Dependencias
|
|
82
|
+
- (preencher)
|
|
83
|
+
|
|
84
|
+
## Contexto do Usuario
|
|
85
|
+
- Objetivo:
|
|
86
|
+
- Proxima acao esperada:
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
*Snapshot gerado por context-guardian v1.0.0*
|
|
90
|
+
*Para restaurar: leia este arquivo + MEMORY.md + context_manager.py load*
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
filepath.write_text(header, encoding="utf-8")
|
|
94
|
+
return str(filepath)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def list_snapshots() -> list[dict]:
|
|
98
|
+
"""List all snapshots with metadata."""
|
|
99
|
+
ensure_data_dir()
|
|
100
|
+
snapshots = []
|
|
101
|
+
|
|
102
|
+
for f in sorted(DATA_DIR.glob("snapshot-*.md"), reverse=True):
|
|
103
|
+
stat = f.stat()
|
|
104
|
+
snapshots.append({
|
|
105
|
+
"file": f.name,
|
|
106
|
+
"path": str(f),
|
|
107
|
+
"size_kb": round(stat.st_size / 1024, 1),
|
|
108
|
+
"modified": datetime.fromtimestamp(stat.st_mtime).strftime("%Y-%m-%d %H:%M:%S"),
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
return snapshots
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def read_latest() -> dict:
|
|
115
|
+
"""Read the most recent snapshot."""
|
|
116
|
+
snapshots = list_snapshots()
|
|
117
|
+
if not snapshots:
|
|
118
|
+
return {"error": "Nenhum snapshot encontrado."}
|
|
119
|
+
|
|
120
|
+
latest = snapshots[0]
|
|
121
|
+
path = Path(latest["path"])
|
|
122
|
+
content = path.read_text(encoding="utf-8")
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
"file": latest["file"],
|
|
126
|
+
"path": latest["path"],
|
|
127
|
+
"size_kb": latest["size_kb"],
|
|
128
|
+
"content": content,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def read_snapshot(filename: str) -> dict:
|
|
133
|
+
"""Read a specific snapshot by filename."""
|
|
134
|
+
filepath = DATA_DIR / filename
|
|
135
|
+
if not filepath.exists():
|
|
136
|
+
return {"error": f"Arquivo nao encontrado: {filename}"}
|
|
137
|
+
|
|
138
|
+
content = filepath.read_text(encoding="utf-8")
|
|
139
|
+
return {
|
|
140
|
+
"file": filename,
|
|
141
|
+
"path": str(filepath),
|
|
142
|
+
"content": content,
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def prune_snapshots(keep: int = 10) -> dict:
|
|
147
|
+
"""Remove old snapshots, keeping the N most recent."""
|
|
148
|
+
snapshots = list_snapshots()
|
|
149
|
+
if len(snapshots) <= keep:
|
|
150
|
+
return {"pruned": 0, "remaining": len(snapshots)}
|
|
151
|
+
|
|
152
|
+
to_remove = snapshots[keep:]
|
|
153
|
+
for s in to_remove:
|
|
154
|
+
Path(s["path"]).unlink()
|
|
155
|
+
|
|
156
|
+
return {"pruned": len(to_remove), "remaining": keep}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
# ── CLI ────────────────────────────────────────────────────────────────────
|
|
160
|
+
|
|
161
|
+
def main():
|
|
162
|
+
args = sys.argv[1:]
|
|
163
|
+
|
|
164
|
+
if not args:
|
|
165
|
+
print(json.dumps({
|
|
166
|
+
"error": "Comando necessario: save, list, latest, read, prune",
|
|
167
|
+
"usage": "python context_snapshot.py <command> [options]",
|
|
168
|
+
}, indent=2, ensure_ascii=False))
|
|
169
|
+
sys.exit(1)
|
|
170
|
+
|
|
171
|
+
cmd = args[0]
|
|
172
|
+
|
|
173
|
+
if cmd == "save":
|
|
174
|
+
project = ""
|
|
175
|
+
phase = ""
|
|
176
|
+
summary = ""
|
|
177
|
+
i = 1
|
|
178
|
+
while i < len(args):
|
|
179
|
+
if args[i] == "--project" and i + 1 < len(args):
|
|
180
|
+
project = args[i + 1]
|
|
181
|
+
i += 2
|
|
182
|
+
elif args[i] == "--phase" and i + 1 < len(args):
|
|
183
|
+
phase = args[i + 1]
|
|
184
|
+
i += 2
|
|
185
|
+
elif args[i] == "--summary" and i + 1 < len(args):
|
|
186
|
+
summary = args[i + 1]
|
|
187
|
+
i += 2
|
|
188
|
+
else:
|
|
189
|
+
i += 1
|
|
190
|
+
|
|
191
|
+
path = save_snapshot(project, phase, summary)
|
|
192
|
+
print(json.dumps({
|
|
193
|
+
"status": "ok",
|
|
194
|
+
"action": "snapshot_created",
|
|
195
|
+
"path": path,
|
|
196
|
+
"next_step": "Preencher o snapshot com dados extraidos da conversa",
|
|
197
|
+
}, indent=2, ensure_ascii=False))
|
|
198
|
+
|
|
199
|
+
elif cmd == "list":
|
|
200
|
+
snapshots = list_snapshots()
|
|
201
|
+
print(json.dumps({
|
|
202
|
+
"total": len(snapshots),
|
|
203
|
+
"snapshots": snapshots,
|
|
204
|
+
}, indent=2, ensure_ascii=False))
|
|
205
|
+
|
|
206
|
+
elif cmd == "latest":
|
|
207
|
+
result = read_latest()
|
|
208
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
209
|
+
|
|
210
|
+
elif cmd == "read" and len(args) > 1:
|
|
211
|
+
result = read_snapshot(args[1])
|
|
212
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
213
|
+
|
|
214
|
+
elif cmd == "prune":
|
|
215
|
+
keep = 10
|
|
216
|
+
if "--keep" in args:
|
|
217
|
+
idx = args.index("--keep")
|
|
218
|
+
if idx + 1 < len(args):
|
|
219
|
+
keep = int(args[idx + 1])
|
|
220
|
+
result = prune_snapshots(keep)
|
|
221
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
222
|
+
|
|
223
|
+
else:
|
|
224
|
+
print(json.dumps({"error": f"Comando desconhecido: {cmd}"}, indent=2))
|
|
225
|
+
sys.exit(1)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
if __name__ == "__main__":
|
|
229
|
+
main()
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Tool to pack a directory into a .docx, .pptx, or .xlsx file with XML formatting undone.
|
|
4
|
+
|
|
5
|
+
Example usage:
|
|
6
|
+
python pack.py <input_directory> <office_file> [--force]
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import shutil
|
|
11
|
+
import subprocess
|
|
12
|
+
import sys
|
|
13
|
+
import tempfile
|
|
14
|
+
import defusedxml.minidom
|
|
15
|
+
import zipfile
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def main():
|
|
20
|
+
parser = argparse.ArgumentParser(description="Pack a directory into an Office file")
|
|
21
|
+
parser.add_argument("input_directory", help="Unpacked Office document directory")
|
|
22
|
+
parser.add_argument("output_file", help="Output Office file (.docx/.pptx/.xlsx)")
|
|
23
|
+
parser.add_argument("--force", action="store_true", help="Skip validation")
|
|
24
|
+
args = parser.parse_args()
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
success = pack_document(
|
|
28
|
+
args.input_directory, args.output_file, validate=not args.force
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Show warning if validation was skipped
|
|
32
|
+
if args.force:
|
|
33
|
+
print("Warning: Skipped validation, file may be corrupt", file=sys.stderr)
|
|
34
|
+
# Exit with error if validation failed
|
|
35
|
+
elif not success:
|
|
36
|
+
print("Contents would produce a corrupt file.", file=sys.stderr)
|
|
37
|
+
print("Please validate XML before repacking.", file=sys.stderr)
|
|
38
|
+
print("Use --force to skip validation and pack anyway.", file=sys.stderr)
|
|
39
|
+
sys.exit(1)
|
|
40
|
+
|
|
41
|
+
except ValueError as e:
|
|
42
|
+
sys.exit(f"Error: {e}")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def pack_document(input_dir, output_file, validate=False):
|
|
46
|
+
"""Pack a directory into an Office file (.docx/.pptx/.xlsx).
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
input_dir: Path to unpacked Office document directory
|
|
50
|
+
output_file: Path to output Office file
|
|
51
|
+
validate: If True, validates with soffice (default: False)
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
bool: True if successful, False if validation failed
|
|
55
|
+
"""
|
|
56
|
+
input_dir = Path(input_dir)
|
|
57
|
+
output_file = Path(output_file)
|
|
58
|
+
|
|
59
|
+
if not input_dir.is_dir():
|
|
60
|
+
raise ValueError(f"{input_dir} is not a directory")
|
|
61
|
+
if output_file.suffix.lower() not in {".docx", ".pptx", ".xlsx"}:
|
|
62
|
+
raise ValueError(f"{output_file} must be a .docx, .pptx, or .xlsx file")
|
|
63
|
+
|
|
64
|
+
# Work in temporary directory to avoid modifying original
|
|
65
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
66
|
+
temp_content_dir = Path(temp_dir) / "content"
|
|
67
|
+
shutil.copytree(input_dir, temp_content_dir)
|
|
68
|
+
|
|
69
|
+
# Process XML files to remove pretty-printing whitespace
|
|
70
|
+
for pattern in ["*.xml", "*.rels"]:
|
|
71
|
+
for xml_file in temp_content_dir.rglob(pattern):
|
|
72
|
+
condense_xml(xml_file)
|
|
73
|
+
|
|
74
|
+
# Create final Office file as zip archive
|
|
75
|
+
output_file.parent.mkdir(parents=True, exist_ok=True)
|
|
76
|
+
with zipfile.ZipFile(output_file, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
77
|
+
for f in temp_content_dir.rglob("*"):
|
|
78
|
+
if f.is_file():
|
|
79
|
+
zf.write(f, f.relative_to(temp_content_dir))
|
|
80
|
+
|
|
81
|
+
# Validate if requested
|
|
82
|
+
if validate:
|
|
83
|
+
if not validate_document(output_file):
|
|
84
|
+
output_file.unlink() # Delete the corrupt file
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
return True
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def validate_document(doc_path):
|
|
91
|
+
"""Validate document by converting to HTML with soffice."""
|
|
92
|
+
# Determine the correct filter based on file extension
|
|
93
|
+
match doc_path.suffix.lower():
|
|
94
|
+
case ".docx":
|
|
95
|
+
filter_name = "html:HTML"
|
|
96
|
+
case ".pptx":
|
|
97
|
+
filter_name = "html:impress_html_Export"
|
|
98
|
+
case ".xlsx":
|
|
99
|
+
filter_name = "html:HTML (StarCalc)"
|
|
100
|
+
|
|
101
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
102
|
+
try:
|
|
103
|
+
result = subprocess.run(
|
|
104
|
+
[
|
|
105
|
+
"soffice",
|
|
106
|
+
"--headless",
|
|
107
|
+
"--convert-to",
|
|
108
|
+
filter_name,
|
|
109
|
+
"--outdir",
|
|
110
|
+
temp_dir,
|
|
111
|
+
str(doc_path),
|
|
112
|
+
],
|
|
113
|
+
capture_output=True,
|
|
114
|
+
timeout=10,
|
|
115
|
+
text=True,
|
|
116
|
+
)
|
|
117
|
+
if not (Path(temp_dir) / f"{doc_path.stem}.html").exists():
|
|
118
|
+
error_msg = result.stderr.strip() or "Document validation failed"
|
|
119
|
+
print(f"Validation error: {error_msg}", file=sys.stderr)
|
|
120
|
+
return False
|
|
121
|
+
return True
|
|
122
|
+
except FileNotFoundError:
|
|
123
|
+
print("Warning: soffice not found. Skipping validation.", file=sys.stderr)
|
|
124
|
+
return True
|
|
125
|
+
except subprocess.TimeoutExpired:
|
|
126
|
+
print("Validation error: Timeout during conversion", file=sys.stderr)
|
|
127
|
+
return False
|
|
128
|
+
except Exception as e:
|
|
129
|
+
print(f"Validation error: {e}", file=sys.stderr)
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def condense_xml(xml_file):
|
|
134
|
+
"""Strip unnecessary whitespace and remove comments."""
|
|
135
|
+
with open(xml_file, "r", encoding="utf-8") as f:
|
|
136
|
+
dom = defusedxml.minidom.parse(f)
|
|
137
|
+
|
|
138
|
+
# Process each element to remove whitespace and comments
|
|
139
|
+
for element in dom.getElementsByTagName("*"):
|
|
140
|
+
# Skip w:t elements and their processing
|
|
141
|
+
if element.tagName.endswith(":t"):
|
|
142
|
+
continue
|
|
143
|
+
|
|
144
|
+
# Remove whitespace-only text nodes and comment nodes
|
|
145
|
+
for child in list(element.childNodes):
|
|
146
|
+
if (
|
|
147
|
+
child.nodeType == child.TEXT_NODE
|
|
148
|
+
and child.nodeValue
|
|
149
|
+
and child.nodeValue.strip() == ""
|
|
150
|
+
) or child.nodeType == child.COMMENT_NODE:
|
|
151
|
+
element.removeChild(child)
|
|
152
|
+
|
|
153
|
+
# Write back the condensed XML
|
|
154
|
+
with open(xml_file, "wb") as f:
|
|
155
|
+
f.write(dom.toxml(encoding="UTF-8"))
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
if __name__ == "__main__":
|
|
159
|
+
main()
|