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,193 @@
|
|
|
1
|
+
import axios, { AxiosInstance } from 'axios';
|
|
2
|
+
import { WhatsAppConfig, SendMessagePayload, SendMessageResponse } from './types';
|
|
3
|
+
|
|
4
|
+
export class WhatsAppClient {
|
|
5
|
+
private client: AxiosInstance;
|
|
6
|
+
private phoneNumberId: string;
|
|
7
|
+
private wabaId: string;
|
|
8
|
+
|
|
9
|
+
constructor(config: WhatsAppConfig) {
|
|
10
|
+
const version = config.graphApiVersion || 'v21.0';
|
|
11
|
+
this.phoneNumberId = config.phoneNumberId;
|
|
12
|
+
this.wabaId = config.wabaId;
|
|
13
|
+
|
|
14
|
+
this.client = axios.create({
|
|
15
|
+
baseURL: `https://graph.facebook.com/${version}`,
|
|
16
|
+
headers: {
|
|
17
|
+
Authorization: `Bearer ${config.token}`,
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async sendMessage(payload: SendMessagePayload): Promise<SendMessageResponse> {
|
|
24
|
+
return this.sendWithRetry(payload);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async sendText(to: string, body: string, previewUrl = false): Promise<SendMessageResponse> {
|
|
28
|
+
return this.sendMessage({
|
|
29
|
+
messaging_product: 'whatsapp',
|
|
30
|
+
to,
|
|
31
|
+
type: 'text',
|
|
32
|
+
text: { body, preview_url: previewUrl },
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async sendTemplate(
|
|
37
|
+
to: string,
|
|
38
|
+
templateName: string,
|
|
39
|
+
languageCode: string,
|
|
40
|
+
components?: SendMessagePayload['template']
|
|
41
|
+
): Promise<SendMessageResponse> {
|
|
42
|
+
return this.sendMessage({
|
|
43
|
+
messaging_product: 'whatsapp',
|
|
44
|
+
to,
|
|
45
|
+
type: 'template',
|
|
46
|
+
template: {
|
|
47
|
+
name: templateName,
|
|
48
|
+
language: { code: languageCode },
|
|
49
|
+
...components,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async sendImage(to: string, imageUrl: string, caption?: string): Promise<SendMessageResponse> {
|
|
55
|
+
return this.sendMessage({
|
|
56
|
+
messaging_product: 'whatsapp',
|
|
57
|
+
to,
|
|
58
|
+
type: 'image',
|
|
59
|
+
image: { link: imageUrl, caption },
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async sendDocument(
|
|
64
|
+
to: string,
|
|
65
|
+
documentUrl: string,
|
|
66
|
+
filename: string,
|
|
67
|
+
caption?: string
|
|
68
|
+
): Promise<SendMessageResponse> {
|
|
69
|
+
return this.sendMessage({
|
|
70
|
+
messaging_product: 'whatsapp',
|
|
71
|
+
to,
|
|
72
|
+
type: 'document',
|
|
73
|
+
document: { link: documentUrl, filename, caption },
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async sendInteractiveButtons(
|
|
78
|
+
to: string,
|
|
79
|
+
bodyText: string,
|
|
80
|
+
buttons: Array<{ id: string; title: string }>,
|
|
81
|
+
headerText?: string,
|
|
82
|
+
footerText?: string
|
|
83
|
+
): Promise<SendMessageResponse> {
|
|
84
|
+
return this.sendMessage({
|
|
85
|
+
messaging_product: 'whatsapp',
|
|
86
|
+
to,
|
|
87
|
+
type: 'interactive',
|
|
88
|
+
interactive: {
|
|
89
|
+
type: 'button',
|
|
90
|
+
...(headerText && { header: { type: 'text', text: headerText } }),
|
|
91
|
+
body: { text: bodyText },
|
|
92
|
+
...(footerText && { footer: { text: footerText } }),
|
|
93
|
+
action: {
|
|
94
|
+
buttons: buttons.map((b) => ({
|
|
95
|
+
type: 'reply' as const,
|
|
96
|
+
reply: { id: b.id, title: b.title },
|
|
97
|
+
})),
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async sendInteractiveList(
|
|
104
|
+
to: string,
|
|
105
|
+
bodyText: string,
|
|
106
|
+
buttonText: string,
|
|
107
|
+
sections: Array<{
|
|
108
|
+
title: string;
|
|
109
|
+
rows: Array<{ id: string; title: string; description?: string }>;
|
|
110
|
+
}>,
|
|
111
|
+
headerText?: string,
|
|
112
|
+
footerText?: string
|
|
113
|
+
): Promise<SendMessageResponse> {
|
|
114
|
+
return this.sendMessage({
|
|
115
|
+
messaging_product: 'whatsapp',
|
|
116
|
+
to,
|
|
117
|
+
type: 'interactive',
|
|
118
|
+
interactive: {
|
|
119
|
+
type: 'list',
|
|
120
|
+
...(headerText && { header: { type: 'text', text: headerText } }),
|
|
121
|
+
body: { text: bodyText },
|
|
122
|
+
...(footerText && { footer: { text: footerText } }),
|
|
123
|
+
action: { button: buttonText, sections },
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async sendReaction(to: string, messageId: string, emoji: string): Promise<SendMessageResponse> {
|
|
129
|
+
return this.sendMessage({
|
|
130
|
+
messaging_product: 'whatsapp',
|
|
131
|
+
to,
|
|
132
|
+
type: 'reaction',
|
|
133
|
+
reaction: { message_id: messageId, emoji },
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async sendLocation(
|
|
138
|
+
to: string,
|
|
139
|
+
latitude: number,
|
|
140
|
+
longitude: number,
|
|
141
|
+
name?: string,
|
|
142
|
+
address?: string
|
|
143
|
+
): Promise<SendMessageResponse> {
|
|
144
|
+
return this.sendMessage({
|
|
145
|
+
messaging_product: 'whatsapp',
|
|
146
|
+
to,
|
|
147
|
+
type: 'location',
|
|
148
|
+
location: { latitude, longitude, name, address },
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async markAsRead(messageId: string): Promise<void> {
|
|
153
|
+
await this.client.post(`/${this.phoneNumberId}/messages`, {
|
|
154
|
+
messaging_product: 'whatsapp',
|
|
155
|
+
status: 'read',
|
|
156
|
+
message_id: messageId,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private async sendWithRetry(
|
|
161
|
+
payload: SendMessagePayload,
|
|
162
|
+
maxRetries = 3
|
|
163
|
+
): Promise<SendMessageResponse> {
|
|
164
|
+
const nonRetryableCodes = [100, 131026, 131051, 132000, 132001, 132005, 133010];
|
|
165
|
+
|
|
166
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
167
|
+
try {
|
|
168
|
+
const response = await this.client.post<SendMessageResponse>(
|
|
169
|
+
`/${this.phoneNumberId}/messages`,
|
|
170
|
+
payload
|
|
171
|
+
);
|
|
172
|
+
return response.data;
|
|
173
|
+
} catch (error: any) {
|
|
174
|
+
const errorCode = error.response?.data?.error?.code;
|
|
175
|
+
const errorMessage = error.response?.data?.error?.message || error.message;
|
|
176
|
+
|
|
177
|
+
if (nonRetryableCodes.includes(errorCode)) {
|
|
178
|
+
throw new Error(`WhatsApp API Error ${errorCode}: ${errorMessage}`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (attempt < maxRetries) {
|
|
182
|
+
const delay = Math.pow(2, attempt) * 1000;
|
|
183
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
throw new Error(`WhatsApp API Error after ${maxRetries} retries: ${errorMessage}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
throw new Error('Unexpected: retry loop exited without return or throw');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Send a test message via WhatsApp Cloud API.
|
|
4
|
+
|
|
5
|
+
Quick way to validate your setup by sending a text message.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
python send_test_message.py --to 5511999999999 --message "Hello from WhatsApp API!"
|
|
9
|
+
python send_test_message.py --to 5511999999999 # Uses default test message
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
import httpx
|
|
19
|
+
except ImportError:
|
|
20
|
+
print("Error: httpx not installed. Run: pip install httpx")
|
|
21
|
+
sys.exit(1)
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
from dotenv import load_dotenv
|
|
25
|
+
except ImportError:
|
|
26
|
+
load_dotenv = None
|
|
27
|
+
|
|
28
|
+
GRAPH_API = "https://graph.facebook.com/v21.0"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _mask_secret(value: str) -> str:
|
|
32
|
+
"""Return a masked version of a secret for safe logging."""
|
|
33
|
+
if not value or len(value) < 8:
|
|
34
|
+
return "***masked***"
|
|
35
|
+
return f"{value[:6]}...masked"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def send_test(to: str, message: str) -> None:
|
|
39
|
+
"""Send a test text message."""
|
|
40
|
+
token = os.environ.get("WHATSAPP_TOKEN")
|
|
41
|
+
phone_id = os.environ.get("PHONE_NUMBER_ID")
|
|
42
|
+
|
|
43
|
+
if not token or not phone_id:
|
|
44
|
+
print("Error: WHATSAPP_TOKEN and PHONE_NUMBER_ID must be set.")
|
|
45
|
+
print("Configure your .env file or set environment variables.")
|
|
46
|
+
sys.exit(1)
|
|
47
|
+
|
|
48
|
+
payload = {
|
|
49
|
+
"messaging_product": "whatsapp",
|
|
50
|
+
"to": to,
|
|
51
|
+
"type": "text",
|
|
52
|
+
"text": {"body": message},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
print(f"Sending message to: {to}")
|
|
56
|
+
print(f"Message: {message}")
|
|
57
|
+
print()
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
response = httpx.post(
|
|
61
|
+
f"{GRAPH_API}/{phone_id}/messages",
|
|
62
|
+
json=payload,
|
|
63
|
+
headers={
|
|
64
|
+
"Authorization": f"Bearer {token}",
|
|
65
|
+
"Content-Type": "application/json",
|
|
66
|
+
},
|
|
67
|
+
timeout=30.0,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
data = response.json()
|
|
71
|
+
|
|
72
|
+
if response.status_code == 200:
|
|
73
|
+
msg_id = data.get("messages", [{}])[0].get("id", "N/A")
|
|
74
|
+
print("Message sent successfully!")
|
|
75
|
+
print(f" Message ID: {msg_id}")
|
|
76
|
+
print(f" Status: 200 OK")
|
|
77
|
+
else:
|
|
78
|
+
error = data.get("error", {})
|
|
79
|
+
print(f"Error sending message:")
|
|
80
|
+
print(f" Code: {error.get('code', '?')}")
|
|
81
|
+
print(f" Message: {error.get('message', 'Unknown error')}")
|
|
82
|
+
if error.get("error_data"):
|
|
83
|
+
print(f" Details: {error['error_data'].get('details', '')}")
|
|
84
|
+
|
|
85
|
+
print()
|
|
86
|
+
print("Full response:")
|
|
87
|
+
# Mask token in response output to prevent credential leakage
|
|
88
|
+
response_str = json.dumps(data, indent=2)
|
|
89
|
+
if token and token in response_str:
|
|
90
|
+
response_str = response_str.replace(token, _mask_secret(token))
|
|
91
|
+
print(response_str)
|
|
92
|
+
|
|
93
|
+
except httpx.ConnectError:
|
|
94
|
+
print("Error: Connection failed. Check your internet connection.")
|
|
95
|
+
sys.exit(1)
|
|
96
|
+
except httpx.TimeoutException:
|
|
97
|
+
print("Error: Request timed out.")
|
|
98
|
+
sys.exit(1)
|
|
99
|
+
except Exception as e:
|
|
100
|
+
# Mask token in error output to prevent credential leakage
|
|
101
|
+
safe_err = str(e).replace(token, _mask_secret(token)) if token else str(e)
|
|
102
|
+
print(f"Error: {safe_err}")
|
|
103
|
+
sys.exit(1)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def main():
|
|
107
|
+
parser = argparse.ArgumentParser(description="Send a test WhatsApp message")
|
|
108
|
+
parser.add_argument(
|
|
109
|
+
"--to",
|
|
110
|
+
required=True,
|
|
111
|
+
help="Recipient phone number with country code (e.g., 5511999999999)",
|
|
112
|
+
)
|
|
113
|
+
parser.add_argument(
|
|
114
|
+
"--message",
|
|
115
|
+
default="Teste de integracao WhatsApp Cloud API - Mensagem enviada com sucesso!",
|
|
116
|
+
help="Message text to send",
|
|
117
|
+
)
|
|
118
|
+
parser.add_argument(
|
|
119
|
+
"--env-file",
|
|
120
|
+
default=".env",
|
|
121
|
+
help="Path to .env file (default: .env)",
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
args = parser.parse_args()
|
|
125
|
+
|
|
126
|
+
# Load environment
|
|
127
|
+
if load_dotenv:
|
|
128
|
+
for env_path in [args.env_file, os.path.join(os.getcwd(), ".env")]:
|
|
129
|
+
if os.path.exists(env_path):
|
|
130
|
+
load_dotenv(env_path)
|
|
131
|
+
break
|
|
132
|
+
|
|
133
|
+
send_test(args.to, args.message)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
if __name__ == "__main__":
|
|
137
|
+
main()
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Setup a new WhatsApp Cloud API project with boilerplate code.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python setup_project.py --language nodejs --path ./my-whatsapp-project
|
|
7
|
+
python setup_project.py --language python --path ./my-whatsapp-project
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import os
|
|
12
|
+
import shutil
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_skill_dir() -> str:
|
|
17
|
+
"""Get the skill directory (parent of scripts/)."""
|
|
18
|
+
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def setup_project(language: str, path: str, name: str | None = None) -> None:
|
|
22
|
+
"""Copy boilerplate and configure a new WhatsApp project."""
|
|
23
|
+
skill_dir = get_skill_dir()
|
|
24
|
+
boilerplate_dir = os.path.join(skill_dir, "assets", "boilerplate", language)
|
|
25
|
+
|
|
26
|
+
if not os.path.exists(boilerplate_dir):
|
|
27
|
+
print(f"Error: Boilerplate not found for language '{language}'")
|
|
28
|
+
print(f"Available: nodejs, python")
|
|
29
|
+
sys.exit(1)
|
|
30
|
+
|
|
31
|
+
target_path = os.path.abspath(path)
|
|
32
|
+
|
|
33
|
+
if os.path.exists(target_path) and os.listdir(target_path):
|
|
34
|
+
print(f"Warning: Directory '{target_path}' already exists and is not empty.")
|
|
35
|
+
response = input("Continue and overwrite? (y/N): ").strip().lower()
|
|
36
|
+
if response != "y":
|
|
37
|
+
print("Aborted.")
|
|
38
|
+
sys.exit(0)
|
|
39
|
+
|
|
40
|
+
# Copy boilerplate
|
|
41
|
+
print(f"Creating {language} project at: {target_path}")
|
|
42
|
+
shutil.copytree(boilerplate_dir, target_path, dirs_exist_ok=True)
|
|
43
|
+
|
|
44
|
+
# Rename .env.example to .env
|
|
45
|
+
env_example = os.path.join(target_path, ".env.example")
|
|
46
|
+
env_file = os.path.join(target_path, ".env")
|
|
47
|
+
if os.path.exists(env_example) and not os.path.exists(env_file):
|
|
48
|
+
shutil.copy2(env_example, env_file)
|
|
49
|
+
print("Created .env from .env.example")
|
|
50
|
+
|
|
51
|
+
# Update project name if provided
|
|
52
|
+
if name and language == "nodejs":
|
|
53
|
+
package_json = os.path.join(target_path, "package.json")
|
|
54
|
+
if os.path.exists(package_json):
|
|
55
|
+
with open(package_json, "r") as f:
|
|
56
|
+
content = f.read()
|
|
57
|
+
content = content.replace('"whatsapp-cloud-api"', f'"{name}"')
|
|
58
|
+
with open(package_json, "w") as f:
|
|
59
|
+
f.write(content)
|
|
60
|
+
|
|
61
|
+
print()
|
|
62
|
+
print("=" * 50)
|
|
63
|
+
print("Project created successfully!")
|
|
64
|
+
print("=" * 50)
|
|
65
|
+
print()
|
|
66
|
+
print("Next steps:")
|
|
67
|
+
print()
|
|
68
|
+
|
|
69
|
+
if language == "nodejs":
|
|
70
|
+
print(f" 1. cd {target_path}")
|
|
71
|
+
print(" 2. npm install")
|
|
72
|
+
print(" 3. Edit .env with your WhatsApp API credentials")
|
|
73
|
+
print(" 4. npm run dev")
|
|
74
|
+
print()
|
|
75
|
+
print("For production:")
|
|
76
|
+
print(" npm run build && npm start")
|
|
77
|
+
else:
|
|
78
|
+
print(f" 1. cd {target_path}")
|
|
79
|
+
print(" 2. pip install -r requirements.txt")
|
|
80
|
+
print(" 3. Edit .env with your WhatsApp API credentials")
|
|
81
|
+
print(" 4. python app.py")
|
|
82
|
+
print()
|
|
83
|
+
print("For production:")
|
|
84
|
+
print(" gunicorn -w 4 -b 0.0.0.0:3000 app:app")
|
|
85
|
+
|
|
86
|
+
print()
|
|
87
|
+
print("For local development with webhooks:")
|
|
88
|
+
print(" ngrok http 3000")
|
|
89
|
+
print(" Then configure the ngrok URL in Meta Developers > WhatsApp > Configuration")
|
|
90
|
+
print()
|
|
91
|
+
print("Need help with setup? Read: references/setup-guide.md")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def main():
|
|
95
|
+
parser = argparse.ArgumentParser(description="Setup a new WhatsApp Cloud API project")
|
|
96
|
+
parser.add_argument(
|
|
97
|
+
"--language",
|
|
98
|
+
choices=["nodejs", "python"],
|
|
99
|
+
required=True,
|
|
100
|
+
help="Project language (nodejs or python)",
|
|
101
|
+
)
|
|
102
|
+
parser.add_argument(
|
|
103
|
+
"--path",
|
|
104
|
+
required=True,
|
|
105
|
+
help="Path where the project will be created",
|
|
106
|
+
)
|
|
107
|
+
parser.add_argument(
|
|
108
|
+
"--name",
|
|
109
|
+
default=None,
|
|
110
|
+
help="Project name (optional, used in package.json for nodejs)",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
args = parser.parse_args()
|
|
114
|
+
setup_project(args.language, args.path, args.name)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if __name__ == "__main__":
|
|
118
|
+
main()
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Validate WhatsApp Cloud API configuration.
|
|
4
|
+
|
|
5
|
+
Checks environment variables and tests API connectivity.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
python validate_config.py
|
|
9
|
+
python validate_config.py --env-file /path/to/.env
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
import httpx
|
|
18
|
+
except ImportError:
|
|
19
|
+
print("Error: httpx not installed. Run: pip install httpx")
|
|
20
|
+
sys.exit(1)
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
from dotenv import load_dotenv
|
|
24
|
+
except ImportError:
|
|
25
|
+
print("Warning: python-dotenv not installed. Using system environment only.")
|
|
26
|
+
load_dotenv = None
|
|
27
|
+
|
|
28
|
+
GRAPH_API = "https://graph.facebook.com/v21.0"
|
|
29
|
+
|
|
30
|
+
REQUIRED_VARS = [
|
|
31
|
+
("WHATSAPP_TOKEN", "Access token for WhatsApp Cloud API"),
|
|
32
|
+
("PHONE_NUMBER_ID", "Phone Number ID from API Setup"),
|
|
33
|
+
("WABA_ID", "WhatsApp Business Account ID"),
|
|
34
|
+
("APP_SECRET", "App Secret from App Settings > Basic"),
|
|
35
|
+
("VERIFY_TOKEN", "Custom token for webhook verification"),
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def check_env_vars() -> tuple[bool, list[str]]:
|
|
40
|
+
"""Check if all required environment variables are set."""
|
|
41
|
+
missing = []
|
|
42
|
+
for var_name, description in REQUIRED_VARS:
|
|
43
|
+
value = os.environ.get(var_name)
|
|
44
|
+
if not value or value.startswith("your_"):
|
|
45
|
+
missing.append(f" {var_name} - {description}")
|
|
46
|
+
|
|
47
|
+
return len(missing) == 0, missing
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _mask_secret(value: str) -> str:
|
|
51
|
+
"""Return a masked version of a secret for safe logging."""
|
|
52
|
+
if not value or len(value) < 8:
|
|
53
|
+
return "***masked***"
|
|
54
|
+
return f"{value[:6]}...masked"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_api_connection() -> tuple[bool, str]:
|
|
58
|
+
"""Test connection to WhatsApp Cloud API."""
|
|
59
|
+
token = os.environ.get("WHATSAPP_TOKEN", "")
|
|
60
|
+
phone_id = os.environ.get("PHONE_NUMBER_ID", "")
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
response = httpx.get(
|
|
64
|
+
f"{GRAPH_API}/{phone_id}",
|
|
65
|
+
params={"fields": "verified_name,code_verification_status,display_phone_number,quality_rating"},
|
|
66
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
67
|
+
timeout=10.0,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
if response.status_code == 200:
|
|
71
|
+
data = response.json()
|
|
72
|
+
return True, (
|
|
73
|
+
f"Phone: {data.get('display_phone_number', 'N/A')}\n"
|
|
74
|
+
f" Name: {data.get('verified_name', 'N/A')}\n"
|
|
75
|
+
f" Status: {data.get('code_verification_status', 'N/A')}\n"
|
|
76
|
+
f" Quality: {data.get('quality_rating', 'N/A')}"
|
|
77
|
+
)
|
|
78
|
+
else:
|
|
79
|
+
error = response.json().get("error", {})
|
|
80
|
+
return False, f"API Error {error.get('code', '?')}: {error.get('message', 'Unknown')}"
|
|
81
|
+
|
|
82
|
+
except httpx.ConnectError:
|
|
83
|
+
return False, "Connection failed. Check your internet connection."
|
|
84
|
+
except httpx.TimeoutException:
|
|
85
|
+
return False, "Request timed out after 10 seconds."
|
|
86
|
+
except Exception as e:
|
|
87
|
+
# Mask token in error output to prevent credential leakage
|
|
88
|
+
safe_err = str(e).replace(token, _mask_secret(token)) if token else str(e)
|
|
89
|
+
return False, f"Unexpected error: {safe_err}"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_waba_access() -> tuple[bool, str]:
|
|
93
|
+
"""Test access to WhatsApp Business Account."""
|
|
94
|
+
token = os.environ.get("WHATSAPP_TOKEN", "")
|
|
95
|
+
waba_id = os.environ.get("WABA_ID", "")
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
response = httpx.get(
|
|
99
|
+
f"{GRAPH_API}/{waba_id}/phone_numbers",
|
|
100
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
101
|
+
timeout=10.0,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if response.status_code == 200:
|
|
105
|
+
data = response.json()
|
|
106
|
+
count = len(data.get("data", []))
|
|
107
|
+
return True, f"WABA accessible. {count} phone number(s) found."
|
|
108
|
+
else:
|
|
109
|
+
error = response.json().get("error", {})
|
|
110
|
+
return False, f"API Error {error.get('code', '?')}: {error.get('message', 'Unknown')}"
|
|
111
|
+
|
|
112
|
+
except Exception as e:
|
|
113
|
+
# Mask token in error output to prevent credential leakage
|
|
114
|
+
safe_err = str(e).replace(token, _mask_secret(token)) if token else str(e)
|
|
115
|
+
return False, f"Error: {safe_err}"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def main():
|
|
119
|
+
parser = argparse.ArgumentParser(description="Validate WhatsApp Cloud API configuration")
|
|
120
|
+
parser.add_argument("--env-file", default=".env", help="Path to .env file (default: .env)")
|
|
121
|
+
args = parser.parse_args()
|
|
122
|
+
|
|
123
|
+
# Load environment
|
|
124
|
+
if load_dotenv and os.path.exists(args.env_file):
|
|
125
|
+
load_dotenv(args.env_file)
|
|
126
|
+
print(f"Loaded: {args.env_file}")
|
|
127
|
+
elif not os.path.exists(args.env_file):
|
|
128
|
+
print(f"Warning: {args.env_file} not found. Using system environment.")
|
|
129
|
+
|
|
130
|
+
print()
|
|
131
|
+
print("=" * 50)
|
|
132
|
+
print("WhatsApp Cloud API - Configuration Validator")
|
|
133
|
+
print("=" * 50)
|
|
134
|
+
print()
|
|
135
|
+
|
|
136
|
+
all_ok = True
|
|
137
|
+
|
|
138
|
+
# Check 1: Environment variables
|
|
139
|
+
print("[1/3] Checking environment variables...")
|
|
140
|
+
env_ok, missing = check_env_vars()
|
|
141
|
+
if env_ok:
|
|
142
|
+
print(" OK - All required variables are set")
|
|
143
|
+
else:
|
|
144
|
+
print(" FAIL - Missing variables:")
|
|
145
|
+
for m in missing:
|
|
146
|
+
print(f" {m}")
|
|
147
|
+
all_ok = False
|
|
148
|
+
|
|
149
|
+
print()
|
|
150
|
+
|
|
151
|
+
if not env_ok:
|
|
152
|
+
print("Cannot test API without required variables. Fix the above and retry.")
|
|
153
|
+
sys.exit(1)
|
|
154
|
+
|
|
155
|
+
# Check 2: API connection
|
|
156
|
+
print("[2/3] Testing API connection (Phone Number)...")
|
|
157
|
+
api_ok, api_msg = test_api_connection()
|
|
158
|
+
if api_ok:
|
|
159
|
+
print(f" OK - Connected successfully")
|
|
160
|
+
print(f" {api_msg}")
|
|
161
|
+
else:
|
|
162
|
+
print(f" FAIL - {api_msg}")
|
|
163
|
+
all_ok = False
|
|
164
|
+
|
|
165
|
+
print()
|
|
166
|
+
|
|
167
|
+
# Check 3: WABA access
|
|
168
|
+
print("[3/3] Testing WABA access...")
|
|
169
|
+
waba_ok, waba_msg = test_waba_access()
|
|
170
|
+
if waba_ok:
|
|
171
|
+
print(f" OK - {waba_msg}")
|
|
172
|
+
else:
|
|
173
|
+
print(f" FAIL - {waba_msg}")
|
|
174
|
+
all_ok = False
|
|
175
|
+
|
|
176
|
+
print()
|
|
177
|
+
print("=" * 50)
|
|
178
|
+
if all_ok:
|
|
179
|
+
print("All checks passed! Your configuration is valid.")
|
|
180
|
+
print("You can start sending messages.")
|
|
181
|
+
else:
|
|
182
|
+
print("Some checks failed. Please fix the issues above.")
|
|
183
|
+
print("Need help? Read: references/setup-guide.md")
|
|
184
|
+
print("=" * 50)
|
|
185
|
+
|
|
186
|
+
sys.exit(0 if all_ok else 1)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
if __name__ == "__main__":
|
|
190
|
+
main()
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Extract YouTube video transcript
|
|
4
|
+
Usage: ./extract-transcript.py VIDEO_ID [LANGUAGE_CODE]
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
from youtube_transcript_api import YouTubeTranscriptApi, TranscriptsDisabled, NoTranscriptFound
|
|
9
|
+
|
|
10
|
+
def extract_transcript(video_id, language='en'):
|
|
11
|
+
"""Extract transcript from YouTube video"""
|
|
12
|
+
try:
|
|
13
|
+
# Try to get transcript in specified language with fallback to English
|
|
14
|
+
transcript = YouTubeTranscriptApi.get_transcript(
|
|
15
|
+
video_id,
|
|
16
|
+
languages=[language, 'en']
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Combine all transcript segments
|
|
20
|
+
full_text = " ".join([entry['text'] for entry in transcript])
|
|
21
|
+
return full_text
|
|
22
|
+
|
|
23
|
+
except TranscriptsDisabled:
|
|
24
|
+
print(f"❌ Transcripts are disabled for video {video_id}", file=sys.stderr)
|
|
25
|
+
sys.exit(1)
|
|
26
|
+
except NoTranscriptFound:
|
|
27
|
+
print(f"❌ No transcript found for video {video_id}", file=sys.stderr)
|
|
28
|
+
sys.exit(1)
|
|
29
|
+
except Exception as e:
|
|
30
|
+
print(f"❌ Error: {e}", file=sys.stderr)
|
|
31
|
+
sys.exit(1)
|
|
32
|
+
|
|
33
|
+
def list_available_transcripts(video_id):
|
|
34
|
+
"""List all available transcripts for a video"""
|
|
35
|
+
try:
|
|
36
|
+
transcript_list = YouTubeTranscriptApi.list_transcripts(video_id)
|
|
37
|
+
print(f"✅ Available transcripts for {video_id}:")
|
|
38
|
+
|
|
39
|
+
for transcript in transcript_list:
|
|
40
|
+
generated = "[Auto-generated]" if transcript.is_generated else "[Manual]"
|
|
41
|
+
translatable = "(translatable)" if transcript.is_translatable else ""
|
|
42
|
+
print(f" - {transcript.language} ({transcript.language_code}) {generated} {translatable}")
|
|
43
|
+
|
|
44
|
+
return True
|
|
45
|
+
except Exception as e:
|
|
46
|
+
print(f"❌ Error listing transcripts: {e}", file=sys.stderr)
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
if len(sys.argv) < 2:
|
|
51
|
+
print("Usage: ./extract-transcript.py VIDEO_ID [LANGUAGE_CODE]")
|
|
52
|
+
print(" ./extract-transcript.py VIDEO_ID --list (list available transcripts)")
|
|
53
|
+
sys.exit(1)
|
|
54
|
+
|
|
55
|
+
video_id = sys.argv[1]
|
|
56
|
+
|
|
57
|
+
# Check if user wants to list available transcripts
|
|
58
|
+
if len(sys.argv) > 2 and sys.argv[2] == "--list":
|
|
59
|
+
success = list_available_transcripts(video_id)
|
|
60
|
+
sys.exit(0 if success else 1)
|
|
61
|
+
|
|
62
|
+
# Extract transcript
|
|
63
|
+
language = sys.argv[2] if len(sys.argv) > 2 else 'en'
|
|
64
|
+
transcript = extract_transcript(video_id, language)
|
|
65
|
+
print(transcript)
|