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,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)
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from pypdf import PdfReader
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Extracts data for the fillable form fields in a PDF and outputs JSON that
|
|
8
|
+
# Claude uses to fill the fields. See forms.md.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# This matches the format used by PdfReader `get_fields` and `update_page_form_field_values` methods.
|
|
12
|
+
def get_full_annotation_field_id(annotation):
|
|
13
|
+
components = []
|
|
14
|
+
while annotation:
|
|
15
|
+
field_name = annotation.get('/T')
|
|
16
|
+
if field_name:
|
|
17
|
+
components.append(field_name)
|
|
18
|
+
annotation = annotation.get('/Parent')
|
|
19
|
+
return ".".join(reversed(components)) if components else None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def make_field_dict(field, field_id):
|
|
23
|
+
field_dict = {"field_id": field_id}
|
|
24
|
+
ft = field.get('/FT')
|
|
25
|
+
if ft == "/Tx":
|
|
26
|
+
field_dict["type"] = "text"
|
|
27
|
+
elif ft == "/Btn":
|
|
28
|
+
field_dict["type"] = "checkbox" # radio groups handled separately
|
|
29
|
+
states = field.get("/_States_", [])
|
|
30
|
+
if len(states) == 2:
|
|
31
|
+
# "/Off" seems to always be the unchecked value, as suggested by
|
|
32
|
+
# https://opensource.adobe.com/dc-acrobat-sdk-docs/standards/pdfstandards/pdf/PDF32000_2008.pdf#page=448
|
|
33
|
+
# It can be either first or second in the "/_States_" list.
|
|
34
|
+
if "/Off" in states:
|
|
35
|
+
field_dict["checked_value"] = states[0] if states[0] != "/Off" else states[1]
|
|
36
|
+
field_dict["unchecked_value"] = "/Off"
|
|
37
|
+
else:
|
|
38
|
+
print(f"Unexpected state values for checkbox `${field_id}`. Its checked and unchecked values may not be correct; if you're trying to check it, visually verify the results.")
|
|
39
|
+
field_dict["checked_value"] = states[0]
|
|
40
|
+
field_dict["unchecked_value"] = states[1]
|
|
41
|
+
elif ft == "/Ch":
|
|
42
|
+
field_dict["type"] = "choice"
|
|
43
|
+
states = field.get("/_States_", [])
|
|
44
|
+
field_dict["choice_options"] = [{
|
|
45
|
+
"value": state[0],
|
|
46
|
+
"text": state[1],
|
|
47
|
+
} for state in states]
|
|
48
|
+
else:
|
|
49
|
+
field_dict["type"] = f"unknown ({ft})"
|
|
50
|
+
return field_dict
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Returns a list of fillable PDF fields:
|
|
54
|
+
# [
|
|
55
|
+
# {
|
|
56
|
+
# "field_id": "name",
|
|
57
|
+
# "page": 1,
|
|
58
|
+
# "type": ("text", "checkbox", "radio_group", or "choice")
|
|
59
|
+
# // Per-type additional fields described in forms.md
|
|
60
|
+
# },
|
|
61
|
+
# ]
|
|
62
|
+
def get_field_info(reader: PdfReader):
|
|
63
|
+
fields = reader.get_fields()
|
|
64
|
+
|
|
65
|
+
field_info_by_id = {}
|
|
66
|
+
possible_radio_names = set()
|
|
67
|
+
|
|
68
|
+
for field_id, field in fields.items():
|
|
69
|
+
# Skip if this is a container field with children, except that it might be
|
|
70
|
+
# a parent group for radio button options.
|
|
71
|
+
if field.get("/Kids"):
|
|
72
|
+
if field.get("/FT") == "/Btn":
|
|
73
|
+
possible_radio_names.add(field_id)
|
|
74
|
+
continue
|
|
75
|
+
field_info_by_id[field_id] = make_field_dict(field, field_id)
|
|
76
|
+
|
|
77
|
+
# Bounding rects are stored in annotations in page objects.
|
|
78
|
+
|
|
79
|
+
# Radio button options have a separate annotation for each choice;
|
|
80
|
+
# all choices have the same field name.
|
|
81
|
+
# See https://westhealth.github.io/exploring-fillable-forms-with-pdfrw.html
|
|
82
|
+
radio_fields_by_id = {}
|
|
83
|
+
|
|
84
|
+
for page_index, page in enumerate(reader.pages):
|
|
85
|
+
annotations = page.get('/Annots', [])
|
|
86
|
+
for ann in annotations:
|
|
87
|
+
field_id = get_full_annotation_field_id(ann)
|
|
88
|
+
if field_id in field_info_by_id:
|
|
89
|
+
field_info_by_id[field_id]["page"] = page_index + 1
|
|
90
|
+
field_info_by_id[field_id]["rect"] = ann.get('/Rect')
|
|
91
|
+
elif field_id in possible_radio_names:
|
|
92
|
+
try:
|
|
93
|
+
# ann['/AP']['/N'] should have two items. One of them is '/Off',
|
|
94
|
+
# the other is the active value.
|
|
95
|
+
on_values = [v for v in ann["/AP"]["/N"] if v != "/Off"]
|
|
96
|
+
except KeyError:
|
|
97
|
+
continue
|
|
98
|
+
if len(on_values) == 1:
|
|
99
|
+
rect = ann.get("/Rect")
|
|
100
|
+
if field_id not in radio_fields_by_id:
|
|
101
|
+
radio_fields_by_id[field_id] = {
|
|
102
|
+
"field_id": field_id,
|
|
103
|
+
"type": "radio_group",
|
|
104
|
+
"page": page_index + 1,
|
|
105
|
+
"radio_options": [],
|
|
106
|
+
}
|
|
107
|
+
# Note: at least on macOS 15.7, Preview.app doesn't show selected
|
|
108
|
+
# radio buttons correctly. (It does if you remove the leading slash
|
|
109
|
+
# from the value, but that causes them not to appear correctly in
|
|
110
|
+
# Chrome/Firefox/Acrobat/etc).
|
|
111
|
+
radio_fields_by_id[field_id]["radio_options"].append({
|
|
112
|
+
"value": on_values[0],
|
|
113
|
+
"rect": rect,
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
# Some PDFs have form field definitions without corresponding annotations,
|
|
117
|
+
# so we can't tell where they are. Ignore these fields for now.
|
|
118
|
+
fields_with_location = []
|
|
119
|
+
for field_info in field_info_by_id.values():
|
|
120
|
+
if "page" in field_info:
|
|
121
|
+
fields_with_location.append(field_info)
|
|
122
|
+
else:
|
|
123
|
+
print(f"Unable to determine location for field id: {field_info.get('field_id')}, ignoring")
|
|
124
|
+
|
|
125
|
+
# Sort by page number, then Y position (flipped in PDF coordinate system), then X.
|
|
126
|
+
def sort_key(f):
|
|
127
|
+
if "radio_options" in f:
|
|
128
|
+
rect = f["radio_options"][0]["rect"] or [0, 0, 0, 0]
|
|
129
|
+
else:
|
|
130
|
+
rect = f.get("rect") or [0, 0, 0, 0]
|
|
131
|
+
adjusted_position = [-rect[1], rect[0]]
|
|
132
|
+
return [f.get("page"), adjusted_position]
|
|
133
|
+
|
|
134
|
+
sorted_fields = fields_with_location + list(radio_fields_by_id.values())
|
|
135
|
+
sorted_fields.sort(key=sort_key)
|
|
136
|
+
|
|
137
|
+
return sorted_fields
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def write_field_info(pdf_path: str, json_output_path: str):
|
|
141
|
+
reader = PdfReader(pdf_path)
|
|
142
|
+
field_info = get_field_info(reader)
|
|
143
|
+
with open(json_output_path, "w") as f:
|
|
144
|
+
json.dump(field_info, f, indent=2)
|
|
145
|
+
print(f"Wrote {len(field_info)} fields to {json_output_path}")
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
if len(sys.argv) != 3:
|
|
150
|
+
print("Usage: extract_form_field_info.py [input pdf] [output json]")
|
|
151
|
+
sys.exit(1)
|
|
152
|
+
write_field_info(sys.argv[1], sys.argv[2])
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from pypdf import PdfReader, PdfWriter
|
|
5
|
+
|
|
6
|
+
from extract_form_field_info import get_field_info
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Fills fillable form fields in a PDF. See forms.md.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def fill_pdf_fields(input_pdf_path: str, fields_json_path: str, output_pdf_path: str):
|
|
13
|
+
with open(fields_json_path) as f:
|
|
14
|
+
fields = json.load(f)
|
|
15
|
+
# Group by page number.
|
|
16
|
+
fields_by_page = {}
|
|
17
|
+
for field in fields:
|
|
18
|
+
if "value" in field:
|
|
19
|
+
field_id = field["field_id"]
|
|
20
|
+
page = field["page"]
|
|
21
|
+
if page not in fields_by_page:
|
|
22
|
+
fields_by_page[page] = {}
|
|
23
|
+
fields_by_page[page][field_id] = field["value"]
|
|
24
|
+
|
|
25
|
+
reader = PdfReader(input_pdf_path)
|
|
26
|
+
|
|
27
|
+
has_error = False
|
|
28
|
+
field_info = get_field_info(reader)
|
|
29
|
+
fields_by_ids = {f["field_id"]: f for f in field_info}
|
|
30
|
+
for field in fields:
|
|
31
|
+
existing_field = fields_by_ids.get(field["field_id"])
|
|
32
|
+
if not existing_field:
|
|
33
|
+
has_error = True
|
|
34
|
+
print(f"ERROR: `{field['field_id']}` is not a valid field ID")
|
|
35
|
+
elif field["page"] != existing_field["page"]:
|
|
36
|
+
has_error = True
|
|
37
|
+
print(f"ERROR: Incorrect page number for `{field['field_id']}` (got {field['page']}, expected {existing_field['page']})")
|
|
38
|
+
else:
|
|
39
|
+
if "value" in field:
|
|
40
|
+
err = validation_error_for_field_value(existing_field, field["value"])
|
|
41
|
+
if err:
|
|
42
|
+
print(err)
|
|
43
|
+
has_error = True
|
|
44
|
+
if has_error:
|
|
45
|
+
sys.exit(1)
|
|
46
|
+
|
|
47
|
+
writer = PdfWriter(clone_from=reader)
|
|
48
|
+
for page, field_values in fields_by_page.items():
|
|
49
|
+
writer.update_page_form_field_values(writer.pages[page - 1], field_values, auto_regenerate=False)
|
|
50
|
+
|
|
51
|
+
# This seems to be necessary for many PDF viewers to format the form values correctly.
|
|
52
|
+
# It may cause the viewer to show a "save changes" dialog even if the user doesn't make any changes.
|
|
53
|
+
writer.set_need_appearances_writer(True)
|
|
54
|
+
|
|
55
|
+
with open(output_pdf_path, "wb") as f:
|
|
56
|
+
writer.write(f)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def validation_error_for_field_value(field_info, field_value):
|
|
60
|
+
field_type = field_info["type"]
|
|
61
|
+
field_id = field_info["field_id"]
|
|
62
|
+
if field_type == "checkbox":
|
|
63
|
+
checked_val = field_info["checked_value"]
|
|
64
|
+
unchecked_val = field_info["unchecked_value"]
|
|
65
|
+
if field_value != checked_val and field_value != unchecked_val:
|
|
66
|
+
return f'ERROR: Invalid value "{field_value}" for checkbox field "{field_id}". The checked value is "{checked_val}" and the unchecked value is "{unchecked_val}"'
|
|
67
|
+
elif field_type == "radio_group":
|
|
68
|
+
option_values = [opt["value"] for opt in field_info["radio_options"]]
|
|
69
|
+
if field_value not in option_values:
|
|
70
|
+
return f'ERROR: Invalid value "{field_value}" for radio group field "{field_id}". Valid values are: {option_values}'
|
|
71
|
+
elif field_type == "choice":
|
|
72
|
+
choice_values = [opt["value"] for opt in field_info["choice_options"]]
|
|
73
|
+
if field_value not in choice_values:
|
|
74
|
+
return f'ERROR: Invalid value "{field_value}" for choice field "{field_id}". Valid values are: {choice_values}'
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# pypdf (at least version 5.7.0) has a bug when setting the value for a selection list field.
|
|
79
|
+
# In _writer.py around line 966:
|
|
80
|
+
#
|
|
81
|
+
# if field.get(FA.FT, "/Tx") == "/Ch" and field_flags & FA.FfBits.Combo == 0:
|
|
82
|
+
# txt = "\n".join(annotation.get_inherited(FA.Opt, []))
|
|
83
|
+
#
|
|
84
|
+
# The problem is that for selection lists, `get_inherited` returns a list of two-element lists like
|
|
85
|
+
# [["value1", "Text 1"], ["value2", "Text 2"], ...]
|
|
86
|
+
# This causes `join` to throw a TypeError because it expects an iterable of strings.
|
|
87
|
+
# The horrible workaround is to patch `get_inherited` to return a list of the value strings.
|
|
88
|
+
# We call the original method and adjust the return value only if the argument to `get_inherited`
|
|
89
|
+
# is `FA.Opt` and if the return value is a list of two-element lists.
|
|
90
|
+
def monkeypatch_pydpf_method():
|
|
91
|
+
from pypdf.generic import DictionaryObject
|
|
92
|
+
from pypdf.constants import FieldDictionaryAttributes
|
|
93
|
+
|
|
94
|
+
original_get_inherited = DictionaryObject.get_inherited
|
|
95
|
+
|
|
96
|
+
def patched_get_inherited(self, key: str, default = None):
|
|
97
|
+
result = original_get_inherited(self, key, default)
|
|
98
|
+
if key == FieldDictionaryAttributes.Opt:
|
|
99
|
+
if isinstance(result, list) and all(isinstance(v, list) and len(v) == 2 for v in result):
|
|
100
|
+
result = [r[0] for r in result]
|
|
101
|
+
return result
|
|
102
|
+
|
|
103
|
+
DictionaryObject.get_inherited = patched_get_inherited
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
if __name__ == "__main__":
|
|
107
|
+
if len(sys.argv) != 4:
|
|
108
|
+
print("Usage: fill_fillable_fields.py [input pdf] [field_values.json] [output pdf]")
|
|
109
|
+
sys.exit(1)
|
|
110
|
+
monkeypatch_pydpf_method()
|
|
111
|
+
input_pdf = sys.argv[1]
|
|
112
|
+
fields_json = sys.argv[2]
|
|
113
|
+
output_pdf = sys.argv[3]
|
|
114
|
+
fill_pdf_fields(input_pdf, fields_json, output_pdf)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from pypdf import PdfReader, PdfWriter
|
|
5
|
+
from pypdf.annotations import FreeText
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Fills a PDF by adding text annotations defined in `fields.json`. See forms.md.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def transform_coordinates(bbox, image_width, image_height, pdf_width, pdf_height):
|
|
12
|
+
"""Transform bounding box from image coordinates to PDF coordinates"""
|
|
13
|
+
# Image coordinates: origin at top-left, y increases downward
|
|
14
|
+
# PDF coordinates: origin at bottom-left, y increases upward
|
|
15
|
+
x_scale = pdf_width / image_width
|
|
16
|
+
y_scale = pdf_height / image_height
|
|
17
|
+
|
|
18
|
+
left = bbox[0] * x_scale
|
|
19
|
+
right = bbox[2] * x_scale
|
|
20
|
+
|
|
21
|
+
# Flip Y coordinates for PDF
|
|
22
|
+
top = pdf_height - (bbox[1] * y_scale)
|
|
23
|
+
bottom = pdf_height - (bbox[3] * y_scale)
|
|
24
|
+
|
|
25
|
+
return left, bottom, right, top
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def fill_pdf_form(input_pdf_path, fields_json_path, output_pdf_path):
|
|
29
|
+
"""Fill the PDF form with data from fields.json"""
|
|
30
|
+
|
|
31
|
+
# `fields.json` format described in forms.md.
|
|
32
|
+
with open(fields_json_path, "r") as f:
|
|
33
|
+
fields_data = json.load(f)
|
|
34
|
+
|
|
35
|
+
# Open the PDF
|
|
36
|
+
reader = PdfReader(input_pdf_path)
|
|
37
|
+
writer = PdfWriter()
|
|
38
|
+
|
|
39
|
+
# Copy all pages to writer
|
|
40
|
+
writer.append(reader)
|
|
41
|
+
|
|
42
|
+
# Get PDF dimensions for each page
|
|
43
|
+
pdf_dimensions = {}
|
|
44
|
+
for i, page in enumerate(reader.pages):
|
|
45
|
+
mediabox = page.mediabox
|
|
46
|
+
pdf_dimensions[i + 1] = [mediabox.width, mediabox.height]
|
|
47
|
+
|
|
48
|
+
# Process each form field
|
|
49
|
+
annotations = []
|
|
50
|
+
for field in fields_data["form_fields"]:
|
|
51
|
+
page_num = field["page_number"]
|
|
52
|
+
|
|
53
|
+
# Get page dimensions and transform coordinates.
|
|
54
|
+
page_info = next(p for p in fields_data["pages"] if p["page_number"] == page_num)
|
|
55
|
+
image_width = page_info["image_width"]
|
|
56
|
+
image_height = page_info["image_height"]
|
|
57
|
+
pdf_width, pdf_height = pdf_dimensions[page_num]
|
|
58
|
+
|
|
59
|
+
transformed_entry_box = transform_coordinates(
|
|
60
|
+
field["entry_bounding_box"],
|
|
61
|
+
image_width, image_height,
|
|
62
|
+
pdf_width, pdf_height
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# Skip empty fields
|
|
66
|
+
if "entry_text" not in field or "text" not in field["entry_text"]:
|
|
67
|
+
continue
|
|
68
|
+
entry_text = field["entry_text"]
|
|
69
|
+
text = entry_text["text"]
|
|
70
|
+
if not text:
|
|
71
|
+
continue
|
|
72
|
+
|
|
73
|
+
font_name = entry_text.get("font", "Arial")
|
|
74
|
+
font_size = str(entry_text.get("font_size", 14)) + "pt"
|
|
75
|
+
font_color = entry_text.get("font_color", "000000")
|
|
76
|
+
|
|
77
|
+
# Font size/color seems to not work reliably across viewers:
|
|
78
|
+
# https://github.com/py-pdf/pypdf/issues/2084
|
|
79
|
+
annotation = FreeText(
|
|
80
|
+
text=text,
|
|
81
|
+
rect=transformed_entry_box,
|
|
82
|
+
font=font_name,
|
|
83
|
+
font_size=font_size,
|
|
84
|
+
font_color=font_color,
|
|
85
|
+
border_color=None,
|
|
86
|
+
background_color=None,
|
|
87
|
+
)
|
|
88
|
+
annotations.append(annotation)
|
|
89
|
+
# page_number is 0-based for pypdf
|
|
90
|
+
writer.add_annotation(page_number=page_num - 1, annotation=annotation)
|
|
91
|
+
|
|
92
|
+
# Save the filled PDF
|
|
93
|
+
with open(output_pdf_path, "wb") as output:
|
|
94
|
+
writer.write(output)
|
|
95
|
+
|
|
96
|
+
print(f"Successfully filled PDF form and saved to {output_pdf_path}")
|
|
97
|
+
print(f"Added {len(annotations)} text annotations")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
if len(sys.argv) != 4:
|
|
102
|
+
print("Usage: fill_pdf_form_with_annotations.py [input pdf] [fields.json] [output pdf]")
|
|
103
|
+
sys.exit(1)
|
|
104
|
+
input_pdf = sys.argv[1]
|
|
105
|
+
fields_json = sys.argv[2]
|
|
106
|
+
output_pdf = sys.argv[3]
|
|
107
|
+
|
|
108
|
+
fill_pdf_form(input_pdf, fields_json, output_pdf)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Check if all phases in task_plan.md are complete
|
|
3
|
+
# Exit 0 if complete, exit 1 if incomplete
|
|
4
|
+
# Used by Stop hook to verify task completion
|
|
5
|
+
|
|
6
|
+
PLAN_FILE="${1:-task_plan.md}"
|
|
7
|
+
|
|
8
|
+
if [ ! -f "$PLAN_FILE" ]; then
|
|
9
|
+
echo "ERROR: $PLAN_FILE not found"
|
|
10
|
+
echo "Cannot verify completion without a task plan."
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
echo "=== Task Completion Check ==="
|
|
15
|
+
echo ""
|
|
16
|
+
|
|
17
|
+
# Count phases by status (using -F for fixed string matching)
|
|
18
|
+
TOTAL=$(grep -c "### Phase" "$PLAN_FILE" || true)
|
|
19
|
+
COMPLETE=$(grep -cF "**Status:** complete" "$PLAN_FILE" || true)
|
|
20
|
+
IN_PROGRESS=$(grep -cF "**Status:** in_progress" "$PLAN_FILE" || true)
|
|
21
|
+
PENDING=$(grep -cF "**Status:** pending" "$PLAN_FILE" || true)
|
|
22
|
+
|
|
23
|
+
# Default to 0 if empty
|
|
24
|
+
: "${TOTAL:=0}"
|
|
25
|
+
: "${COMPLETE:=0}"
|
|
26
|
+
: "${IN_PROGRESS:=0}"
|
|
27
|
+
: "${PENDING:=0}"
|
|
28
|
+
|
|
29
|
+
echo "Total phases: $TOTAL"
|
|
30
|
+
echo "Complete: $COMPLETE"
|
|
31
|
+
echo "In progress: $IN_PROGRESS"
|
|
32
|
+
echo "Pending: $PENDING"
|
|
33
|
+
echo ""
|
|
34
|
+
|
|
35
|
+
# Check completion
|
|
36
|
+
if [ "$COMPLETE" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
|
|
37
|
+
echo "ALL PHASES COMPLETE"
|
|
38
|
+
exit 0
|
|
39
|
+
else
|
|
40
|
+
echo "TASK NOT COMPLETE"
|
|
41
|
+
echo ""
|
|
42
|
+
echo "Do not stop until all phases are complete."
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Initialize planning files for a new session
|
|
3
|
+
# Usage: ./init-session.sh [project-name]
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
PROJECT_NAME="${1:-project}"
|
|
8
|
+
DATE=$(date +%Y-%m-%d)
|
|
9
|
+
|
|
10
|
+
echo "Initializing planning files for: $PROJECT_NAME"
|
|
11
|
+
|
|
12
|
+
# Create task_plan.md if it doesn't exist
|
|
13
|
+
if [ ! -f "task_plan.md" ]; then
|
|
14
|
+
cat > task_plan.md << 'EOF'
|
|
15
|
+
# Task Plan: [Brief Description]
|
|
16
|
+
|
|
17
|
+
## Goal
|
|
18
|
+
[One sentence describing the end state]
|
|
19
|
+
|
|
20
|
+
## Current Phase
|
|
21
|
+
Phase 1
|
|
22
|
+
|
|
23
|
+
## Phases
|
|
24
|
+
|
|
25
|
+
### Phase 1: Requirements & Discovery
|
|
26
|
+
- [ ] Understand user intent
|
|
27
|
+
- [ ] Identify constraints
|
|
28
|
+
- [ ] Document in findings.md
|
|
29
|
+
- **Status:** in_progress
|
|
30
|
+
|
|
31
|
+
### Phase 2: Planning & Structure
|
|
32
|
+
- [ ] Define approach
|
|
33
|
+
- [ ] Create project structure
|
|
34
|
+
- **Status:** pending
|
|
35
|
+
|
|
36
|
+
### Phase 3: Implementation
|
|
37
|
+
- [ ] Execute the plan
|
|
38
|
+
- [ ] Write to files before executing
|
|
39
|
+
- **Status:** pending
|
|
40
|
+
|
|
41
|
+
### Phase 4: Testing & Verification
|
|
42
|
+
- [ ] Verify requirements met
|
|
43
|
+
- [ ] Document test results
|
|
44
|
+
- **Status:** pending
|
|
45
|
+
|
|
46
|
+
### Phase 5: Delivery
|
|
47
|
+
- [ ] Review outputs
|
|
48
|
+
- [ ] Deliver to user
|
|
49
|
+
- **Status:** pending
|
|
50
|
+
|
|
51
|
+
## Decisions Made
|
|
52
|
+
| Decision | Rationale |
|
|
53
|
+
|----------|-----------|
|
|
54
|
+
|
|
55
|
+
## Errors Encountered
|
|
56
|
+
| Error | Resolution |
|
|
57
|
+
|-------|------------|
|
|
58
|
+
EOF
|
|
59
|
+
echo "Created task_plan.md"
|
|
60
|
+
else
|
|
61
|
+
echo "task_plan.md already exists, skipping"
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Create findings.md if it doesn't exist
|
|
65
|
+
if [ ! -f "findings.md" ]; then
|
|
66
|
+
cat > findings.md << 'EOF'
|
|
67
|
+
# Findings & Decisions
|
|
68
|
+
|
|
69
|
+
## Requirements
|
|
70
|
+
-
|
|
71
|
+
|
|
72
|
+
## Research Findings
|
|
73
|
+
-
|
|
74
|
+
|
|
75
|
+
## Technical Decisions
|
|
76
|
+
| Decision | Rationale |
|
|
77
|
+
|----------|-----------|
|
|
78
|
+
|
|
79
|
+
## Issues Encountered
|
|
80
|
+
| Issue | Resolution |
|
|
81
|
+
|-------|------------|
|
|
82
|
+
|
|
83
|
+
## Resources
|
|
84
|
+
-
|
|
85
|
+
EOF
|
|
86
|
+
echo "Created findings.md"
|
|
87
|
+
else
|
|
88
|
+
echo "findings.md already exists, skipping"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# Create progress.md if it doesn't exist
|
|
92
|
+
if [ ! -f "progress.md" ]; then
|
|
93
|
+
cat > progress.md << EOF
|
|
94
|
+
# Progress Log
|
|
95
|
+
|
|
96
|
+
## Session: $DATE
|
|
97
|
+
|
|
98
|
+
### Current Status
|
|
99
|
+
- **Phase:** 1 - Requirements & Discovery
|
|
100
|
+
- **Started:** $DATE
|
|
101
|
+
|
|
102
|
+
### Actions Taken
|
|
103
|
+
-
|
|
104
|
+
|
|
105
|
+
### Test Results
|
|
106
|
+
| Test | Expected | Actual | Status |
|
|
107
|
+
|------|----------|--------|--------|
|
|
108
|
+
|
|
109
|
+
### Errors
|
|
110
|
+
| Error | Resolution |
|
|
111
|
+
|-------|------------|
|
|
112
|
+
EOF
|
|
113
|
+
echo "Created progress.md"
|
|
114
|
+
else
|
|
115
|
+
echo "progress.md already exists, skipping"
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
echo ""
|
|
119
|
+
echo "Planning files initialized!"
|
|
120
|
+
echo "Files: task_plan.md, findings.md, progress.md"
|