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,271 @@
1
+ """
2
+ Scanner de skills: descobre e inventaria todas as skills do ecossistema.
3
+
4
+ Percorre os diretorios conhecidos procurando SKILL.md com frontmatter YAML,
5
+ e coleta metricas de arquivo para cada skill encontrada.
6
+
7
+ Uso:
8
+ from scanner import SkillScanner
9
+ scanner = SkillScanner()
10
+ skills = scanner.discover_all()
11
+ for s in skills:
12
+ print(s["name"], s["path"], s["file_count"])
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import ast
17
+ import re
18
+ from pathlib import Path
19
+ from typing import Any, Dict, List, Optional
20
+
21
+ from config import (
22
+ IGNORE_DIRS,
23
+ SKILL_MAX_DEPTH,
24
+ SKILL_SEARCH_PATHS,
25
+ SKILLS_ROOT,
26
+ )
27
+
28
+
29
+ def _parse_yaml_frontmatter(content: str) -> Dict[str, str]:
30
+ """Extrai frontmatter YAML simples de um arquivo SKILL.md."""
31
+ if not content.startswith("---"):
32
+ return {}
33
+ end = content.find("---", 3)
34
+ if end == -1:
35
+ return {}
36
+ frontmatter = content[3:end].strip()
37
+ result = {}
38
+ for line in frontmatter.split("\n"):
39
+ line = line.strip()
40
+ if not line or line.startswith("#"):
41
+ continue
42
+ # Tratar continuacao de description com >-
43
+ if ":" in line and not line.startswith("-") and not line.startswith(" "):
44
+ key, _, value = line.partition(":")
45
+ key = key.strip()
46
+ value = value.strip().strip('"').strip("'")
47
+ if value == ">-" or value == ">":
48
+ # Multi-line: coletar proximas linhas indentadas
49
+ continue
50
+ result[key] = value
51
+ elif line.startswith(" ") and "description" not in result:
52
+ # Continuacao multi-line de description
53
+ result.setdefault("description", "")
54
+ result["description"] += " " + line.strip()
55
+ # Limpar description
56
+ if "description" in result:
57
+ result["description"] = result["description"].strip().strip('"').strip("'")
58
+ return result
59
+
60
+
61
+ def _count_lines(filepath: Path) -> int:
62
+ """Conta linhas de um arquivo de texto."""
63
+ try:
64
+ return len(filepath.read_text(encoding="utf-8", errors="replace").splitlines())
65
+ except (OSError, UnicodeDecodeError):
66
+ return 0
67
+
68
+
69
+ # .claude is an explicit SKILL_SEARCH_PATH so its .py files must be scanned
70
+ _PY_IGNORE_DIRS = IGNORE_DIRS - {".claude"}
71
+
72
+
73
+ def _list_python_files(directory: Path) -> List[Path]:
74
+ """Lista todos os .py dentro de um diretorio (recursivo)."""
75
+ result = []
76
+ if not directory.exists():
77
+ return result
78
+ for p in directory.rglob("*.py"):
79
+ if not any(part in _PY_IGNORE_DIRS for part in p.parts):
80
+ result.append(p)
81
+ return sorted(result)
82
+
83
+
84
+ def _extract_functions(filepath: Path) -> List[Dict[str, Any]]:
85
+ """Extrai informacoes de funcoes/classes via AST."""
86
+ try:
87
+ source = filepath.read_text(encoding="utf-8", errors="replace")
88
+ tree = ast.parse(source, filename=str(filepath))
89
+ except (SyntaxError, OSError):
90
+ return []
91
+
92
+ functions = []
93
+ for node in ast.walk(tree):
94
+ if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
95
+ functions.append({
96
+ "name": node.name,
97
+ "type": "async_function" if isinstance(node, ast.AsyncFunctionDef) else "function",
98
+ "line": node.lineno,
99
+ "end_line": getattr(node, "end_lineno", node.lineno),
100
+ "has_docstring": (
101
+ isinstance(node.body[0], ast.Expr)
102
+ and isinstance(node.body[0].value, (ast.Constant, ast.Str))
103
+ if node.body else False
104
+ ),
105
+ "args_count": len(node.args.args),
106
+ })
107
+ elif isinstance(node, ast.ClassDef):
108
+ functions.append({
109
+ "name": node.name,
110
+ "type": "class",
111
+ "line": node.lineno,
112
+ "end_line": getattr(node, "end_lineno", node.lineno),
113
+ "has_docstring": (
114
+ isinstance(node.body[0], ast.Expr)
115
+ and isinstance(node.body[0].value, (ast.Constant, ast.Str))
116
+ if node.body else False
117
+ ),
118
+ "args_count": 0,
119
+ })
120
+ return functions
121
+
122
+
123
+ def _parse_requirements(skill_dir: Path) -> List[Dict[str, str]]:
124
+ """Parse requirements.txt se existir."""
125
+ reqs_path = skill_dir / "scripts" / "requirements.txt"
126
+ if not reqs_path.exists():
127
+ return []
128
+ deps = []
129
+ try:
130
+ for line in reqs_path.read_text(encoding="utf-8").splitlines():
131
+ line = line.strip()
132
+ if not line or line.startswith("#") or line.startswith("-"):
133
+ continue
134
+ # Parse "package==1.0" ou "package>=1.0" ou "package"
135
+ match = re.match(r'^([a-zA-Z0-9_-]+)\s*([><=!~]+)?\s*([\d.]*)', line)
136
+ if match:
137
+ deps.append({
138
+ "name": match.group(1),
139
+ "version_spec": (match.group(2) or "") + (match.group(3) or ""),
140
+ "pinned": "==" in (match.group(2) or ""),
141
+ })
142
+ except OSError:
143
+ pass
144
+ return deps
145
+
146
+
147
+ class SkillScanner:
148
+ """Descobre e inventaria skills no ecossistema."""
149
+
150
+ def __init__(self, skills_root: Path = SKILLS_ROOT):
151
+ self.skills_root = skills_root
152
+
153
+ def discover_all(self) -> List[Dict[str, Any]]:
154
+ """Descobre todas as skills, retornando metadados enriquecidos."""
155
+ skill_dirs = self._find_skill_dirs()
156
+ skills = []
157
+ for skill_dir in skill_dirs:
158
+ info = self._analyze_skill(skill_dir)
159
+ if info:
160
+ skills.append(info)
161
+ return sorted(skills, key=lambda s: s["name"])
162
+
163
+ def discover_skill(self, name: str) -> Optional[Dict[str, Any]]:
164
+ """Descobre uma skill especifica pelo nome."""
165
+ for skill in self.discover_all():
166
+ if skill["name"] == name:
167
+ return skill
168
+ return None
169
+
170
+ def _find_skill_dirs(self) -> List[Path]:
171
+ """Encontra diretorios que contem SKILL.md."""
172
+ found = []
173
+ for search_path in SKILL_SEARCH_PATHS:
174
+ if not search_path.exists():
175
+ continue
176
+ self._search_recursive(search_path, found, depth=0)
177
+ # Deduplica
178
+ seen = set()
179
+ unique = []
180
+ for p in found:
181
+ resolved = p.resolve()
182
+ if resolved not in seen:
183
+ seen.add(resolved)
184
+ unique.append(p)
185
+ return unique
186
+
187
+ def _search_recursive(self, directory: Path, found: List[Path], depth: int) -> None:
188
+ """Busca recursiva por SKILL.md com limite de profundidade."""
189
+ if depth > SKILL_MAX_DEPTH:
190
+ return
191
+ try:
192
+ for item in sorted(directory.iterdir()):
193
+ if not item.is_dir():
194
+ continue
195
+ if item.name in IGNORE_DIRS:
196
+ continue
197
+ skill_md = item / "SKILL.md"
198
+ if skill_md.exists():
199
+ found.append(item)
200
+ else:
201
+ self._search_recursive(item, found, depth + 1)
202
+ except PermissionError:
203
+ pass
204
+
205
+ def _analyze_skill(self, skill_dir: Path) -> Optional[Dict[str, Any]]:
206
+ """Analisa uma skill e retorna metadados completos."""
207
+ skill_md = skill_dir / "SKILL.md"
208
+ if not skill_md.exists():
209
+ return None
210
+
211
+ try:
212
+ content = skill_md.read_text(encoding="utf-8", errors="replace")
213
+ except OSError:
214
+ return None
215
+
216
+ meta = _parse_yaml_frontmatter(content)
217
+ if not meta.get("name"):
218
+ # Inferir nome do diretorio
219
+ meta["name"] = skill_dir.name
220
+
221
+ py_files = _list_python_files(skill_dir / "scripts")
222
+ total_lines = sum(_count_lines(f) for f in py_files)
223
+
224
+ all_functions = {}
225
+ for f in py_files:
226
+ funcs = _extract_functions(f)
227
+ if funcs:
228
+ all_functions[str(f.relative_to(skill_dir))] = funcs
229
+
230
+ ref_dir = skill_dir / "references"
231
+ ref_files = sorted(ref_dir.glob("*.md")) if ref_dir.exists() else []
232
+
233
+ deps = _parse_requirements(skill_dir)
234
+
235
+ return {
236
+ "name": meta.get("name", skill_dir.name),
237
+ "path": str(skill_dir),
238
+ "version": meta.get("version", ""),
239
+ "description": meta.get("description", ""),
240
+ "skill_md_path": str(skill_md),
241
+ "skill_md_lines": _count_lines(skill_md),
242
+ "python_files": [str(f.relative_to(skill_dir)) for f in py_files],
243
+ "file_count": len(py_files),
244
+ "line_count": total_lines,
245
+ "functions": all_functions,
246
+ "requirements": deps,
247
+ "reference_files": [str(f.relative_to(skill_dir)) for f in ref_files],
248
+ "has_scripts_dir": (skill_dir / "scripts").is_dir(),
249
+ "has_references_dir": ref_dir.is_dir(),
250
+ "has_data_dir": (skill_dir / "data").is_dir(),
251
+ "has_governance": any("governance" in f.name for f in py_files),
252
+ "has_db": any("db" in f.name for f in py_files),
253
+ "has_config": any("config" in f.name for f in py_files),
254
+ }
255
+
256
+
257
+ # -- CLI -----------------------------------------------------------------------
258
+ if __name__ == "__main__":
259
+ import json
260
+ scanner = SkillScanner()
261
+ skills = scanner.discover_all()
262
+ print(f"Skills encontradas: {len(skills)}\n")
263
+ for s in skills:
264
+ print(f" {s['name']} (v{s['version'] or '?'})")
265
+ print(f" Path: {s['path']}")
266
+ print(f" Files: {s['file_count']} Python ({s['line_count']} lines)")
267
+ print(f" Refs: {len(s['reference_files'])} docs")
268
+ print(f" Gov: {'sim' if s['has_governance'] else 'nao'} | "
269
+ f"DB: {'sim' if s['has_db'] else 'nao'} | "
270
+ f"Config: {'sim' if s['has_config'] else 'nao'}")
271
+ print()
@@ -0,0 +1,266 @@
1
+ """
2
+ Configuracao central da skill Stability AI.
3
+
4
+ Gerencia: API keys, modelos, formatos, aspect ratios, limites de seguranca.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import json
9
+ import os
10
+ from datetime import datetime
11
+ from pathlib import Path
12
+
13
+ # ── Paths ────────────────────────────────────────────────────────────────────
14
+
15
+ ROOT_DIR = Path(__file__).resolve().parent.parent
16
+ SCRIPTS_DIR = ROOT_DIR / "scripts"
17
+ DATA_DIR = ROOT_DIR / "data"
18
+ OUTPUT_DIR = DATA_DIR / "outputs"
19
+ OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
20
+
21
+ # ── API ──────────────────────────────────────────────────────────────────────
22
+
23
+ API_BASE = "https://api.stability.ai/v2beta"
24
+ USER_AGENT = "StabilityAI-Skill/2.0"
25
+
26
+ ENDPOINTS = {
27
+ "generate_sd3": "/stable-image/generate/sd3",
28
+ "generate_ultra": "/stable-image/generate/ultra",
29
+ "generate_core": "/stable-image/generate/core",
30
+ "upscale_conservative": "/stable-image/upscale/conservative",
31
+ "upscale_creative": "/stable-image/upscale/creative",
32
+ "remove_bg": "/stable-image/edit/remove-background",
33
+ "inpaint": "/stable-image/edit/inpaint",
34
+ "search_replace": "/stable-image/edit/search-and-replace",
35
+ "erase": "/stable-image/edit/erase",
36
+ "outpaint": "/stable-image/edit/outpaint",
37
+ }
38
+
39
+ # ── Modelos ──────────────────────────────────────────────────────────────────
40
+
41
+ MODELS = {
42
+ "sd3.5-large": {
43
+ "id": "sd3.5-large",
44
+ "name": "Stable Diffusion 3.5 Large",
45
+ "endpoint": "generate_sd3",
46
+ "description": "Melhor qualidade geral. Recomendado para a maioria dos usos.",
47
+ "cost": "free",
48
+ },
49
+ "sd3.5-large-turbo": {
50
+ "id": "sd3.5-large-turbo",
51
+ "name": "SD 3.5 Large Turbo",
52
+ "endpoint": "generate_sd3",
53
+ "description": "Versao rapida do SD 3.5. Menos passos, resultado bom.",
54
+ "cost": "free",
55
+ },
56
+ "sd3.5-medium": {
57
+ "id": "sd3.5-medium",
58
+ "name": "SD 3.5 Medium",
59
+ "endpoint": "generate_sd3",
60
+ "description": "Balanco entre velocidade e qualidade.",
61
+ "cost": "free",
62
+ },
63
+ "ultra": {
64
+ "id": "ultra",
65
+ "name": "Stable Image Ultra",
66
+ "endpoint": "generate_ultra",
67
+ "description": "Maxima qualidade. Fotorrealismo e detalhes extremos.",
68
+ "cost": "free",
69
+ },
70
+ "core": {
71
+ "id": "core",
72
+ "name": "Stable Image Core",
73
+ "endpoint": "generate_core",
74
+ "description": "Rapido e eficiente. Bom para iteracao.",
75
+ "cost": "free",
76
+ },
77
+ }
78
+
79
+ DEFAULT_MODEL = "sd3.5-large"
80
+
81
+ # ── Aspect Ratios ────────────────────────────────────────────────────────────
82
+
83
+ ASPECT_RATIOS = {
84
+ "square": "1:1",
85
+ "portrait": "2:3",
86
+ "landscape": "3:2",
87
+ "wide": "16:9",
88
+ "ultrawide": "21:9",
89
+ "stories": "9:16",
90
+ "phone": "9:21",
91
+ "photo": "4:5",
92
+ "cinema": "5:4",
93
+ }
94
+
95
+ ASPECT_ALIASES = {
96
+ # Valores diretos
97
+ "1:1": "1:1", "2:3": "2:3", "3:2": "3:2", "16:9": "16:9",
98
+ "21:9": "21:9", "9:16": "9:16", "9:21": "9:21", "4:5": "4:5", "5:4": "5:4",
99
+ # Portugues
100
+ "quadrado": "1:1", "retrato": "2:3", "paisagem": "3:2",
101
+ "widescreen": "16:9", "vertical": "9:16", "horizontal": "3:2",
102
+ # Plataformas
103
+ "ig": "1:1", "instagram": "1:1", "ig-feed": "4:5", "ig-stories": "9:16",
104
+ "youtube": "16:9", "yt": "16:9", "tiktok": "9:16", "reels": "9:16",
105
+ "twitter": "16:9", "x": "16:9", "facebook": "16:9", "fb": "16:9",
106
+ "pinterest": "2:3", "linkedin": "16:9",
107
+ "wallpaper": "16:9", "desktop": "16:9", "mobile": "9:16",
108
+ }
109
+
110
+ DEFAULT_ASPECT_RATIO = "1:1"
111
+
112
+ # ── MIME Types ───────────────────────────────────────────────────────────────
113
+
114
+ MIME_MAP = {
115
+ ".png": "image/png",
116
+ ".jpg": "image/jpeg",
117
+ ".jpeg": "image/jpeg",
118
+ ".webp": "image/webp",
119
+ ".gif": "image/gif",
120
+ ".bmp": "image/bmp",
121
+ ".tiff": "image/tiff",
122
+ ".tif": "image/tiff",
123
+ }
124
+
125
+ # ── Output ───────────────────────────────────────────────────────────────────
126
+
127
+ OUTPUT_SETTINGS = {
128
+ "format": "png",
129
+ "save_metadata": True,
130
+ "save_prompt": True,
131
+ }
132
+
133
+ # ── Limites de Seguranca ─────────────────────────────────────────────────────
134
+
135
+ SAFETY_MAX_IMAGES_PER_DAY = int(os.environ.get("SAFETY_MAX_IMAGES_PER_DAY", "100"))
136
+
137
+
138
+ # ── Funcoes ──────────────────────────────────────────────────────────────────
139
+
140
+
141
+ def _parse_env_file(env_path: Path) -> dict[str, str]:
142
+ """Parse arquivo .env e retorna dict chave=valor."""
143
+ result: dict[str, str] = {}
144
+ if not env_path.exists():
145
+ return result
146
+ try:
147
+ for line in env_path.read_text(encoding="utf-8").splitlines():
148
+ line = line.strip()
149
+ if not line or line.startswith("#"):
150
+ continue
151
+ if "=" in line:
152
+ k, v = line.split("=", 1)
153
+ k = k.strip()
154
+ v = v.strip().strip('"').strip("'")
155
+ if k and v:
156
+ result[k] = v
157
+ except (OSError, UnicodeDecodeError):
158
+ pass
159
+ return result
160
+
161
+
162
+ def get_api_key() -> str | None:
163
+ """Busca a API key em ordem: env var > .env na skill."""
164
+ key = os.environ.get("STABILITY_API_KEY")
165
+ if key:
166
+ return key
167
+
168
+ env_data = _parse_env_file(ROOT_DIR / ".env")
169
+ return env_data.get("STABILITY_API_KEY")
170
+
171
+
172
+ def get_all_api_keys() -> list[str]:
173
+ """Retorna todas as API keys (primaria + backups)."""
174
+ keys: list[str] = []
175
+ primary = get_api_key()
176
+ if primary:
177
+ keys.append(primary)
178
+
179
+ env_data = _parse_env_file(ROOT_DIR / ".env")
180
+ for k, v in env_data.items():
181
+ if k.startswith("STABILITY_API_KEY_BACKUP") and v and v not in keys:
182
+ keys.append(v)
183
+
184
+ return keys
185
+
186
+
187
+ def resolve_aspect_ratio(name: str) -> str:
188
+ """Resolve nome ou alias para aspect ratio valido."""
189
+ name_lower = name.lower().strip()
190
+ if name_lower in ASPECT_RATIOS:
191
+ return ASPECT_RATIOS[name_lower]
192
+ if name_lower in ASPECT_ALIASES:
193
+ return ASPECT_ALIASES[name_lower]
194
+ if ":" in name and all(p.isdigit() for p in name.split(":")):
195
+ return name
196
+ return DEFAULT_ASPECT_RATIO
197
+
198
+
199
+ def get_mime_type(filepath: Path) -> str:
200
+ """Retorna MIME type baseado na extensao do arquivo."""
201
+ return MIME_MAP.get(filepath.suffix.lower(), "image/png")
202
+
203
+
204
+ def safety_check_daily_limit(num_images: int = 1) -> tuple[bool, str]:
205
+ """Verifica se nao excedeu limite diario."""
206
+ today = datetime.now().strftime("%Y-%m-%d")
207
+ counter_file = DATA_DIR / "daily_counter.json"
208
+
209
+ count = 0
210
+ if counter_file.exists():
211
+ try:
212
+ data = json.loads(counter_file.read_text(encoding="utf-8"))
213
+ if data.get("date") == today:
214
+ count = data.get("count", 0)
215
+ except (json.JSONDecodeError, KeyError, OSError):
216
+ pass
217
+
218
+ if count + num_images > SAFETY_MAX_IMAGES_PER_DAY:
219
+ return False, (
220
+ f"LIMITE DIARIO: {count}/{SAFETY_MAX_IMAGES_PER_DAY} imagens hoje. "
221
+ f"Tentando gerar {num_images} mais. "
222
+ f"Configure SAFETY_MAX_IMAGES_PER_DAY para ajustar."
223
+ )
224
+
225
+ return True, f"OK: {count}/{SAFETY_MAX_IMAGES_PER_DAY} imagens hoje."
226
+
227
+
228
+ def increment_daily_counter(num_images: int = 1) -> None:
229
+ """Incrementa o contador diario de forma segura."""
230
+ today = datetime.now().strftime("%Y-%m-%d")
231
+ counter_file = DATA_DIR / "daily_counter.json"
232
+
233
+ count = 0
234
+ if counter_file.exists():
235
+ try:
236
+ data = json.loads(counter_file.read_text(encoding="utf-8"))
237
+ if data.get("date") == today:
238
+ count = data.get("count", 0)
239
+ except (json.JSONDecodeError, KeyError, OSError):
240
+ pass
241
+
242
+ try:
243
+ counter_file.parent.mkdir(parents=True, exist_ok=True)
244
+ counter_file.write_text(
245
+ json.dumps({"date": today, "count": count + num_images}, indent=2),
246
+ encoding="utf-8",
247
+ )
248
+ except OSError:
249
+ pass # Falha silenciosa no contador nao deve bloquear geracao
250
+
251
+
252
+ def validate_image_file(filepath: str | Path) -> Path:
253
+ """Valida que o arquivo de imagem existe e tem extensao suportada."""
254
+ path = Path(filepath)
255
+ if not path.exists():
256
+ raise FileNotFoundError(f"Arquivo nao encontrado: {path}")
257
+ if not path.is_file():
258
+ raise ValueError(f"Nao e um arquivo: {path}")
259
+ if path.suffix.lower() not in MIME_MAP:
260
+ supported = ", ".join(MIME_MAP.keys())
261
+ raise ValueError(f"Formato nao suportado: {path.suffix}. Suportados: {supported}")
262
+ if path.stat().st_size == 0:
263
+ raise ValueError(f"Arquivo vazio: {path}")
264
+ if path.stat().st_size > 50 * 1024 * 1024: # 50MB
265
+ raise ValueError(f"Arquivo muito grande ({path.stat().st_size / 1024 / 1024:.1f}MB). Max: 50MB")
266
+ return path