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,204 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Environment Setup for NotebookLM Skill
|
|
4
|
+
Manages virtual environment and dependencies automatically
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
import subprocess
|
|
10
|
+
import venv
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SkillEnvironment:
|
|
15
|
+
"""Manages skill-specific virtual environment"""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
# Skill directory paths
|
|
19
|
+
self.skill_dir = Path(__file__).parent.parent
|
|
20
|
+
self.venv_dir = self.skill_dir / ".venv"
|
|
21
|
+
self.requirements_file = self.skill_dir / "requirements.txt"
|
|
22
|
+
|
|
23
|
+
# Python executable in venv
|
|
24
|
+
if os.name == 'nt': # Windows
|
|
25
|
+
self.venv_python = self.venv_dir / "Scripts" / "python.exe"
|
|
26
|
+
self.venv_pip = self.venv_dir / "Scripts" / "pip.exe"
|
|
27
|
+
else: # Unix/Linux/Mac
|
|
28
|
+
self.venv_python = self.venv_dir / "bin" / "python"
|
|
29
|
+
self.venv_pip = self.venv_dir / "bin" / "pip"
|
|
30
|
+
|
|
31
|
+
def ensure_venv(self) -> bool:
|
|
32
|
+
"""Ensure virtual environment exists and is set up"""
|
|
33
|
+
|
|
34
|
+
# Check if we're already in the correct venv
|
|
35
|
+
if self.is_in_skill_venv():
|
|
36
|
+
print("✅ Already running in skill virtual environment")
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
# Create venv if it doesn't exist
|
|
40
|
+
if not self.venv_dir.exists():
|
|
41
|
+
print(f"🔧 Creating virtual environment in {self.venv_dir.name}/")
|
|
42
|
+
try:
|
|
43
|
+
venv.create(self.venv_dir, with_pip=True)
|
|
44
|
+
print("✅ Virtual environment created")
|
|
45
|
+
except Exception as e:
|
|
46
|
+
print(f"❌ Failed to create venv: {e}")
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
# Install/update dependencies
|
|
50
|
+
if self.requirements_file.exists():
|
|
51
|
+
print("📦 Installing dependencies...")
|
|
52
|
+
try:
|
|
53
|
+
# Upgrade pip first
|
|
54
|
+
subprocess.run(
|
|
55
|
+
[str(self.venv_pip), "install", "--upgrade", "pip"],
|
|
56
|
+
check=True,
|
|
57
|
+
capture_output=True,
|
|
58
|
+
text=True
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Install requirements
|
|
62
|
+
result = subprocess.run(
|
|
63
|
+
[str(self.venv_pip), "install", "-r", str(self.requirements_file)],
|
|
64
|
+
check=True,
|
|
65
|
+
capture_output=True,
|
|
66
|
+
text=True
|
|
67
|
+
)
|
|
68
|
+
print("✅ Dependencies installed")
|
|
69
|
+
|
|
70
|
+
# Install Chrome for Patchright (not Chromium!)
|
|
71
|
+
# Using real Chrome ensures cross-platform reliability and consistent browser fingerprinting
|
|
72
|
+
# See: https://github.com/Kaliiiiiiiiii-Vinyzu/patchright-python#anti-detection
|
|
73
|
+
print("🌐 Installing Google Chrome for Patchright...")
|
|
74
|
+
try:
|
|
75
|
+
subprocess.run(
|
|
76
|
+
[str(self.venv_python), "-m", "patchright", "install", "chrome"],
|
|
77
|
+
check=True,
|
|
78
|
+
capture_output=True,
|
|
79
|
+
text=True
|
|
80
|
+
)
|
|
81
|
+
print("✅ Chrome installed")
|
|
82
|
+
except subprocess.CalledProcessError as e:
|
|
83
|
+
print(f"⚠️ Warning: Failed to install Chrome: {e}")
|
|
84
|
+
print(" You may need to run manually: python -m patchright install chrome")
|
|
85
|
+
print(" Chrome is required (not Chromium) for reliability!")
|
|
86
|
+
|
|
87
|
+
return True
|
|
88
|
+
except subprocess.CalledProcessError as e:
|
|
89
|
+
print(f"❌ Failed to install dependencies: {e}")
|
|
90
|
+
print(f" Output: {e.output if hasattr(e, 'output') else 'No output'}")
|
|
91
|
+
return False
|
|
92
|
+
else:
|
|
93
|
+
print("⚠️ No requirements.txt found, skipping dependency installation")
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
def is_in_skill_venv(self) -> bool:
|
|
97
|
+
"""Check if we're already running in the skill's venv"""
|
|
98
|
+
if hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
|
|
99
|
+
# We're in a venv, check if it's ours
|
|
100
|
+
venv_path = Path(sys.prefix)
|
|
101
|
+
return venv_path == self.venv_dir
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
def get_python_executable(self) -> str:
|
|
105
|
+
"""Get the correct Python executable to use"""
|
|
106
|
+
if self.venv_python.exists():
|
|
107
|
+
return str(self.venv_python)
|
|
108
|
+
return sys.executable
|
|
109
|
+
|
|
110
|
+
def run_script(self, script_name: str, args: list = None) -> int:
|
|
111
|
+
"""Run a script with the virtual environment"""
|
|
112
|
+
script_path = self.skill_dir / "scripts" / script_name
|
|
113
|
+
|
|
114
|
+
if not script_path.exists():
|
|
115
|
+
print(f"❌ Script not found: {script_path}")
|
|
116
|
+
return 1
|
|
117
|
+
|
|
118
|
+
# Ensure venv is set up
|
|
119
|
+
if not self.ensure_venv():
|
|
120
|
+
print("❌ Failed to set up environment")
|
|
121
|
+
return 1
|
|
122
|
+
|
|
123
|
+
# Build command
|
|
124
|
+
cmd = [str(self.venv_python), str(script_path)]
|
|
125
|
+
if args:
|
|
126
|
+
cmd.extend(args)
|
|
127
|
+
|
|
128
|
+
print(f"🚀 Running: {script_name} with venv Python")
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
# Run the script with venv Python
|
|
132
|
+
result = subprocess.run(cmd)
|
|
133
|
+
return result.returncode
|
|
134
|
+
except Exception as e:
|
|
135
|
+
print(f"❌ Failed to run script: {e}")
|
|
136
|
+
return 1
|
|
137
|
+
|
|
138
|
+
def activate_instructions(self) -> str:
|
|
139
|
+
"""Get instructions for manual activation"""
|
|
140
|
+
if os.name == 'nt':
|
|
141
|
+
activate = self.venv_dir / "Scripts" / "activate.bat"
|
|
142
|
+
return f"Run: {activate}"
|
|
143
|
+
else:
|
|
144
|
+
activate = self.venv_dir / "bin" / "activate"
|
|
145
|
+
return f"Run: source {activate}"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def main():
|
|
149
|
+
"""Main entry point for environment setup"""
|
|
150
|
+
import argparse
|
|
151
|
+
|
|
152
|
+
parser = argparse.ArgumentParser(
|
|
153
|
+
description='Setup NotebookLM skill environment'
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
parser.add_argument(
|
|
157
|
+
'--check',
|
|
158
|
+
action='store_true',
|
|
159
|
+
help='Check if environment is set up'
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
parser.add_argument(
|
|
163
|
+
'--run',
|
|
164
|
+
help='Run a script with the venv (e.g., --run ask_question.py)'
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
parser.add_argument(
|
|
168
|
+
'args',
|
|
169
|
+
nargs='*',
|
|
170
|
+
help='Arguments to pass to the script'
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
args = parser.parse_args()
|
|
174
|
+
|
|
175
|
+
env = SkillEnvironment()
|
|
176
|
+
|
|
177
|
+
if args.check:
|
|
178
|
+
if env.venv_dir.exists():
|
|
179
|
+
print(f"✅ Virtual environment exists: {env.venv_dir}")
|
|
180
|
+
print(f" Python: {env.get_python_executable()}")
|
|
181
|
+
print(f" To activate manually: {env.activate_instructions()}")
|
|
182
|
+
else:
|
|
183
|
+
print(f"❌ No virtual environment found")
|
|
184
|
+
print(f" Run setup_environment.py to create it")
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
if args.run:
|
|
188
|
+
# Run a script with venv
|
|
189
|
+
return env.run_script(args.run, args.args)
|
|
190
|
+
|
|
191
|
+
# Default: ensure environment is set up
|
|
192
|
+
if env.ensure_venv():
|
|
193
|
+
print("\n✅ Environment ready!")
|
|
194
|
+
print(f" Virtual env: {env.venv_dir}")
|
|
195
|
+
print(f" Python: {env.get_python_executable()}")
|
|
196
|
+
print(f"\nTo activate manually: {env.activate_instructions()}")
|
|
197
|
+
print(f"Or run scripts directly: python setup_environment.py --run script_name.py")
|
|
198
|
+
else:
|
|
199
|
+
print("\n❌ Environment setup failed")
|
|
200
|
+
return 1
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
if __name__ == "__main__":
|
|
204
|
+
sys.exit(main() or 0)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
import json
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Script to check that the `fields.json` file that Claude creates when analyzing PDFs
|
|
7
|
+
# does not have overlapping bounding boxes. See forms.md.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class RectAndField:
|
|
12
|
+
rect: list[float]
|
|
13
|
+
rect_type: str
|
|
14
|
+
field: dict
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Returns a list of messages that are printed to stdout for Claude to read.
|
|
18
|
+
def get_bounding_box_messages(fields_json_stream) -> list[str]:
|
|
19
|
+
messages = []
|
|
20
|
+
fields = json.load(fields_json_stream)
|
|
21
|
+
messages.append(f"Read {len(fields['form_fields'])} fields")
|
|
22
|
+
|
|
23
|
+
def rects_intersect(r1, r2):
|
|
24
|
+
disjoint_horizontal = r1[0] >= r2[2] or r1[2] <= r2[0]
|
|
25
|
+
disjoint_vertical = r1[1] >= r2[3] or r1[3] <= r2[1]
|
|
26
|
+
return not (disjoint_horizontal or disjoint_vertical)
|
|
27
|
+
|
|
28
|
+
rects_and_fields = []
|
|
29
|
+
for f in fields["form_fields"]:
|
|
30
|
+
rects_and_fields.append(RectAndField(f["label_bounding_box"], "label", f))
|
|
31
|
+
rects_and_fields.append(RectAndField(f["entry_bounding_box"], "entry", f))
|
|
32
|
+
|
|
33
|
+
has_error = False
|
|
34
|
+
for i, ri in enumerate(rects_and_fields):
|
|
35
|
+
# This is O(N^2); we can optimize if it becomes a problem.
|
|
36
|
+
for j in range(i + 1, len(rects_and_fields)):
|
|
37
|
+
rj = rects_and_fields[j]
|
|
38
|
+
if ri.field["page_number"] == rj.field["page_number"] and rects_intersect(ri.rect, rj.rect):
|
|
39
|
+
has_error = True
|
|
40
|
+
if ri.field is rj.field:
|
|
41
|
+
messages.append(f"FAILURE: intersection between label and entry bounding boxes for `{ri.field['description']}` ({ri.rect}, {rj.rect})")
|
|
42
|
+
else:
|
|
43
|
+
messages.append(f"FAILURE: intersection between {ri.rect_type} bounding box for `{ri.field['description']}` ({ri.rect}) and {rj.rect_type} bounding box for `{rj.field['description']}` ({rj.rect})")
|
|
44
|
+
if len(messages) >= 20:
|
|
45
|
+
messages.append("Aborting further checks; fix bounding boxes and try again")
|
|
46
|
+
return messages
|
|
47
|
+
if ri.rect_type == "entry":
|
|
48
|
+
if "entry_text" in ri.field:
|
|
49
|
+
font_size = ri.field["entry_text"].get("font_size", 14)
|
|
50
|
+
entry_height = ri.rect[3] - ri.rect[1]
|
|
51
|
+
if entry_height < font_size:
|
|
52
|
+
has_error = True
|
|
53
|
+
messages.append(f"FAILURE: entry bounding box height ({entry_height}) for `{ri.field['description']}` is too short for the text content (font size: {font_size}). Increase the box height or decrease the font size.")
|
|
54
|
+
if len(messages) >= 20:
|
|
55
|
+
messages.append("Aborting further checks; fix bounding boxes and try again")
|
|
56
|
+
return messages
|
|
57
|
+
|
|
58
|
+
if not has_error:
|
|
59
|
+
messages.append("SUCCESS: All bounding boxes are valid")
|
|
60
|
+
return messages
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
if len(sys.argv) != 2:
|
|
64
|
+
print("Usage: check_bounding_boxes.py [fields.json]")
|
|
65
|
+
sys.exit(1)
|
|
66
|
+
# Input file should be in the `fields.json` format described in forms.md.
|
|
67
|
+
with open(sys.argv[1]) as f:
|
|
68
|
+
messages = get_bounding_box_messages(f)
|
|
69
|
+
for msg in messages:
|
|
70
|
+
print(msg)
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import json
|
|
3
|
+
import io
|
|
4
|
+
from check_bounding_boxes import get_bounding_box_messages
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Currently this is not run automatically in CI; it's just for documentation and manual checking.
|
|
8
|
+
class TestGetBoundingBoxMessages(unittest.TestCase):
|
|
9
|
+
|
|
10
|
+
def create_json_stream(self, data):
|
|
11
|
+
"""Helper to create a JSON stream from data"""
|
|
12
|
+
return io.StringIO(json.dumps(data))
|
|
13
|
+
|
|
14
|
+
def test_no_intersections(self):
|
|
15
|
+
"""Test case with no bounding box intersections"""
|
|
16
|
+
data = {
|
|
17
|
+
"form_fields": [
|
|
18
|
+
{
|
|
19
|
+
"description": "Name",
|
|
20
|
+
"page_number": 1,
|
|
21
|
+
"label_bounding_box": [10, 10, 50, 30],
|
|
22
|
+
"entry_bounding_box": [60, 10, 150, 30]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"description": "Email",
|
|
26
|
+
"page_number": 1,
|
|
27
|
+
"label_bounding_box": [10, 40, 50, 60],
|
|
28
|
+
"entry_bounding_box": [60, 40, 150, 60]
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
stream = self.create_json_stream(data)
|
|
34
|
+
messages = get_bounding_box_messages(stream)
|
|
35
|
+
self.assertTrue(any("SUCCESS" in msg for msg in messages))
|
|
36
|
+
self.assertFalse(any("FAILURE" in msg for msg in messages))
|
|
37
|
+
|
|
38
|
+
def test_label_entry_intersection_same_field(self):
|
|
39
|
+
"""Test intersection between label and entry of the same field"""
|
|
40
|
+
data = {
|
|
41
|
+
"form_fields": [
|
|
42
|
+
{
|
|
43
|
+
"description": "Name",
|
|
44
|
+
"page_number": 1,
|
|
45
|
+
"label_bounding_box": [10, 10, 60, 30],
|
|
46
|
+
"entry_bounding_box": [50, 10, 150, 30] # Overlaps with label
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
stream = self.create_json_stream(data)
|
|
52
|
+
messages = get_bounding_box_messages(stream)
|
|
53
|
+
self.assertTrue(any("FAILURE" in msg and "intersection" in msg for msg in messages))
|
|
54
|
+
self.assertFalse(any("SUCCESS" in msg for msg in messages))
|
|
55
|
+
|
|
56
|
+
def test_intersection_between_different_fields(self):
|
|
57
|
+
"""Test intersection between bounding boxes of different fields"""
|
|
58
|
+
data = {
|
|
59
|
+
"form_fields": [
|
|
60
|
+
{
|
|
61
|
+
"description": "Name",
|
|
62
|
+
"page_number": 1,
|
|
63
|
+
"label_bounding_box": [10, 10, 50, 30],
|
|
64
|
+
"entry_bounding_box": [60, 10, 150, 30]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"description": "Email",
|
|
68
|
+
"page_number": 1,
|
|
69
|
+
"label_bounding_box": [40, 20, 80, 40], # Overlaps with Name's boxes
|
|
70
|
+
"entry_bounding_box": [160, 10, 250, 30]
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
stream = self.create_json_stream(data)
|
|
76
|
+
messages = get_bounding_box_messages(stream)
|
|
77
|
+
self.assertTrue(any("FAILURE" in msg and "intersection" in msg for msg in messages))
|
|
78
|
+
self.assertFalse(any("SUCCESS" in msg for msg in messages))
|
|
79
|
+
|
|
80
|
+
def test_different_pages_no_intersection(self):
|
|
81
|
+
"""Test that boxes on different pages don't count as intersecting"""
|
|
82
|
+
data = {
|
|
83
|
+
"form_fields": [
|
|
84
|
+
{
|
|
85
|
+
"description": "Name",
|
|
86
|
+
"page_number": 1,
|
|
87
|
+
"label_bounding_box": [10, 10, 50, 30],
|
|
88
|
+
"entry_bounding_box": [60, 10, 150, 30]
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"description": "Email",
|
|
92
|
+
"page_number": 2,
|
|
93
|
+
"label_bounding_box": [10, 10, 50, 30], # Same coordinates but different page
|
|
94
|
+
"entry_bounding_box": [60, 10, 150, 30]
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
stream = self.create_json_stream(data)
|
|
100
|
+
messages = get_bounding_box_messages(stream)
|
|
101
|
+
self.assertTrue(any("SUCCESS" in msg for msg in messages))
|
|
102
|
+
self.assertFalse(any("FAILURE" in msg for msg in messages))
|
|
103
|
+
|
|
104
|
+
def test_entry_height_too_small(self):
|
|
105
|
+
"""Test that entry box height is checked against font size"""
|
|
106
|
+
data = {
|
|
107
|
+
"form_fields": [
|
|
108
|
+
{
|
|
109
|
+
"description": "Name",
|
|
110
|
+
"page_number": 1,
|
|
111
|
+
"label_bounding_box": [10, 10, 50, 30],
|
|
112
|
+
"entry_bounding_box": [60, 10, 150, 20], # Height is 10
|
|
113
|
+
"entry_text": {
|
|
114
|
+
"font_size": 14 # Font size larger than height
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
stream = self.create_json_stream(data)
|
|
121
|
+
messages = get_bounding_box_messages(stream)
|
|
122
|
+
self.assertTrue(any("FAILURE" in msg and "height" in msg for msg in messages))
|
|
123
|
+
self.assertFalse(any("SUCCESS" in msg for msg in messages))
|
|
124
|
+
|
|
125
|
+
def test_entry_height_adequate(self):
|
|
126
|
+
"""Test that adequate entry box height passes"""
|
|
127
|
+
data = {
|
|
128
|
+
"form_fields": [
|
|
129
|
+
{
|
|
130
|
+
"description": "Name",
|
|
131
|
+
"page_number": 1,
|
|
132
|
+
"label_bounding_box": [10, 10, 50, 30],
|
|
133
|
+
"entry_bounding_box": [60, 10, 150, 30], # Height is 20
|
|
134
|
+
"entry_text": {
|
|
135
|
+
"font_size": 14 # Font size smaller than height
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
stream = self.create_json_stream(data)
|
|
142
|
+
messages = get_bounding_box_messages(stream)
|
|
143
|
+
self.assertTrue(any("SUCCESS" in msg for msg in messages))
|
|
144
|
+
self.assertFalse(any("FAILURE" in msg for msg in messages))
|
|
145
|
+
|
|
146
|
+
def test_default_font_size(self):
|
|
147
|
+
"""Test that default font size is used when not specified"""
|
|
148
|
+
data = {
|
|
149
|
+
"form_fields": [
|
|
150
|
+
{
|
|
151
|
+
"description": "Name",
|
|
152
|
+
"page_number": 1,
|
|
153
|
+
"label_bounding_box": [10, 10, 50, 30],
|
|
154
|
+
"entry_bounding_box": [60, 10, 150, 20], # Height is 10
|
|
155
|
+
"entry_text": {} # No font_size specified, should use default 14
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
stream = self.create_json_stream(data)
|
|
161
|
+
messages = get_bounding_box_messages(stream)
|
|
162
|
+
self.assertTrue(any("FAILURE" in msg and "height" in msg for msg in messages))
|
|
163
|
+
self.assertFalse(any("SUCCESS" in msg for msg in messages))
|
|
164
|
+
|
|
165
|
+
def test_no_entry_text(self):
|
|
166
|
+
"""Test that missing entry_text doesn't cause height check"""
|
|
167
|
+
data = {
|
|
168
|
+
"form_fields": [
|
|
169
|
+
{
|
|
170
|
+
"description": "Name",
|
|
171
|
+
"page_number": 1,
|
|
172
|
+
"label_bounding_box": [10, 10, 50, 30],
|
|
173
|
+
"entry_bounding_box": [60, 10, 150, 20] # Small height but no entry_text
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
stream = self.create_json_stream(data)
|
|
179
|
+
messages = get_bounding_box_messages(stream)
|
|
180
|
+
self.assertTrue(any("SUCCESS" in msg for msg in messages))
|
|
181
|
+
self.assertFalse(any("FAILURE" in msg for msg in messages))
|
|
182
|
+
|
|
183
|
+
def test_multiple_errors_limit(self):
|
|
184
|
+
"""Test that error messages are limited to prevent excessive output"""
|
|
185
|
+
fields = []
|
|
186
|
+
# Create many overlapping fields
|
|
187
|
+
for i in range(25):
|
|
188
|
+
fields.append({
|
|
189
|
+
"description": f"Field{i}",
|
|
190
|
+
"page_number": 1,
|
|
191
|
+
"label_bounding_box": [10, 10, 50, 30], # All overlap
|
|
192
|
+
"entry_bounding_box": [20, 15, 60, 35] # All overlap
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
data = {"form_fields": fields}
|
|
196
|
+
|
|
197
|
+
stream = self.create_json_stream(data)
|
|
198
|
+
messages = get_bounding_box_messages(stream)
|
|
199
|
+
# Should abort after ~20 messages
|
|
200
|
+
self.assertTrue(any("Aborting" in msg for msg in messages))
|
|
201
|
+
# Should have some FAILURE messages but not hundreds
|
|
202
|
+
failure_count = sum(1 for msg in messages if "FAILURE" in msg)
|
|
203
|
+
self.assertGreater(failure_count, 0)
|
|
204
|
+
self.assertLess(len(messages), 30) # Should be limited
|
|
205
|
+
|
|
206
|
+
def test_edge_touching_boxes(self):
|
|
207
|
+
"""Test that boxes touching at edges don't count as intersecting"""
|
|
208
|
+
data = {
|
|
209
|
+
"form_fields": [
|
|
210
|
+
{
|
|
211
|
+
"description": "Name",
|
|
212
|
+
"page_number": 1,
|
|
213
|
+
"label_bounding_box": [10, 10, 50, 30],
|
|
214
|
+
"entry_bounding_box": [50, 10, 150, 30] # Touches at x=50
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
stream = self.create_json_stream(data)
|
|
220
|
+
messages = get_bounding_box_messages(stream)
|
|
221
|
+
self.assertTrue(any("SUCCESS" in msg for msg in messages))
|
|
222
|
+
self.assertFalse(any("FAILURE" in msg for msg in messages))
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
if __name__ == '__main__':
|
|
226
|
+
unittest.main()
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pypdf import PdfReader
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# Script for Claude to run to determine whether a PDF has fillable form fields. See forms.md.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
reader = PdfReader(sys.argv[1])
|
|
9
|
+
if (reader.get_fields()):
|
|
10
|
+
print("This PDF has fillable form fields")
|
|
11
|
+
else:
|
|
12
|
+
print("This PDF does not have fillable form fields; you will need to visually determine where to enter data")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from pdf2image import convert_from_path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Converts each page of a PDF to a PNG image.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def convert(pdf_path, output_dir, max_dim=1000):
|
|
11
|
+
images = convert_from_path(pdf_path, dpi=200)
|
|
12
|
+
|
|
13
|
+
for i, image in enumerate(images):
|
|
14
|
+
# Scale image if needed to keep width/height under `max_dim`
|
|
15
|
+
width, height = image.size
|
|
16
|
+
if width > max_dim or height > max_dim:
|
|
17
|
+
scale_factor = min(max_dim / width, max_dim / height)
|
|
18
|
+
new_width = int(width * scale_factor)
|
|
19
|
+
new_height = int(height * scale_factor)
|
|
20
|
+
image = image.resize((new_width, new_height))
|
|
21
|
+
|
|
22
|
+
image_path = os.path.join(output_dir, f"page_{i+1}.png")
|
|
23
|
+
image.save(image_path)
|
|
24
|
+
print(f"Saved page {i+1} as {image_path} (size: {image.size})")
|
|
25
|
+
|
|
26
|
+
print(f"Converted {len(images)} pages to PNG images")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
if len(sys.argv) != 3:
|
|
31
|
+
print("Usage: convert_pdf_to_images.py [input pdf] [output directory]")
|
|
32
|
+
sys.exit(1)
|
|
33
|
+
pdf_path = sys.argv[1]
|
|
34
|
+
output_directory = sys.argv[2]
|
|
35
|
+
convert(pdf_path, output_directory)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from PIL import Image, ImageDraw
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Creates "validation" images with rectangles for the bounding box information that
|
|
8
|
+
# Claude creates when determining where to add text annotations in PDFs. See forms.md.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def create_validation_image(page_number, fields_json_path, input_path, output_path):
|
|
12
|
+
# Input file should be in the `fields.json` format described in forms.md.
|
|
13
|
+
with open(fields_json_path, 'r') as f:
|
|
14
|
+
data = json.load(f)
|
|
15
|
+
|
|
16
|
+
img = Image.open(input_path)
|
|
17
|
+
draw = ImageDraw.Draw(img)
|
|
18
|
+
num_boxes = 0
|
|
19
|
+
|
|
20
|
+
for field in data["form_fields"]:
|
|
21
|
+
if field["page_number"] == page_number:
|
|
22
|
+
entry_box = field['entry_bounding_box']
|
|
23
|
+
label_box = field['label_bounding_box']
|
|
24
|
+
# Draw red rectangle over entry bounding box and blue rectangle over the label.
|
|
25
|
+
draw.rectangle(entry_box, outline='red', width=2)
|
|
26
|
+
draw.rectangle(label_box, outline='blue', width=2)
|
|
27
|
+
num_boxes += 2
|
|
28
|
+
|
|
29
|
+
img.save(output_path)
|
|
30
|
+
print(f"Created validation image at {output_path} with {num_boxes} bounding boxes")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
if len(sys.argv) != 5:
|
|
35
|
+
print("Usage: create_validation_image.py [page number] [fields.json file] [input image path] [output image path]")
|
|
36
|
+
sys.exit(1)
|
|
37
|
+
page_number = int(sys.argv[1])
|
|
38
|
+
fields_json_path = sys.argv[2]
|
|
39
|
+
input_image_path = sys.argv[3]
|
|
40
|
+
output_image_path = sys.argv[4]
|
|
41
|
+
create_validation_image(page_number, fields_json_path, input_image_path, output_image_path)
|