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,164 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Analyzer de performance.
|
|
3
|
+
|
|
4
|
+
Verifica: chamadas API sequenciais, caching, N+1 queries,
|
|
5
|
+
connection reuse, retry/backoff, timeouts.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict, List, Tuple
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def analyze(skill_data: Dict[str, Any]) -> Tuple[float, List[Dict[str, Any]]]:
|
|
15
|
+
"""Analisa performance de uma skill. Retorna (score, findings)."""
|
|
16
|
+
score = 100.0
|
|
17
|
+
findings: List[Dict[str, Any]] = []
|
|
18
|
+
skill_name = skill_data["name"]
|
|
19
|
+
skill_path = Path(skill_data["path"])
|
|
20
|
+
|
|
21
|
+
has_retry = False
|
|
22
|
+
has_timeout = False
|
|
23
|
+
has_caching = False
|
|
24
|
+
has_connection_pool = False
|
|
25
|
+
has_async = False
|
|
26
|
+
has_concurrency = False
|
|
27
|
+
|
|
28
|
+
api_call_files = []
|
|
29
|
+
|
|
30
|
+
for rel_path in skill_data.get("python_files", []):
|
|
31
|
+
filepath = skill_path / rel_path
|
|
32
|
+
if not filepath.exists():
|
|
33
|
+
continue
|
|
34
|
+
try:
|
|
35
|
+
source = filepath.read_text(encoding="utf-8", errors="replace")
|
|
36
|
+
except OSError:
|
|
37
|
+
continue
|
|
38
|
+
|
|
39
|
+
# Detectar patterns de performance
|
|
40
|
+
if re.search(r'(?:retry|backoff|MAX_RETRIES|RETRY_BACKOFF)', source, re.I):
|
|
41
|
+
has_retry = True
|
|
42
|
+
if re.search(r'(?:timeout|REQUEST_TIMEOUT)', source, re.I):
|
|
43
|
+
has_timeout = True
|
|
44
|
+
if re.search(r'(?:cache|lru_cache|functools\.cache|_cache)', source, re.I):
|
|
45
|
+
has_caching = True
|
|
46
|
+
if re.search(r'(?:session|Session\(\)|httpx\.Client)', source, re.I):
|
|
47
|
+
has_connection_pool = True
|
|
48
|
+
if re.search(r'(?:async\s+def|asyncio|aiohttp|httpx\.AsyncClient)', source):
|
|
49
|
+
has_async = True
|
|
50
|
+
if re.search(r'(?:concurrent|ThreadPool|ProcessPool|asyncio\.gather|--concurrency)', source, re.I):
|
|
51
|
+
has_concurrency = True
|
|
52
|
+
|
|
53
|
+
# Contar chamadas API (requests.get/post, httpx, etc)
|
|
54
|
+
api_calls = len(re.findall(
|
|
55
|
+
r'(?:requests\.\w+|httpx\.\w+|self\.\w*(?:get|post|put|delete|patch))\s*\(',
|
|
56
|
+
source
|
|
57
|
+
))
|
|
58
|
+
if api_calls > 0:
|
|
59
|
+
api_call_files.append((rel_path, api_calls))
|
|
60
|
+
|
|
61
|
+
# Detectar N+1 patterns (loop com query SQL dentro)
|
|
62
|
+
# Analise linha-a-linha para evitar backtracking em regex DOTALL
|
|
63
|
+
lines = source.splitlines()
|
|
64
|
+
in_for_loop = False
|
|
65
|
+
for line_text in lines:
|
|
66
|
+
stripped = line_text.strip()
|
|
67
|
+
if stripped.startswith("for ") and stripped.endswith(":"):
|
|
68
|
+
in_for_loop = True
|
|
69
|
+
elif in_for_loop and stripped and not stripped[0].isspace() and not line_text[0].isspace():
|
|
70
|
+
in_for_loop = False
|
|
71
|
+
elif in_for_loop and re.search(r'(?:SELECT|\.execute)\s*\(', stripped):
|
|
72
|
+
findings.append({
|
|
73
|
+
"skill_name": skill_name,
|
|
74
|
+
"dimension": "performance",
|
|
75
|
+
"severity": "medium",
|
|
76
|
+
"category": "n_plus_1",
|
|
77
|
+
"title": f"Possivel N+1 query em {rel_path}",
|
|
78
|
+
"description": "Loop com query SQL pode causar muitas chamadas ao banco",
|
|
79
|
+
"file_path": rel_path,
|
|
80
|
+
"recommendation": "Carregar dados em batch antes do loop",
|
|
81
|
+
"effort": "medium",
|
|
82
|
+
"impact": "high",
|
|
83
|
+
})
|
|
84
|
+
score -= 8
|
|
85
|
+
break
|
|
86
|
+
|
|
87
|
+
# Criar conexao dentro de loop (analise simples)
|
|
88
|
+
has_connect_in_loop = False
|
|
89
|
+
in_for_loop = False
|
|
90
|
+
for line_text in lines:
|
|
91
|
+
stripped = line_text.strip()
|
|
92
|
+
if stripped.startswith("for ") and stripped.endswith(":"):
|
|
93
|
+
in_for_loop = True
|
|
94
|
+
elif in_for_loop and stripped and not line_text[0].isspace():
|
|
95
|
+
in_for_loop = False
|
|
96
|
+
elif in_for_loop and "_connect()" in stripped:
|
|
97
|
+
has_connect_in_loop = True
|
|
98
|
+
break
|
|
99
|
+
|
|
100
|
+
if has_connect_in_loop:
|
|
101
|
+
findings.append({
|
|
102
|
+
"skill_name": skill_name,
|
|
103
|
+
"dimension": "performance",
|
|
104
|
+
"severity": "medium",
|
|
105
|
+
"category": "connection_per_iteration",
|
|
106
|
+
"title": f"Conexao criada dentro de loop em {rel_path}",
|
|
107
|
+
"file_path": rel_path,
|
|
108
|
+
"recommendation": "Mover _connect() para fora do loop, reutilizar conexao",
|
|
109
|
+
"effort": "low",
|
|
110
|
+
"impact": "high",
|
|
111
|
+
})
|
|
112
|
+
score -= 5
|
|
113
|
+
|
|
114
|
+
# Verificar ausencia de boas praticas
|
|
115
|
+
if not has_retry and api_call_files:
|
|
116
|
+
findings.append({
|
|
117
|
+
"skill_name": skill_name,
|
|
118
|
+
"dimension": "performance",
|
|
119
|
+
"severity": "medium",
|
|
120
|
+
"category": "no_retry",
|
|
121
|
+
"title": "Sem retry/backoff para chamadas API",
|
|
122
|
+
"description": f"Encontradas chamadas API em {len(api_call_files)} arquivo(s) sem mecanismo de retry",
|
|
123
|
+
"recommendation": "Implementar retry com exponential backoff (ex: tenacity, ou manual)",
|
|
124
|
+
"effort": "medium",
|
|
125
|
+
"impact": "high",
|
|
126
|
+
})
|
|
127
|
+
score -= 10
|
|
128
|
+
|
|
129
|
+
if not has_timeout and api_call_files:
|
|
130
|
+
findings.append({
|
|
131
|
+
"skill_name": skill_name,
|
|
132
|
+
"dimension": "performance",
|
|
133
|
+
"severity": "medium",
|
|
134
|
+
"category": "no_timeout",
|
|
135
|
+
"title": "Sem timeout configurado para chamadas HTTP",
|
|
136
|
+
"recommendation": "Adicionar timeout= em todas as chamadas requests/httpx",
|
|
137
|
+
"effort": "low",
|
|
138
|
+
"impact": "medium",
|
|
139
|
+
})
|
|
140
|
+
score -= 5
|
|
141
|
+
|
|
142
|
+
if not has_connection_pool and len(api_call_files) > 2:
|
|
143
|
+
findings.append({
|
|
144
|
+
"skill_name": skill_name,
|
|
145
|
+
"dimension": "performance",
|
|
146
|
+
"severity": "low",
|
|
147
|
+
"category": "no_connection_reuse",
|
|
148
|
+
"title": "Sem reuso de conexoes HTTP",
|
|
149
|
+
"description": "Multiplos arquivos fazem chamadas HTTP sem Session/Client compartilhado",
|
|
150
|
+
"recommendation": "Usar requests.Session() ou httpx.Client() para reutilizar conexoes",
|
|
151
|
+
"effort": "low",
|
|
152
|
+
"impact": "medium",
|
|
153
|
+
})
|
|
154
|
+
score -= 3
|
|
155
|
+
|
|
156
|
+
# Bonus
|
|
157
|
+
if has_retry:
|
|
158
|
+
score = min(100.0, score + 5)
|
|
159
|
+
if has_async or has_concurrency:
|
|
160
|
+
score = min(100.0, score + 5)
|
|
161
|
+
if has_caching:
|
|
162
|
+
score = min(100.0, score + 3)
|
|
163
|
+
|
|
164
|
+
return max(0.0, min(100.0, score)), findings
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Analyzer de seguranca.
|
|
3
|
+
|
|
4
|
+
Verifica: secrets hardcoded, SQL injection, validacao de input,
|
|
5
|
+
HTTPS enforcement, tokens em logs, padroes de autenticacao.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict, List, Tuple
|
|
12
|
+
|
|
13
|
+
from config import SECRET_EXCEPTIONS, SECRET_PATTERNS, SQL_INJECTION_PATTERNS
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _check_secrets(source: str, rel_path: str, skill_name: str) -> List[Dict[str, Any]]:
|
|
17
|
+
"""Verifica patterns de secrets hardcoded."""
|
|
18
|
+
findings = []
|
|
19
|
+
for i, line in enumerate(source.splitlines(), 1):
|
|
20
|
+
for pattern in SECRET_PATTERNS:
|
|
21
|
+
if pattern.search(line):
|
|
22
|
+
# Checar se eh excecao conhecida
|
|
23
|
+
is_exception = any(exc in line for exc in SECRET_EXCEPTIONS)
|
|
24
|
+
if is_exception:
|
|
25
|
+
continue
|
|
26
|
+
findings.append({
|
|
27
|
+
"skill_name": skill_name,
|
|
28
|
+
"dimension": "security",
|
|
29
|
+
"severity": "critical",
|
|
30
|
+
"category": "hardcoded_secret",
|
|
31
|
+
"title": f"Possivel secret hardcoded em {rel_path}:{i}",
|
|
32
|
+
"description": "Credencial ou token encontrado no codigo-fonte. "
|
|
33
|
+
"Mover para variavel de ambiente.",
|
|
34
|
+
"file_path": rel_path,
|
|
35
|
+
"line_number": i,
|
|
36
|
+
"recommendation": "Usar os.environ.get() ou arquivo .env (nao versionado)",
|
|
37
|
+
"effort": "low",
|
|
38
|
+
"impact": "high",
|
|
39
|
+
})
|
|
40
|
+
return findings
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _check_sql_injection(source: str, rel_path: str, skill_name: str) -> List[Dict[str, Any]]:
|
|
44
|
+
"""Verifica uso de f-strings/format em queries SQL."""
|
|
45
|
+
findings = []
|
|
46
|
+
for i, line in enumerate(source.splitlines(), 1):
|
|
47
|
+
for pattern in SQL_INJECTION_PATTERNS:
|
|
48
|
+
if pattern.search(line):
|
|
49
|
+
findings.append({
|
|
50
|
+
"skill_name": skill_name,
|
|
51
|
+
"dimension": "security",
|
|
52
|
+
"severity": "high",
|
|
53
|
+
"category": "sql_injection",
|
|
54
|
+
"title": f"Possivel SQL injection em {rel_path}:{i}",
|
|
55
|
+
"description": "Interpolacao de string em query SQL. Usar queries parametrizadas (?)",
|
|
56
|
+
"file_path": rel_path,
|
|
57
|
+
"line_number": i,
|
|
58
|
+
"recommendation": "Substituir f-string/format por query parametrizada: cursor.execute(sql, [param])",
|
|
59
|
+
"effort": "low",
|
|
60
|
+
"impact": "high",
|
|
61
|
+
})
|
|
62
|
+
return findings
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _check_https(source: str, rel_path: str, skill_name: str) -> List[Dict[str, Any]]:
|
|
66
|
+
"""Verifica se URLs usam HTTP em vez de HTTPS."""
|
|
67
|
+
findings = []
|
|
68
|
+
http_pattern = re.compile(r'["\']http://(?!localhost|127\.0\.0\.1|0\.0\.0\.0)')
|
|
69
|
+
for i, line in enumerate(source.splitlines(), 1):
|
|
70
|
+
if http_pattern.search(line):
|
|
71
|
+
findings.append({
|
|
72
|
+
"skill_name": skill_name,
|
|
73
|
+
"dimension": "security",
|
|
74
|
+
"severity": "medium",
|
|
75
|
+
"category": "insecure_http",
|
|
76
|
+
"title": f"URL HTTP insegura em {rel_path}:{i}",
|
|
77
|
+
"description": "Uso de HTTP em vez de HTTPS para comunicacao externa.",
|
|
78
|
+
"file_path": rel_path,
|
|
79
|
+
"line_number": i,
|
|
80
|
+
"recommendation": "Trocar http:// por https://",
|
|
81
|
+
"effort": "low",
|
|
82
|
+
"impact": "medium",
|
|
83
|
+
})
|
|
84
|
+
return findings
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _check_token_in_logs(source: str, rel_path: str, skill_name: str) -> List[Dict[str, Any]]:
|
|
88
|
+
"""Verifica se tokens/secrets aparecem em print/logging."""
|
|
89
|
+
findings = []
|
|
90
|
+
log_pattern = re.compile(
|
|
91
|
+
r'(?:print|logging\.\w+|logger\.\w+)\s*\(.*(?:token|secret|password|key|credential)',
|
|
92
|
+
re.I
|
|
93
|
+
)
|
|
94
|
+
for i, line in enumerate(source.splitlines(), 1):
|
|
95
|
+
if log_pattern.search(line):
|
|
96
|
+
findings.append({
|
|
97
|
+
"skill_name": skill_name,
|
|
98
|
+
"dimension": "security",
|
|
99
|
+
"severity": "high",
|
|
100
|
+
"category": "token_in_log",
|
|
101
|
+
"title": f"Possivel token em log em {rel_path}:{i}",
|
|
102
|
+
"description": "Dados sensiveis podem estar sendo logados.",
|
|
103
|
+
"file_path": rel_path,
|
|
104
|
+
"line_number": i,
|
|
105
|
+
"recommendation": "Nao logar tokens/secrets. Usar mascaramento ou remover do log.",
|
|
106
|
+
"effort": "low",
|
|
107
|
+
"impact": "high",
|
|
108
|
+
})
|
|
109
|
+
return findings
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _check_input_validation(source: str, rel_path: str, skill_name: str) -> List[Dict[str, Any]]:
|
|
113
|
+
"""Verifica se argumentos CLI sao validados."""
|
|
114
|
+
findings = []
|
|
115
|
+
# Se usa argparse mas nao tem choices/type/nargs restritivos, e warning leve
|
|
116
|
+
if "argparse" in source and "add_argument" in source:
|
|
117
|
+
# Verificar se ao menos alguns args tem type= ou choices=
|
|
118
|
+
args_count = source.count("add_argument")
|
|
119
|
+
typed_count = len(re.findall(r'add_argument\([^)]*(?:type=|choices=)', source))
|
|
120
|
+
if args_count > 3 and typed_count == 0:
|
|
121
|
+
findings.append({
|
|
122
|
+
"skill_name": skill_name,
|
|
123
|
+
"dimension": "security",
|
|
124
|
+
"severity": "low",
|
|
125
|
+
"category": "weak_input_validation",
|
|
126
|
+
"title": f"Validacao fraca de argumentos CLI em {rel_path}",
|
|
127
|
+
"description": f"{args_count} argumentos sem type= ou choices=",
|
|
128
|
+
"file_path": rel_path,
|
|
129
|
+
"recommendation": "Adicionar type= e choices= nos argumentos do argparse",
|
|
130
|
+
"effort": "low",
|
|
131
|
+
"impact": "low",
|
|
132
|
+
})
|
|
133
|
+
return findings
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def analyze(skill_data: Dict[str, Any]) -> Tuple[float, List[Dict[str, Any]]]:
|
|
137
|
+
"""Analisa seguranca de uma skill. Retorna (score, findings)."""
|
|
138
|
+
score = 100.0
|
|
139
|
+
findings: List[Dict[str, Any]] = []
|
|
140
|
+
skill_name = skill_data["name"]
|
|
141
|
+
skill_path = Path(skill_data["path"])
|
|
142
|
+
|
|
143
|
+
has_auth_module = False
|
|
144
|
+
uses_env_vars = False
|
|
145
|
+
|
|
146
|
+
for rel_path in skill_data.get("python_files", []):
|
|
147
|
+
filepath = skill_path / rel_path
|
|
148
|
+
if not filepath.exists():
|
|
149
|
+
continue
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
source = filepath.read_text(encoding="utf-8", errors="replace")
|
|
153
|
+
except OSError:
|
|
154
|
+
continue
|
|
155
|
+
|
|
156
|
+
if "auth" in rel_path.lower():
|
|
157
|
+
has_auth_module = True
|
|
158
|
+
if "os.environ" in source or "os.getenv" in source or "dotenv" in source:
|
|
159
|
+
uses_env_vars = True
|
|
160
|
+
|
|
161
|
+
# Checks
|
|
162
|
+
secret_findings = _check_secrets(source, rel_path, skill_name)
|
|
163
|
+
findings.extend(secret_findings)
|
|
164
|
+
score -= len([f for f in secret_findings if f["severity"] == "critical"]) * 20
|
|
165
|
+
score -= len([f for f in secret_findings if f["severity"] == "high"]) * 10
|
|
166
|
+
|
|
167
|
+
sql_findings = _check_sql_injection(source, rel_path, skill_name)
|
|
168
|
+
findings.extend(sql_findings)
|
|
169
|
+
score -= len(sql_findings) * 15
|
|
170
|
+
|
|
171
|
+
https_findings = _check_https(source, rel_path, skill_name)
|
|
172
|
+
findings.extend(https_findings)
|
|
173
|
+
score -= len(https_findings) * 5
|
|
174
|
+
|
|
175
|
+
token_findings = _check_token_in_logs(source, rel_path, skill_name)
|
|
176
|
+
findings.extend(token_findings)
|
|
177
|
+
score -= len(token_findings) * 10
|
|
178
|
+
|
|
179
|
+
input_findings = _check_input_validation(source, rel_path, skill_name)
|
|
180
|
+
findings.extend(input_findings)
|
|
181
|
+
score -= len(input_findings) * 2
|
|
182
|
+
|
|
183
|
+
# Bonus por boas praticas
|
|
184
|
+
if has_auth_module:
|
|
185
|
+
score = min(100.0, score + 5)
|
|
186
|
+
if uses_env_vars:
|
|
187
|
+
score = min(100.0, score + 5)
|
|
188
|
+
|
|
189
|
+
return max(0.0, min(100.0, score)), findings
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuracao central da skill Sentinel.
|
|
3
|
+
|
|
4
|
+
Paths, thresholds de analise, pesos de scoring e padroes de seguranca.
|
|
5
|
+
Importado por todos os outros scripts.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict, List, Tuple
|
|
12
|
+
|
|
13
|
+
# -- Paths --------------------------------------------------------------------
|
|
14
|
+
ROOT_DIR = Path(__file__).resolve().parent.parent
|
|
15
|
+
SCRIPTS_DIR = ROOT_DIR / "scripts"
|
|
16
|
+
DATA_DIR = ROOT_DIR / "data"
|
|
17
|
+
REPORTS_DIR = DATA_DIR / "reports"
|
|
18
|
+
DB_PATH = DATA_DIR / "sentinel.db"
|
|
19
|
+
|
|
20
|
+
# Raiz do ecossistema de skills
|
|
21
|
+
SKILLS_ROOT = ROOT_DIR.parent
|
|
22
|
+
|
|
23
|
+
# Garante que diretorios existem
|
|
24
|
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
25
|
+
REPORTS_DIR.mkdir(parents=True, exist_ok=True)
|
|
26
|
+
|
|
27
|
+
# -- Skill Discovery ----------------------------------------------------------
|
|
28
|
+
# Locais onde skills podem estar (relativo a SKILLS_ROOT)
|
|
29
|
+
SKILL_SEARCH_PATHS: List[Path] = [
|
|
30
|
+
SKILLS_ROOT, # skills de primeiro nivel
|
|
31
|
+
SKILLS_ROOT / ".claude" / "skills", # skills built-in do Claude
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
# Subdiretorios a escanear recursivamente (para skills aninhadas)
|
|
35
|
+
SKILL_MAX_DEPTH = 3
|
|
36
|
+
|
|
37
|
+
# Diretorios a ignorar durante o scan
|
|
38
|
+
IGNORE_DIRS = {
|
|
39
|
+
"__pycache__", ".git", "node_modules", ".venv", "venv",
|
|
40
|
+
"data", "exports", "static", ".claude",
|
|
41
|
+
"skill-sentinel", # nao auditar a si mesmo
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# -- Scoring Weights (devem somar 1.0) ----------------------------------------
|
|
45
|
+
DIMENSION_WEIGHTS: Dict[str, float] = {
|
|
46
|
+
"code_quality": 0.20,
|
|
47
|
+
"security": 0.20,
|
|
48
|
+
"performance": 0.15,
|
|
49
|
+
"governance": 0.15,
|
|
50
|
+
"documentation": 0.15,
|
|
51
|
+
"dependencies": 0.15,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# -- Score Labels --------------------------------------------------------------
|
|
55
|
+
SCORE_LABELS: List[Tuple[int, int, str]] = [
|
|
56
|
+
(90, 100, "Excelente"),
|
|
57
|
+
(75, 89, "Bom"),
|
|
58
|
+
(50, 74, "Adequado"),
|
|
59
|
+
(25, 49, "Precisa melhorar"),
|
|
60
|
+
(0, 24, "Critico"),
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
def get_score_label(score: float) -> str:
|
|
64
|
+
"""Retorna label textual para um score numerico."""
|
|
65
|
+
for low, high, label in SCORE_LABELS:
|
|
66
|
+
if low <= score <= high:
|
|
67
|
+
return label
|
|
68
|
+
return "Desconhecido"
|
|
69
|
+
|
|
70
|
+
# -- Code Quality Thresholds ---------------------------------------------------
|
|
71
|
+
MAX_FUNCTION_LINES = 50
|
|
72
|
+
MAX_CYCLOMATIC_COMPLEXITY = 10
|
|
73
|
+
MAX_FILE_LINES = 500
|
|
74
|
+
MIN_DOCSTRING_COVERAGE = 0.5
|
|
75
|
+
|
|
76
|
+
# Penalidades (pontos subtraidos de 100)
|
|
77
|
+
PENALTY_HIGH_COMPLEXITY = 5 # por funcao acima do limite
|
|
78
|
+
PENALTY_LONG_FUNCTION = 3 # por funcao acima do limite
|
|
79
|
+
PENALTY_LONG_FILE = 5 # por arquivo acima do limite
|
|
80
|
+
PENALTY_NO_DOCSTRING = 1 # por funcao/classe sem docstring
|
|
81
|
+
PENALTY_BARE_EXCEPT = 8 # por bare except
|
|
82
|
+
PENALTY_BROAD_EXCEPT = 3 # por except Exception sem log
|
|
83
|
+
|
|
84
|
+
# -- Security Patterns ---------------------------------------------------------
|
|
85
|
+
SECRET_PATTERNS: List[re.Pattern] = [
|
|
86
|
+
re.compile(r'(?:password|passwd|pwd)\s*=\s*["\'][^"\']{8,}["\']', re.I),
|
|
87
|
+
re.compile(r'(?:secret|secret_key)\s*=\s*["\'][^"\']{8,}["\']', re.I),
|
|
88
|
+
re.compile(r'(?:api_key|apikey|api_secret)\s*=\s*["\'][^"\']{8,}["\']', re.I),
|
|
89
|
+
re.compile(r'(?:access_token|auth_token)\s*=\s*["\'][^"\']{8,}["\']', re.I),
|
|
90
|
+
re.compile(r'(?:private_key|ssh_key)\s*=\s*["\']', re.I),
|
|
91
|
+
re.compile(r'(?:aws_access_key_id|aws_secret)\s*=\s*["\']', re.I),
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
# Padroes que sao excepcoes conhecidas (nao sao secrets reais)
|
|
95
|
+
SECRET_EXCEPTIONS: List[str] = [
|
|
96
|
+
"546c25a59c58ad7", # Imgur public anonymous upload key
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
SQL_INJECTION_PATTERNS: List[re.Pattern] = [
|
|
100
|
+
re.compile(r'f["\'].*(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE).*\{', re.I),
|
|
101
|
+
re.compile(r'\.format\(.*(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE)', re.I),
|
|
102
|
+
re.compile(r'%\s*\(.*(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE)', re.I),
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
# -- Performance Thresholds ----------------------------------------------------
|
|
106
|
+
MAX_SEQUENTIAL_API_CALLS = 5 # sugerir batching se > este numero
|
|
107
|
+
WARN_NO_RETRY = True # avisar se nao tem retry/backoff
|
|
108
|
+
WARN_NO_TIMEOUT = True # avisar se requests sem timeout
|
|
109
|
+
|
|
110
|
+
# -- Governance Maturity Levels ------------------------------------------------
|
|
111
|
+
GOVERNANCE_LEVELS: Dict[int, str] = {
|
|
112
|
+
0: "Nenhuma",
|
|
113
|
+
1: "Basica (action logging)",
|
|
114
|
+
2: "Padrao (logging + rate limiting)",
|
|
115
|
+
3: "Completa (logging + rate limit + confirmacoes)",
|
|
116
|
+
4: "Avancada (completa + alertas + trends)",
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# -- Documentation Required Sections -------------------------------------------
|
|
120
|
+
SKILL_MD_REQUIRED_SECTIONS: List[str] = [
|
|
121
|
+
"name", # frontmatter
|
|
122
|
+
"description", # frontmatter
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
SKILL_MD_RECOMMENDED_SECTIONS: List[str] = [
|
|
126
|
+
"version", # frontmatter
|
|
127
|
+
"instalacao", # ou "installation"
|
|
128
|
+
"comandos", # ou "commands", "uso", "usage"
|
|
129
|
+
"governanca", # ou "governance"
|
|
130
|
+
"referencias", # ou "references"
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
# -- Severity Ordering ---------------------------------------------------------
|
|
134
|
+
SEVERITY_ORDER = {"critical": 0, "high": 1, "medium": 2, "low": 3, "info": 4}
|
|
135
|
+
|
|
136
|
+
# -- Gap Analysis Taxonomy -----------------------------------------------------
|
|
137
|
+
CAPABILITY_TAXONOMY: Dict[str, str] = {
|
|
138
|
+
"data-extraction": "Extracao de dados de fontes externas",
|
|
139
|
+
"social-media": "Integracao com redes sociais",
|
|
140
|
+
"messaging": "Sistemas de mensageria",
|
|
141
|
+
"government-data": "Dados governamentais e registros publicos",
|
|
142
|
+
"web-automation": "Automacao de browser e interacoes web",
|
|
143
|
+
"api-integration": "Integracao com APIs externas",
|
|
144
|
+
"analytics": "Analise de dados e metricas",
|
|
145
|
+
"content-management": "Gestao e criacao de conteudo",
|
|
146
|
+
"testing": "Testes automatizados e QA",
|
|
147
|
+
"monitoring": "Monitoramento e alertas",
|
|
148
|
+
"ci-cd": "Integracao e deploy continuo",
|
|
149
|
+
"documentation-gen": "Geracao automatica de documentacao",
|
|
150
|
+
"data-pipeline": "ETL e pipelines de dados",
|
|
151
|
+
"scheduling": "Agendamento e cron jobs",
|
|
152
|
+
"notification": "Notificacoes multi-canal",
|
|
153
|
+
"email-integration": "Integracao com email",
|
|
154
|
+
"database-management": "Gestao de bancos de dados",
|
|
155
|
+
"file-management": "Gestao de arquivos e storage",
|
|
156
|
+
"security-audit": "Auditoria de seguranca",
|
|
157
|
+
"cost-optimization": "Otimizacao de custos e recursos",
|
|
158
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cost Optimizer: analisa padroes que impactam consumo de tokens e custos de API.
|
|
3
|
+
|
|
4
|
+
Identifica SKILL.md muito grandes (impacto direto em tokens consumidos pelo Claude),
|
|
5
|
+
output verboso, oportunidades de cache, e padrao de chamadas API.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any, Dict, List, Tuple
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def analyze(skill_data: Dict[str, Any]) -> Tuple[float, List[Dict[str, Any]]]:
|
|
14
|
+
"""
|
|
15
|
+
Analisa custos de uma skill. Retorna (score, findings).
|
|
16
|
+
Score alto = skill eficiente em custo.
|
|
17
|
+
"""
|
|
18
|
+
score = 100.0
|
|
19
|
+
findings: List[Dict[str, Any]] = []
|
|
20
|
+
skill_name = skill_data["name"]
|
|
21
|
+
skill_path = Path(skill_data["path"])
|
|
22
|
+
|
|
23
|
+
# -- 1. Tamanho do SKILL.md (impacto direto em context window) ---------------
|
|
24
|
+
skill_md_lines = skill_data.get("skill_md_lines", 0)
|
|
25
|
+
|
|
26
|
+
if skill_md_lines > 500:
|
|
27
|
+
cost_impact = "alto"
|
|
28
|
+
severity = "high"
|
|
29
|
+
score -= 20
|
|
30
|
+
elif skill_md_lines > 300:
|
|
31
|
+
cost_impact = "medio"
|
|
32
|
+
severity = "medium"
|
|
33
|
+
score -= 10
|
|
34
|
+
elif skill_md_lines > 150:
|
|
35
|
+
cost_impact = "baixo"
|
|
36
|
+
severity = "low"
|
|
37
|
+
score -= 3
|
|
38
|
+
else:
|
|
39
|
+
cost_impact = None
|
|
40
|
+
|
|
41
|
+
if cost_impact:
|
|
42
|
+
# Estimar tokens: ~1.3 tokens por palavra, ~10 palavras por linha
|
|
43
|
+
est_tokens = int(skill_md_lines * 10 * 1.3)
|
|
44
|
+
findings.append({
|
|
45
|
+
"skill_name": skill_name,
|
|
46
|
+
"dimension": "cost",
|
|
47
|
+
"severity": severity,
|
|
48
|
+
"category": "large_skill_md",
|
|
49
|
+
"title": f"SKILL.md com {skill_md_lines} linhas (~{est_tokens:,} tokens estimados)",
|
|
50
|
+
"description": f"Impacto de custo {cost_impact}. Cada ativacao desta skill "
|
|
51
|
+
f"consome ~{est_tokens:,} tokens do context window.",
|
|
52
|
+
"recommendation": "Mover detalhes para references/ e manter SKILL.md < 200 linhas. "
|
|
53
|
+
"Usar progressive disclosure: SKILL.md = overview, "
|
|
54
|
+
"references/ = detalhes lidos sob demanda.",
|
|
55
|
+
"effort": "medium",
|
|
56
|
+
"impact": "high",
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
# -- 2. References muito grandes ----------------------------------------------
|
|
60
|
+
ref_dir = skill_path / "references"
|
|
61
|
+
if ref_dir.exists():
|
|
62
|
+
for ref_file in ref_dir.glob("*.md"):
|
|
63
|
+
try:
|
|
64
|
+
lines = len(ref_file.read_text(encoding="utf-8", errors="replace").splitlines())
|
|
65
|
+
except OSError:
|
|
66
|
+
continue
|
|
67
|
+
if lines > 300:
|
|
68
|
+
est_tokens = int(lines * 10 * 1.3)
|
|
69
|
+
findings.append({
|
|
70
|
+
"skill_name": skill_name,
|
|
71
|
+
"dimension": "cost",
|
|
72
|
+
"severity": "low",
|
|
73
|
+
"category": "large_reference",
|
|
74
|
+
"title": f"Reference grande: {ref_file.name} ({lines} linhas, ~{est_tokens:,} tokens)",
|
|
75
|
+
"description": "Se carregado inteiro no contexto, consome muitos tokens.",
|
|
76
|
+
"file_path": f"references/{ref_file.name}",
|
|
77
|
+
"recommendation": "Adicionar indice/TOC no inicio. Instruir no SKILL.md "
|
|
78
|
+
"para ler apenas secoes relevantes.",
|
|
79
|
+
"effort": "low",
|
|
80
|
+
"impact": "medium",
|
|
81
|
+
})
|
|
82
|
+
score -= 3
|
|
83
|
+
|
|
84
|
+
# -- 3. Output verboso dos scripts --------------------------------------------
|
|
85
|
+
for rel_path in skill_data.get("python_files", []):
|
|
86
|
+
filepath = skill_path / rel_path
|
|
87
|
+
if not filepath.exists():
|
|
88
|
+
continue
|
|
89
|
+
try:
|
|
90
|
+
source = filepath.read_text(encoding="utf-8", errors="replace")
|
|
91
|
+
except OSError:
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
# Contar prints verbosos
|
|
95
|
+
import re
|
|
96
|
+
print_count = len(re.findall(r'\bprint\s*\(', source))
|
|
97
|
+
lines = len(source.splitlines())
|
|
98
|
+
|
|
99
|
+
# Se >10% das linhas sao prints, eh verboso
|
|
100
|
+
if lines > 20 and print_count > 0 and (print_count / lines) > 0.08:
|
|
101
|
+
findings.append({
|
|
102
|
+
"skill_name": skill_name,
|
|
103
|
+
"dimension": "cost",
|
|
104
|
+
"severity": "low",
|
|
105
|
+
"category": "verbose_output",
|
|
106
|
+
"title": f"Output verboso em {rel_path} ({print_count} prints em {lines} linhas)",
|
|
107
|
+
"description": "Output excessivo consome tokens do context window quando "
|
|
108
|
+
"Claude le a saida do script.",
|
|
109
|
+
"file_path": rel_path,
|
|
110
|
+
"recommendation": "Usar --verbose flag ou logging levels em vez de prints fixos. "
|
|
111
|
+
"Retornar JSON conciso por padrao.",
|
|
112
|
+
"effort": "low",
|
|
113
|
+
"impact": "medium",
|
|
114
|
+
})
|
|
115
|
+
score -= 3
|
|
116
|
+
|
|
117
|
+
# -- 4. Verificar se scripts retornam JSON estruturado vs texto livre -----------
|
|
118
|
+
has_json_output = False
|
|
119
|
+
for rel_path in skill_data.get("python_files", []):
|
|
120
|
+
filepath = skill_path / rel_path
|
|
121
|
+
if not filepath.exists():
|
|
122
|
+
continue
|
|
123
|
+
try:
|
|
124
|
+
source = filepath.read_text(encoding="utf-8", errors="replace")
|
|
125
|
+
except OSError:
|
|
126
|
+
continue
|
|
127
|
+
if "json.dumps" in source or "json.dump" in source:
|
|
128
|
+
has_json_output = True
|
|
129
|
+
break
|
|
130
|
+
|
|
131
|
+
if not has_json_output and skill_data.get("file_count", 0) > 3:
|
|
132
|
+
findings.append({
|
|
133
|
+
"skill_name": skill_name,
|
|
134
|
+
"dimension": "cost",
|
|
135
|
+
"severity": "low",
|
|
136
|
+
"category": "no_structured_output",
|
|
137
|
+
"title": "Sem output JSON estruturado",
|
|
138
|
+
"description": "Scripts que retornam JSON sao mais eficientes para o Claude processar "
|
|
139
|
+
"do que texto livre.",
|
|
140
|
+
"recommendation": "Adicionar opcao --json para output estruturado em scripts principais",
|
|
141
|
+
"effort": "low",
|
|
142
|
+
"impact": "medium",
|
|
143
|
+
})
|
|
144
|
+
score -= 5
|
|
145
|
+
|
|
146
|
+
return max(0.0, min(100.0, score)), findings
|