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.
Files changed (368) hide show
  1. package/package.json +1 -1
  2. package/templates/.agents/agents/backend-specialist.md +263 -0
  3. package/templates/.agents/agents/code-archaeologist.md +106 -0
  4. package/templates/.agents/agents/database-architect.md +226 -0
  5. package/templates/.agents/agents/debugger.md +225 -0
  6. package/templates/.agents/agents/devops-engineer.md +242 -0
  7. package/templates/.agents/agents/documentation-writer.md +104 -0
  8. package/templates/.agents/agents/explorer-agent.md +73 -0
  9. package/templates/.agents/agents/frontend-specialist.md +593 -0
  10. package/templates/.agents/agents/game-developer.md +162 -0
  11. package/templates/.agents/agents/mobile-developer.md +377 -0
  12. package/templates/.agents/agents/orchestrator.md +416 -0
  13. package/templates/.agents/agents/penetration-tester.md +188 -0
  14. package/templates/.agents/agents/performance-optimizer.md +187 -0
  15. package/templates/.agents/agents/product-manager.md +112 -0
  16. package/templates/.agents/agents/product-owner.md +95 -0
  17. package/templates/.agents/agents/project-planner.md +406 -0
  18. package/templates/.agents/agents/qa-automation-engineer.md +103 -0
  19. package/templates/.agents/agents/security-auditor.md +170 -0
  20. package/templates/.agents/agents/seo-specialist.md +111 -0
  21. package/templates/.agents/agents/test-engineer.md +158 -0
  22. package/templates/.agents/rules/GEMINI.md +219 -0
  23. package/templates/.agents/scripts/auto_preview.py +148 -0
  24. package/templates/.agents/scripts/checklist.py +217 -0
  25. package/templates/.agents/scripts/session_manager.py +120 -0
  26. package/templates/.agents/scripts/verify_all.py +327 -0
  27. package/templates/.agents/workflows/brainstorm.md +113 -0
  28. package/templates/.agents/workflows/create.md +59 -0
  29. package/templates/.agents/workflows/debug.md +103 -0
  30. package/templates/.agents/workflows/deploy.md +176 -0
  31. package/templates/.agents/workflows/enhance.md +63 -0
  32. package/templates/.agents/workflows/orchestrate.md +237 -0
  33. package/templates/.agents/workflows/plan.md +89 -0
  34. package/templates/.agents/workflows/preview.md +81 -0
  35. package/templates/.agents/workflows/setup-brain.md +39 -0
  36. package/templates/.agents/workflows/status.md +86 -0
  37. package/templates/.agents/workflows/test.md +144 -0
  38. package/templates/.agents/workflows/ui-ux-pro-max.md +296 -0
  39. package/templates/skills_normal/api-patterns/scripts/api_validator.py +211 -0
  40. package/templates/skills_normal/database-design/scripts/schema_validator.py +172 -0
  41. package/templates/skills_normal/frontend-design/scripts/accessibility_checker.py +183 -0
  42. package/templates/skills_normal/frontend-design/scripts/ux_audit.py +722 -0
  43. package/templates/skills_normal/git-pushing/scripts/smart_commit.sh +19 -0
  44. package/templates/skills_normal/lint-and-validate/scripts/lint_runner.py +184 -0
  45. package/templates/skills_normal/lint-and-validate/scripts/type_coverage.py +173 -0
  46. package/templates/skills_normal/performance-profiling/scripts/lighthouse_audit.py +76 -0
  47. package/templates/skills_normal/senior-fullstack/scripts/code_quality_analyzer.py +114 -0
  48. package/templates/skills_normal/senior-fullstack/scripts/fullstack_scaffolder.py +114 -0
  49. package/templates/skills_normal/senior-fullstack/scripts/project_scaffolder.py +114 -0
  50. package/templates/skills_normal/seo-fundamentals/scripts/seo_checker.py +219 -0
  51. package/templates/skills_normal/testing-patterns/scripts/test_runner.py +219 -0
  52. package/templates/skills_normal/vulnerability-scanner/scripts/security_scan.py +458 -0
  53. package/templates/vault/007/scripts/config.py +472 -0
  54. package/templates/vault/007/scripts/full_audit.py +1306 -0
  55. package/templates/vault/007/scripts/quick_scan.py +481 -0
  56. package/templates/vault/007/scripts/requirements.txt +26 -0
  57. package/templates/vault/007/scripts/scanners/__init__.py +0 -0
  58. package/templates/vault/007/scripts/scanners/dependency_scanner.py +1305 -0
  59. package/templates/vault/007/scripts/scanners/injection_scanner.py +1104 -0
  60. package/templates/vault/007/scripts/scanners/secrets_scanner.py +1008 -0
  61. package/templates/vault/007/scripts/score_calculator.py +693 -0
  62. package/templates/vault/agent-orchestrator/scripts/match_skills.py +329 -0
  63. package/templates/vault/agent-orchestrator/scripts/orchestrate.py +304 -0
  64. package/templates/vault/agent-orchestrator/scripts/requirements.txt +1 -0
  65. package/templates/vault/agent-orchestrator/scripts/scan_registry.py +508 -0
  66. package/templates/vault/ai-studio-image/scripts/config.py +613 -0
  67. package/templates/vault/ai-studio-image/scripts/generate.py +630 -0
  68. package/templates/vault/ai-studio-image/scripts/prompt_engine.py +424 -0
  69. package/templates/vault/ai-studio-image/scripts/requirements.txt +4 -0
  70. package/templates/vault/ai-studio-image/scripts/templates.py +349 -0
  71. package/templates/vault/android_ui_verification/scripts/verify_ui.sh +32 -0
  72. package/templates/vault/apify-audience-analysis/reference/scripts/run_actor.js +363 -0
  73. package/templates/vault/apify-brand-reputation-monitoring/reference/scripts/run_actor.js +363 -0
  74. package/templates/vault/apify-competitor-intelligence/reference/scripts/run_actor.js +363 -0
  75. package/templates/vault/apify-content-analytics/reference/scripts/run_actor.js +363 -0
  76. package/templates/vault/apify-ecommerce/reference/scripts/package.json +3 -0
  77. package/templates/vault/apify-ecommerce/reference/scripts/run_actor.js +369 -0
  78. package/templates/vault/apify-influencer-discovery/reference/scripts/run_actor.js +363 -0
  79. package/templates/vault/apify-lead-generation/reference/scripts/run_actor.js +363 -0
  80. package/templates/vault/apify-market-research/reference/scripts/run_actor.js +363 -0
  81. package/templates/vault/apify-trend-analysis/reference/scripts/run_actor.js +363 -0
  82. package/templates/vault/apify-ultimate-scraper/reference/scripts/run_actor.js +363 -0
  83. package/templates/vault/audio-transcriber/scripts/install-requirements.sh +190 -0
  84. package/templates/vault/audio-transcriber/scripts/transcribe.py +486 -0
  85. package/templates/vault/claude-monitor/scripts/api_bench.py +240 -0
  86. package/templates/vault/claude-monitor/scripts/config.py +69 -0
  87. package/templates/vault/claude-monitor/scripts/health_check.py +362 -0
  88. package/templates/vault/claude-monitor/scripts/monitor.py +296 -0
  89. package/templates/vault/content-creator/scripts/brand_voice_analyzer.py +185 -0
  90. package/templates/vault/content-creator/scripts/seo_optimizer.py +419 -0
  91. package/templates/vault/context-agent/scripts/active_context.py +227 -0
  92. package/templates/vault/context-agent/scripts/compressor.py +149 -0
  93. package/templates/vault/context-agent/scripts/config.py +69 -0
  94. package/templates/vault/context-agent/scripts/context_loader.py +155 -0
  95. package/templates/vault/context-agent/scripts/context_manager.py +302 -0
  96. package/templates/vault/context-agent/scripts/models.py +103 -0
  97. package/templates/vault/context-agent/scripts/project_registry.py +132 -0
  98. package/templates/vault/context-agent/scripts/requirements.txt +6 -0
  99. package/templates/vault/context-agent/scripts/search.py +115 -0
  100. package/templates/vault/context-agent/scripts/session_parser.py +206 -0
  101. package/templates/vault/context-agent/scripts/session_summary.py +319 -0
  102. package/templates/vault/context-guardian/scripts/context_snapshot.py +229 -0
  103. package/templates/vault/docx/ooxml/scripts/pack.py +159 -0
  104. package/templates/vault/docx/ooxml/scripts/unpack.py +29 -0
  105. package/templates/vault/docx/ooxml/scripts/validate.py +69 -0
  106. package/templates/vault/docx/ooxml/scripts/validation/__init__.py +15 -0
  107. package/templates/vault/docx/ooxml/scripts/validation/base.py +951 -0
  108. package/templates/vault/docx/ooxml/scripts/validation/docx.py +274 -0
  109. package/templates/vault/docx/ooxml/scripts/validation/pptx.py +315 -0
  110. package/templates/vault/docx/ooxml/scripts/validation/redlining.py +279 -0
  111. package/templates/vault/docx/scripts/__init__.py +1 -0
  112. package/templates/vault/docx/scripts/document.py +1276 -0
  113. package/templates/vault/docx/scripts/templates/comments.xml +3 -0
  114. package/templates/vault/docx/scripts/templates/commentsExtended.xml +3 -0
  115. package/templates/vault/docx/scripts/templates/commentsExtensible.xml +3 -0
  116. package/templates/vault/docx/scripts/templates/commentsIds.xml +3 -0
  117. package/templates/vault/docx/scripts/templates/people.xml +3 -0
  118. package/templates/vault/docx/scripts/utilities.py +374 -0
  119. package/templates/vault/docx-official/ooxml/scripts/pack.py +159 -0
  120. package/templates/vault/docx-official/ooxml/scripts/unpack.py +29 -0
  121. package/templates/vault/docx-official/ooxml/scripts/validate.py +69 -0
  122. package/templates/vault/docx-official/ooxml/scripts/validation/__init__.py +15 -0
  123. package/templates/vault/docx-official/ooxml/scripts/validation/base.py +951 -0
  124. package/templates/vault/docx-official/ooxml/scripts/validation/docx.py +274 -0
  125. package/templates/vault/docx-official/ooxml/scripts/validation/pptx.py +315 -0
  126. package/templates/vault/docx-official/ooxml/scripts/validation/redlining.py +279 -0
  127. package/templates/vault/docx-official/scripts/__init__.py +1 -0
  128. package/templates/vault/docx-official/scripts/document.py +1276 -0
  129. package/templates/vault/docx-official/scripts/templates/comments.xml +3 -0
  130. package/templates/vault/docx-official/scripts/templates/commentsExtended.xml +3 -0
  131. package/templates/vault/docx-official/scripts/templates/commentsExtensible.xml +3 -0
  132. package/templates/vault/docx-official/scripts/templates/commentsIds.xml +3 -0
  133. package/templates/vault/docx-official/scripts/templates/people.xml +3 -0
  134. package/templates/vault/docx-official/scripts/utilities.py +374 -0
  135. package/templates/vault/geo-fundamentals/scripts/geo_checker.py +289 -0
  136. package/templates/vault/helm-chart-scaffolding/scripts/validate-chart.sh +244 -0
  137. package/templates/vault/i18n-localization/scripts/i18n_checker.py +241 -0
  138. package/templates/vault/instagram/scripts/account_setup.py +233 -0
  139. package/templates/vault/instagram/scripts/analyze.py +221 -0
  140. package/templates/vault/instagram/scripts/api_client.py +444 -0
  141. package/templates/vault/instagram/scripts/auth.py +411 -0
  142. package/templates/vault/instagram/scripts/comments.py +160 -0
  143. package/templates/vault/instagram/scripts/config.py +111 -0
  144. package/templates/vault/instagram/scripts/db.py +467 -0
  145. package/templates/vault/instagram/scripts/export.py +138 -0
  146. package/templates/vault/instagram/scripts/governance.py +233 -0
  147. package/templates/vault/instagram/scripts/hashtags.py +114 -0
  148. package/templates/vault/instagram/scripts/insights.py +170 -0
  149. package/templates/vault/instagram/scripts/media.py +65 -0
  150. package/templates/vault/instagram/scripts/messages.py +103 -0
  151. package/templates/vault/instagram/scripts/profile.py +58 -0
  152. package/templates/vault/instagram/scripts/publish.py +449 -0
  153. package/templates/vault/instagram/scripts/requirements.txt +5 -0
  154. package/templates/vault/instagram/scripts/run_all.py +189 -0
  155. package/templates/vault/instagram/scripts/schedule.py +189 -0
  156. package/templates/vault/instagram/scripts/serve_api.py +234 -0
  157. package/templates/vault/instagram/scripts/templates.py +155 -0
  158. package/templates/vault/junta-leiloeiros/scripts/db.py +216 -0
  159. package/templates/vault/junta-leiloeiros/scripts/export.py +137 -0
  160. package/templates/vault/junta-leiloeiros/scripts/requirements.txt +15 -0
  161. package/templates/vault/junta-leiloeiros/scripts/run_all.py +190 -0
  162. package/templates/vault/junta-leiloeiros/scripts/scraper/__init__.py +4 -0
  163. package/templates/vault/junta-leiloeiros/scripts/scraper/base_scraper.py +209 -0
  164. package/templates/vault/junta-leiloeiros/scripts/scraper/generic_scraper.py +110 -0
  165. package/templates/vault/junta-leiloeiros/scripts/scraper/jucap.py +110 -0
  166. package/templates/vault/junta-leiloeiros/scripts/scraper/juceac.py +72 -0
  167. package/templates/vault/junta-leiloeiros/scripts/scraper/juceal.py +72 -0
  168. package/templates/vault/junta-leiloeiros/scripts/scraper/juceb.py +68 -0
  169. package/templates/vault/junta-leiloeiros/scripts/scraper/jucec.py +63 -0
  170. package/templates/vault/junta-leiloeiros/scripts/scraper/jucema.py +211 -0
  171. package/templates/vault/junta-leiloeiros/scripts/scraper/jucemg.py +218 -0
  172. package/templates/vault/junta-leiloeiros/scripts/scraper/jucep.py +70 -0
  173. package/templates/vault/junta-leiloeiros/scripts/scraper/jucepa.py +74 -0
  174. package/templates/vault/junta-leiloeiros/scripts/scraper/jucepar.py +80 -0
  175. package/templates/vault/junta-leiloeiros/scripts/scraper/jucepe.py +78 -0
  176. package/templates/vault/junta-leiloeiros/scripts/scraper/jucepi.py +69 -0
  177. package/templates/vault/junta-leiloeiros/scripts/scraper/jucer.py +256 -0
  178. package/templates/vault/junta-leiloeiros/scripts/scraper/jucerja.py +170 -0
  179. package/templates/vault/junta-leiloeiros/scripts/scraper/jucern.py +71 -0
  180. package/templates/vault/junta-leiloeiros/scripts/scraper/jucesc.py +89 -0
  181. package/templates/vault/junta-leiloeiros/scripts/scraper/jucesp.py +233 -0
  182. package/templates/vault/junta-leiloeiros/scripts/scraper/jucetins.py +134 -0
  183. package/templates/vault/junta-leiloeiros/scripts/scraper/jucis_df.py +63 -0
  184. package/templates/vault/junta-leiloeiros/scripts/scraper/jucisrs.py +299 -0
  185. package/templates/vault/junta-leiloeiros/scripts/scraper/states.py +99 -0
  186. package/templates/vault/junta-leiloeiros/scripts/serve_api.py +164 -0
  187. package/templates/vault/junta-leiloeiros/scripts/web_scraper_fallback.py +233 -0
  188. package/templates/vault/last30days/scripts/last30days.py +521 -0
  189. package/templates/vault/last30days/scripts/lib/__init__.py +1 -0
  190. package/templates/vault/last30days/scripts/lib/cache.py +152 -0
  191. package/templates/vault/last30days/scripts/lib/dates.py +124 -0
  192. package/templates/vault/last30days/scripts/lib/dedupe.py +120 -0
  193. package/templates/vault/last30days/scripts/lib/env.py +149 -0
  194. package/templates/vault/last30days/scripts/lib/http.py +152 -0
  195. package/templates/vault/last30days/scripts/lib/models.py +175 -0
  196. package/templates/vault/last30days/scripts/lib/normalize.py +160 -0
  197. package/templates/vault/last30days/scripts/lib/openai_reddit.py +230 -0
  198. package/templates/vault/last30days/scripts/lib/reddit_enrich.py +232 -0
  199. package/templates/vault/last30days/scripts/lib/render.py +383 -0
  200. package/templates/vault/last30days/scripts/lib/schema.py +336 -0
  201. package/templates/vault/last30days/scripts/lib/score.py +311 -0
  202. package/templates/vault/last30days/scripts/lib/ui.py +324 -0
  203. package/templates/vault/last30days/scripts/lib/websearch.py +401 -0
  204. package/templates/vault/last30days/scripts/lib/xai_x.py +217 -0
  205. package/templates/vault/leiloeiro-avaliacao/scripts/governance.py +106 -0
  206. package/templates/vault/leiloeiro-avaliacao/scripts/requirements.txt +1 -0
  207. package/templates/vault/leiloeiro-edital/scripts/governance.py +106 -0
  208. package/templates/vault/leiloeiro-edital/scripts/requirements.txt +1 -0
  209. package/templates/vault/leiloeiro-ia/scripts/governance.py +106 -0
  210. package/templates/vault/leiloeiro-ia/scripts/requirements.txt +1 -0
  211. package/templates/vault/leiloeiro-juridico/scripts/governance.py +106 -0
  212. package/templates/vault/leiloeiro-juridico/scripts/requirements.txt +1 -0
  213. package/templates/vault/leiloeiro-mercado/scripts/governance.py +106 -0
  214. package/templates/vault/leiloeiro-mercado/scripts/requirements.txt +1 -0
  215. package/templates/vault/leiloeiro-risco/scripts/governance.py +106 -0
  216. package/templates/vault/leiloeiro-risco/scripts/requirements.txt +1 -0
  217. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/database.ts +24 -0
  218. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/db.ts +35 -0
  219. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/index.ts +2 -0
  220. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/migrations.ts +31 -0
  221. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/db/schema.sql +8 -0
  222. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/index.ts +44 -0
  223. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/routes/todos.ts +155 -0
  224. package/templates/vault/loki-mode/examples/todo-app-generated/backend/src/types/index.ts +35 -0
  225. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/App.css +384 -0
  226. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/App.tsx +81 -0
  227. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/api/todos.ts +57 -0
  228. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/ConfirmDialog.tsx +26 -0
  229. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/EmptyState.tsx +8 -0
  230. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoForm.tsx +43 -0
  231. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoItem.tsx +36 -0
  232. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/components/TodoList.tsx +27 -0
  233. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/hooks/useTodos.ts +81 -0
  234. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/index.css +48 -0
  235. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/main.tsx +10 -0
  236. package/templates/vault/loki-mode/examples/todo-app-generated/frontend/src/vite-env.d.ts +1 -0
  237. package/templates/vault/loki-mode/scripts/export-to-vibe-kanban.sh +178 -0
  238. package/templates/vault/loki-mode/scripts/loki-wrapper.sh +281 -0
  239. package/templates/vault/loki-mode/scripts/take-screenshots.js +55 -0
  240. package/templates/vault/matematico-tao/scripts/complexity_analyzer.py +544 -0
  241. package/templates/vault/matematico-tao/scripts/dependency_graph.py +538 -0
  242. package/templates/vault/mcp-builder/scripts/connections.py +151 -0
  243. package/templates/vault/mcp-builder/scripts/evaluation.py +373 -0
  244. package/templates/vault/mcp-builder/scripts/example_evaluation.xml +22 -0
  245. package/templates/vault/mcp-builder/scripts/requirements.txt +2 -0
  246. package/templates/vault/mobile-design/scripts/mobile_audit.py +670 -0
  247. package/templates/vault/notebooklm/scripts/__init__.py +81 -0
  248. package/templates/vault/notebooklm/scripts/ask_question.py +256 -0
  249. package/templates/vault/notebooklm/scripts/auth_manager.py +358 -0
  250. package/templates/vault/notebooklm/scripts/browser_session.py +255 -0
  251. package/templates/vault/notebooklm/scripts/browser_utils.py +107 -0
  252. package/templates/vault/notebooklm/scripts/cleanup_manager.py +302 -0
  253. package/templates/vault/notebooklm/scripts/config.py +44 -0
  254. package/templates/vault/notebooklm/scripts/notebook_manager.py +410 -0
  255. package/templates/vault/notebooklm/scripts/run.py +102 -0
  256. package/templates/vault/notebooklm/scripts/setup_environment.py +204 -0
  257. package/templates/vault/pdf/scripts/check_bounding_boxes.py +70 -0
  258. package/templates/vault/pdf/scripts/check_bounding_boxes_test.py +226 -0
  259. package/templates/vault/pdf/scripts/check_fillable_fields.py +12 -0
  260. package/templates/vault/pdf/scripts/convert_pdf_to_images.py +35 -0
  261. package/templates/vault/pdf/scripts/create_validation_image.py +41 -0
  262. package/templates/vault/pdf/scripts/extract_form_field_info.py +152 -0
  263. package/templates/vault/pdf/scripts/fill_fillable_fields.py +114 -0
  264. package/templates/vault/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  265. package/templates/vault/pdf-official/scripts/check_bounding_boxes.py +70 -0
  266. package/templates/vault/pdf-official/scripts/check_bounding_boxes_test.py +226 -0
  267. package/templates/vault/pdf-official/scripts/check_fillable_fields.py +12 -0
  268. package/templates/vault/pdf-official/scripts/convert_pdf_to_images.py +35 -0
  269. package/templates/vault/pdf-official/scripts/create_validation_image.py +41 -0
  270. package/templates/vault/pdf-official/scripts/extract_form_field_info.py +152 -0
  271. package/templates/vault/pdf-official/scripts/fill_fillable_fields.py +114 -0
  272. package/templates/vault/pdf-official/scripts/fill_pdf_form_with_annotations.py +108 -0
  273. package/templates/vault/planning-with-files/scripts/check-complete.sh +44 -0
  274. package/templates/vault/planning-with-files/scripts/init-session.sh +120 -0
  275. package/templates/vault/pptx/ooxml/scripts/pack.py +159 -0
  276. package/templates/vault/pptx/ooxml/scripts/unpack.py +29 -0
  277. package/templates/vault/pptx/ooxml/scripts/validate.py +69 -0
  278. package/templates/vault/pptx/ooxml/scripts/validation/__init__.py +15 -0
  279. package/templates/vault/pptx/ooxml/scripts/validation/base.py +951 -0
  280. package/templates/vault/pptx/ooxml/scripts/validation/docx.py +274 -0
  281. package/templates/vault/pptx/ooxml/scripts/validation/pptx.py +315 -0
  282. package/templates/vault/pptx/ooxml/scripts/validation/redlining.py +279 -0
  283. package/templates/vault/pptx/scripts/html2pptx.js +979 -0
  284. package/templates/vault/pptx/scripts/inventory.py +1020 -0
  285. package/templates/vault/pptx/scripts/rearrange.py +231 -0
  286. package/templates/vault/pptx/scripts/replace.py +385 -0
  287. package/templates/vault/pptx/scripts/thumbnail.py +450 -0
  288. package/templates/vault/pptx-official/ooxml/scripts/pack.py +159 -0
  289. package/templates/vault/pptx-official/ooxml/scripts/unpack.py +29 -0
  290. package/templates/vault/pptx-official/ooxml/scripts/validate.py +69 -0
  291. package/templates/vault/pptx-official/ooxml/scripts/validation/__init__.py +15 -0
  292. package/templates/vault/pptx-official/ooxml/scripts/validation/base.py +951 -0
  293. package/templates/vault/pptx-official/ooxml/scripts/validation/docx.py +274 -0
  294. package/templates/vault/pptx-official/ooxml/scripts/validation/pptx.py +315 -0
  295. package/templates/vault/pptx-official/ooxml/scripts/validation/redlining.py +279 -0
  296. package/templates/vault/pptx-official/scripts/html2pptx.js +979 -0
  297. package/templates/vault/pptx-official/scripts/inventory.py +1020 -0
  298. package/templates/vault/pptx-official/scripts/rearrange.py +231 -0
  299. package/templates/vault/pptx-official/scripts/replace.py +385 -0
  300. package/templates/vault/pptx-official/scripts/thumbnail.py +450 -0
  301. package/templates/vault/product-manager-toolkit/scripts/customer_interview_analyzer.py +441 -0
  302. package/templates/vault/product-manager-toolkit/scripts/rice_prioritizer.py +296 -0
  303. package/templates/vault/prompt-engineering-patterns/scripts/optimize-prompt.py +279 -0
  304. package/templates/vault/scripts/.skill_cache.json +7538 -0
  305. package/templates/vault/scripts/skill_search.py +228 -0
  306. package/templates/vault/senior-architect/scripts/architecture_diagram_generator.py +114 -0
  307. package/templates/vault/senior-architect/scripts/dependency_analyzer.py +114 -0
  308. package/templates/vault/senior-architect/scripts/project_architect.py +114 -0
  309. package/templates/vault/shopify-development/scripts/requirements.txt +19 -0
  310. package/templates/vault/shopify-development/scripts/shopify_graphql.py +428 -0
  311. package/templates/vault/shopify-development/scripts/shopify_init.py +441 -0
  312. package/templates/vault/shopify-development/scripts/tests/test_shopify_init.py +379 -0
  313. package/templates/vault/skill-creator/scripts/init_skill.py +303 -0
  314. package/templates/vault/skill-creator/scripts/package_skill.py +110 -0
  315. package/templates/vault/skill-creator/scripts/quick_validate.py +95 -0
  316. package/templates/vault/skill-installer/scripts/detect_skills.py +318 -0
  317. package/templates/vault/skill-installer/scripts/install_skill.py +1708 -0
  318. package/templates/vault/skill-installer/scripts/package_skill.py +417 -0
  319. package/templates/vault/skill-installer/scripts/requirements.txt +1 -0
  320. package/templates/vault/skill-installer/scripts/validate_skill.py +430 -0
  321. package/templates/vault/skill-sentinel/scripts/analyzers/__init__.py +13 -0
  322. package/templates/vault/skill-sentinel/scripts/analyzers/code_quality.py +247 -0
  323. package/templates/vault/skill-sentinel/scripts/analyzers/cross_skill.py +134 -0
  324. package/templates/vault/skill-sentinel/scripts/analyzers/dependencies.py +121 -0
  325. package/templates/vault/skill-sentinel/scripts/analyzers/documentation.py +189 -0
  326. package/templates/vault/skill-sentinel/scripts/analyzers/governance_audit.py +153 -0
  327. package/templates/vault/skill-sentinel/scripts/analyzers/performance.py +164 -0
  328. package/templates/vault/skill-sentinel/scripts/analyzers/security.py +189 -0
  329. package/templates/vault/skill-sentinel/scripts/config.py +158 -0
  330. package/templates/vault/skill-sentinel/scripts/cost_optimizer.py +146 -0
  331. package/templates/vault/skill-sentinel/scripts/db.py +354 -0
  332. package/templates/vault/skill-sentinel/scripts/governance.py +58 -0
  333. package/templates/vault/skill-sentinel/scripts/recommender.py +228 -0
  334. package/templates/vault/skill-sentinel/scripts/report_generator.py +224 -0
  335. package/templates/vault/skill-sentinel/scripts/requirements.txt +1 -0
  336. package/templates/vault/skill-sentinel/scripts/run_audit.py +290 -0
  337. package/templates/vault/skill-sentinel/scripts/scanner.py +271 -0
  338. package/templates/vault/stability-ai/scripts/config.py +266 -0
  339. package/templates/vault/stability-ai/scripts/generate.py +687 -0
  340. package/templates/vault/stability-ai/scripts/requirements.txt +4 -0
  341. package/templates/vault/stability-ai/scripts/styles.py +174 -0
  342. package/templates/vault/telegram/assets/boilerplate/nodejs/src/bot-client.ts +86 -0
  343. package/templates/vault/telegram/assets/boilerplate/nodejs/src/handlers.ts +79 -0
  344. package/templates/vault/telegram/assets/boilerplate/nodejs/src/index.ts +32 -0
  345. package/templates/vault/telegram/scripts/send_message.py +143 -0
  346. package/templates/vault/telegram/scripts/setup_project.py +103 -0
  347. package/templates/vault/telegram/scripts/test_bot.py +144 -0
  348. package/templates/vault/typescript-expert/scripts/ts_diagnostic.py +203 -0
  349. package/templates/vault/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
  350. package/templates/vault/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
  351. package/templates/vault/ui-ux-pro-max/scripts/core.py +257 -0
  352. package/templates/vault/ui-ux-pro-max/scripts/design_system.py +487 -0
  353. package/templates/vault/ui-ux-pro-max/scripts/search.py +76 -0
  354. package/templates/vault/videodb/scripts/ws_listener.py +204 -0
  355. package/templates/vault/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
  356. package/templates/vault/web-artifacts-builder/scripts/init-artifact.sh +322 -0
  357. package/templates/vault/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  358. package/templates/vault/webapp-testing/scripts/with_server.py +106 -0
  359. package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/index.ts +125 -0
  360. package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/template-manager.ts +67 -0
  361. package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/types.ts +216 -0
  362. package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/webhook-handler.ts +173 -0
  363. package/templates/vault/whatsapp-cloud-api/assets/boilerplate/nodejs/src/whatsapp-client.ts +193 -0
  364. package/templates/vault/whatsapp-cloud-api/scripts/send_test_message.py +137 -0
  365. package/templates/vault/whatsapp-cloud-api/scripts/setup_project.py +118 -0
  366. package/templates/vault/whatsapp-cloud-api/scripts/validate_config.py +190 -0
  367. package/templates/vault/youtube-summarizer/scripts/extract-transcript.py +65 -0
  368. 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)