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,233 @@
1
+ """
2
+ Governança: rate limiting, audit log e confirmações para ações do Instagram.
3
+
4
+ Rate limits são rastreados via SQLite (action_log table).
5
+ Confirmações usam padrão 2-step: retorna JSON com requires_confirmation,
6
+ Claude apresenta ao usuário, e na segunda chamada com --confirm executa.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import uuid
12
+ from datetime import datetime, timezone
13
+ from typing import Any, Dict, Optional
14
+
15
+ from config import (
16
+ ACTION_CATEGORIES,
17
+ RATE_LIMIT_DMS_PER_HOUR,
18
+ RATE_LIMIT_HASHTAGS_PER_WEEK,
19
+ RATE_LIMIT_PUBLISHES_PER_DAY,
20
+ RATE_LIMIT_REQUESTS_PER_HOUR,
21
+ RATE_LIMIT_WARNING_THRESHOLD,
22
+ )
23
+ from db import Database
24
+
25
+
26
+ class RateLimitExceeded(Exception):
27
+ """Limite de taxa excedido."""
28
+
29
+ def __init__(self, limit_type: str, current: int, maximum: int, retry_after_seconds: int):
30
+ self.limit_type = limit_type
31
+ self.current = current
32
+ self.maximum = maximum
33
+ self.retry_after_seconds = retry_after_seconds
34
+ super().__init__(
35
+ f"Rate limit '{limit_type}' excedido: {current}/{maximum}. "
36
+ f"Tente novamente em {retry_after_seconds}s."
37
+ )
38
+
39
+ def to_dict(self) -> Dict[str, Any]:
40
+ return {
41
+ "error": "rate_limit_exceeded",
42
+ "limit_type": self.limit_type,
43
+ "current": self.current,
44
+ "maximum": self.maximum,
45
+ "retry_after_seconds": self.retry_after_seconds,
46
+ }
47
+
48
+
49
+ class GovernanceManager:
50
+ """Gerencia rate limits, logging e confirmações."""
51
+
52
+ def __init__(self, db: Optional[Database] = None):
53
+ self.db = db or Database()
54
+ self.db.init()
55
+
56
+ # ── Rate Limiting ─────────────────────────────────────────────────────────
57
+
58
+ def check_rate_limit(self, action: str, account_id: Optional[int] = None) -> Dict[str, Any]:
59
+ """
60
+ Verifica rate limits antes de uma ação.
61
+ Retorna dict com remaining e warnings.
62
+ Raises RateLimitExceeded se o limite foi atingido.
63
+ """
64
+ requests_used = self.db.count_requests_last_hour()
65
+ publishes_used = self.db.count_publishes_today()
66
+
67
+ result = {
68
+ "requests": {
69
+ "used": requests_used,
70
+ "limit": RATE_LIMIT_REQUESTS_PER_HOUR,
71
+ "remaining": RATE_LIMIT_REQUESTS_PER_HOUR - requests_used,
72
+ },
73
+ "publishes": {
74
+ "used": publishes_used,
75
+ "limit": RATE_LIMIT_PUBLISHES_PER_DAY,
76
+ "remaining": RATE_LIMIT_PUBLISHES_PER_DAY - publishes_used,
77
+ },
78
+ "warnings": [],
79
+ }
80
+
81
+ # Verificar limite de requests
82
+ if requests_used >= RATE_LIMIT_REQUESTS_PER_HOUR:
83
+ raise RateLimitExceeded(
84
+ "requests_per_hour", requests_used,
85
+ RATE_LIMIT_REQUESTS_PER_HOUR, 3600,
86
+ )
87
+
88
+ # Verificar limite de publicações
89
+ if action.startswith("publish_") and publishes_used >= RATE_LIMIT_PUBLISHES_PER_DAY:
90
+ raise RateLimitExceeded(
91
+ "publishes_per_day", publishes_used,
92
+ RATE_LIMIT_PUBLISHES_PER_DAY, 86400,
93
+ )
94
+
95
+ # Verificar limite de hashtags
96
+ if action == "search_hashtag" and account_id:
97
+ hashtag_count = self.db.count_hashtag_searches_last_week(account_id)
98
+ result["hashtags"] = {
99
+ "used": hashtag_count,
100
+ "limit": RATE_LIMIT_HASHTAGS_PER_WEEK,
101
+ "remaining": RATE_LIMIT_HASHTAGS_PER_WEEK - hashtag_count,
102
+ }
103
+ if hashtag_count >= RATE_LIMIT_HASHTAGS_PER_WEEK:
104
+ raise RateLimitExceeded(
105
+ "hashtags_per_week", hashtag_count,
106
+ RATE_LIMIT_HASHTAGS_PER_WEEK, 604800,
107
+ )
108
+
109
+ # Warnings em 90% do limite
110
+ if requests_used >= RATE_LIMIT_REQUESTS_PER_HOUR * RATE_LIMIT_WARNING_THRESHOLD:
111
+ result["warnings"].append(
112
+ f"Atenção: {requests_used}/{RATE_LIMIT_REQUESTS_PER_HOUR} requests na última hora"
113
+ )
114
+ if publishes_used >= RATE_LIMIT_PUBLISHES_PER_DAY * RATE_LIMIT_WARNING_THRESHOLD:
115
+ result["warnings"].append(
116
+ f"Atenção: {publishes_used}/{RATE_LIMIT_PUBLISHES_PER_DAY} publicações hoje"
117
+ )
118
+
119
+ return result
120
+
121
+ def get_rate_status(self) -> Dict[str, Any]:
122
+ """Retorna status atual de todos os rate limits."""
123
+ return {
124
+ "requests_per_hour": {
125
+ "used": self.db.count_requests_last_hour(),
126
+ "limit": RATE_LIMIT_REQUESTS_PER_HOUR,
127
+ },
128
+ "publishes_per_day": {
129
+ "used": self.db.count_publishes_today(),
130
+ "limit": RATE_LIMIT_PUBLISHES_PER_DAY,
131
+ },
132
+ }
133
+
134
+ # ── Action Logging ────────────────────────────────────────────────────────
135
+
136
+ def log_action(
137
+ self,
138
+ action: str,
139
+ params: Optional[Dict] = None,
140
+ result: Optional[Dict] = None,
141
+ confirmed: bool = True,
142
+ account_id: Optional[int] = None,
143
+ ) -> None:
144
+ """Registra uma ação no audit log."""
145
+ rate_status = self.get_rate_status()
146
+ self.db.log_action({
147
+ "account_id": account_id,
148
+ "action": action,
149
+ "params": json.dumps(params, ensure_ascii=False) if params else None,
150
+ "result": json.dumps(result, ensure_ascii=False) if result else None,
151
+ "confirmed": 1 if confirmed else 0,
152
+ "rate_remaining": json.dumps(rate_status),
153
+ })
154
+
155
+ # ── Confirmation ──────────────────────────────────────────────────────────
156
+
157
+ def requires_confirmation(self, action: str) -> bool:
158
+ """Verifica se uma ação requer confirmação do usuário."""
159
+ for category in ("ENGAGE", "PUBLISH", "DELETE", "MESSAGE"):
160
+ if action in ACTION_CATEGORIES.get(category, []):
161
+ return True
162
+ return False
163
+
164
+ def get_confirmation_category(self, action: str) -> str:
165
+ """Retorna a categoria de confirmação de uma ação."""
166
+ for category, actions in ACTION_CATEGORIES.items():
167
+ if action in actions:
168
+ return category
169
+ return "READ"
170
+
171
+ def create_confirmation_request(
172
+ self,
173
+ action: str,
174
+ details: Dict[str, Any],
175
+ account_id: Optional[int] = None,
176
+ ) -> Dict[str, Any]:
177
+ """
178
+ Cria um pedido de confirmação para o Claude apresentar ao usuário.
179
+ Retorna JSON estruturado com action_id para confirmar depois.
180
+ """
181
+ action_id = str(uuid.uuid4())[:8]
182
+ rate_status = self.get_rate_status()
183
+
184
+ return {
185
+ "requires_confirmation": True,
186
+ "action_id": action_id,
187
+ "action": action,
188
+ "category": self.get_confirmation_category(action),
189
+ "details": details,
190
+ "rate_limits": rate_status,
191
+ "message": self._format_confirmation_message(action, details, rate_status),
192
+ }
193
+
194
+ def _format_confirmation_message(
195
+ self, action: str, details: Dict[str, Any], rate_status: Dict[str, Any],
196
+ ) -> str:
197
+ """Formata mensagem de confirmação legível."""
198
+ category = self.get_confirmation_category(action)
199
+ action_names = {
200
+ "publish_photo": "PUBLICAR uma foto",
201
+ "publish_video": "PUBLICAR um vídeo",
202
+ "publish_reel": "PUBLICAR um reel",
203
+ "publish_story": "PUBLICAR um story",
204
+ "publish_carousel": "PUBLICAR um carrossel",
205
+ "schedule_post": "AGENDAR uma publicação",
206
+ "reply_comment": "RESPONDER a um comentário",
207
+ "delete_comment": "DELETAR um comentário",
208
+ "hide_comment": "OCULTAR um comentário",
209
+ "send_dm": "ENVIAR uma mensagem direta",
210
+ }
211
+ action_desc = action_names.get(action, action)
212
+
213
+ lines = [f"[CONFIRMAÇÃO] Prestes a {action_desc}:"]
214
+ for key, value in details.items():
215
+ if value is not None:
216
+ lines.append(f" {key}: {value}")
217
+
218
+ req = rate_status["requests_per_hour"]
219
+ pub = rate_status["publishes_per_day"]
220
+ lines.append(f"\n Rate limits: {req['used']}/{req['limit']} requests/hr, "
221
+ f"{pub['used']}/{pub['limit']} publicações/dia")
222
+
223
+ return "\n".join(lines)
224
+
225
+
226
+ # ── CLI para verificação ─────────────────────────────────────────────────────
227
+ if __name__ == "__main__":
228
+ gov = GovernanceManager()
229
+ status = gov.get_rate_status()
230
+ print(json.dumps(status, indent=2))
231
+ print("\nÚltimas ações:")
232
+ for a in gov.db.get_recent_actions(10):
233
+ print(f" [{a['created_at']}] {a['action']}")
@@ -0,0 +1,114 @@
1
+ """
2
+ Pesquisa e tracking de hashtags do Instagram.
3
+
4
+ Uso:
5
+ python scripts/hashtags.py --search "artificialintelligence" --limit 25
6
+ python scripts/hashtags.py --top "tecnologia"
7
+ python scripts/hashtags.py --info "marketing"
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import asyncio
13
+ import json
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ sys.path.insert(0, str(Path(__file__).parent))
18
+
19
+ from api_client import InstagramAPI
20
+ from auth import auto_refresh_if_needed
21
+ from db import Database
22
+ from governance import GovernanceManager, RateLimitExceeded
23
+
24
+ db = Database()
25
+ db.init()
26
+ gov = GovernanceManager(db)
27
+
28
+
29
+ async def search_hashtag(hashtag: str, limit: int = 25, mode: str = "recent") -> None:
30
+ """Busca posts com uma hashtag."""
31
+ await auto_refresh_if_needed()
32
+
33
+ account = db.get_active_account()
34
+ if not account:
35
+ print(json.dumps({"error": "Nenhuma conta configurada"}, indent=2))
36
+ return
37
+
38
+ # Verificar rate limit de hashtags
39
+ try:
40
+ gov.check_rate_limit("search_hashtag", account["id"])
41
+ except RateLimitExceeded as e:
42
+ print(json.dumps(e.to_dict(), indent=2))
43
+ return
44
+
45
+ api = InstagramAPI()
46
+
47
+ # Step 1: Buscar ID da hashtag
48
+ search_result = await api.search_hashtag(hashtag)
49
+ hashtag_data = search_result.get("data", [])
50
+ if not hashtag_data:
51
+ print(json.dumps({"error": f"Hashtag '{hashtag}' não encontrada"}, indent=2))
52
+ await api.close()
53
+ return
54
+
55
+ hashtag_id = hashtag_data[0]["id"]
56
+
57
+ # Registrar busca
58
+ db.insert_hashtag_search({
59
+ "account_id": account["id"],
60
+ "hashtag": hashtag,
61
+ "ig_hashtag_id": hashtag_id,
62
+ })
63
+
64
+ # Step 2: Buscar posts
65
+ if mode == "top":
66
+ result = await api.get_hashtag_top_media(hashtag_id, limit=limit)
67
+ else:
68
+ result = await api.get_hashtag_recent_media(hashtag_id, limit=limit)
69
+
70
+ await api.close()
71
+
72
+ # Contagem de buscas na semana
73
+ weekly_count = db.count_hashtag_searches_last_week(account["id"])
74
+
75
+ output = {
76
+ "hashtag": hashtag,
77
+ "hashtag_id": hashtag_id,
78
+ "mode": mode,
79
+ "results": result.get("data", []),
80
+ "total": len(result.get("data", [])),
81
+ "hashtag_searches_this_week": weekly_count,
82
+ "hashtag_searches_limit": 30,
83
+ }
84
+ print(json.dumps(output, indent=2, ensure_ascii=False))
85
+
86
+
87
+ async def hashtag_info(hashtag: str) -> None:
88
+ """Info de uma hashtag (apenas o ID — media_count requer permissões especiais)."""
89
+ await auto_refresh_if_needed()
90
+ api = InstagramAPI()
91
+ result = await api.search_hashtag(hashtag)
92
+ await api.close()
93
+ print(json.dumps({"hashtag": hashtag, "data": result.get("data", [])}, indent=2, ensure_ascii=False))
94
+
95
+
96
+ def main():
97
+ parser = argparse.ArgumentParser(description="Hashtags do Instagram")
98
+ group = parser.add_mutually_exclusive_group(required=True)
99
+ group.add_argument("--search", metavar="TAG", help="Buscar posts recentes com hashtag")
100
+ group.add_argument("--top", metavar="TAG", help="Top posts de uma hashtag")
101
+ group.add_argument("--info", metavar="TAG", help="Info da hashtag")
102
+ parser.add_argument("--limit", type=int, default=25, help="Limite de resultados")
103
+ args = parser.parse_args()
104
+
105
+ if args.search:
106
+ asyncio.run(search_hashtag(args.search, args.limit, mode="recent"))
107
+ elif args.top:
108
+ asyncio.run(search_hashtag(args.top, args.limit, mode="top"))
109
+ elif args.info:
110
+ asyncio.run(hashtag_info(args.info))
111
+
112
+
113
+ if __name__ == "__main__":
114
+ main()
@@ -0,0 +1,170 @@
1
+ """
2
+ Analytics e insights do Instagram.
3
+
4
+ Uso:
5
+ python scripts/insights.py --media --media-id 12345
6
+ python scripts/insights.py --user --period day --since 7
7
+ python scripts/insights.py --fetch-all --limit 20
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import asyncio
13
+ import json
14
+ import sys
15
+ from datetime import datetime, timedelta, timezone
16
+ from pathlib import Path
17
+
18
+ sys.path.insert(0, str(Path(__file__).parent))
19
+
20
+ from api_client import InstagramAPI
21
+ from auth import auto_refresh_if_needed
22
+ from db import Database
23
+
24
+ db = Database()
25
+ db.init()
26
+
27
+
28
+ async def media_insights(media_id: str, metrics: list = None) -> None:
29
+ """Busca insights de um post específico."""
30
+ await auto_refresh_if_needed()
31
+ api = InstagramAPI()
32
+ try:
33
+ result = await api.get_media_insights(media_id, metrics=metrics)
34
+ except Exception as e:
35
+ print(json.dumps({"error": str(e), "media_id": media_id}, indent=2))
36
+ await api.close()
37
+ return
38
+
39
+ # Salvar no banco
40
+ account = db.get_active_account()
41
+ if account:
42
+ raw = json.dumps(result, ensure_ascii=False)
43
+ for item in result.get("data", []):
44
+ values = item.get("values", [{}])
45
+ value = values[0].get("value", 0) if values else 0
46
+ db.insert_insights([{
47
+ "account_id": account["id"],
48
+ "ig_media_id": media_id,
49
+ "metric_name": item.get("name", ""),
50
+ "metric_value": float(value) if isinstance(value, (int, float)) else 0,
51
+ "period": item.get("period", ""),
52
+ "raw_json": raw,
53
+ }])
54
+
55
+ await api.close()
56
+ print(json.dumps(result, indent=2, ensure_ascii=False))
57
+
58
+
59
+ async def user_insights(period: str = "day", since_days: int = 7, metrics: list = None) -> None:
60
+ """Busca insights da conta."""
61
+ await auto_refresh_if_needed()
62
+ api = InstagramAPI()
63
+
64
+ now = datetime.now(timezone.utc)
65
+ since = (now - timedelta(days=since_days)).strftime("%Y-%m-%d")
66
+ until = now.strftime("%Y-%m-%d")
67
+
68
+ result = await api.get_user_insights(
69
+ period=period,
70
+ metrics=metrics,
71
+ since=since,
72
+ until=until,
73
+ )
74
+
75
+ # Salvar no banco
76
+ account = db.get_active_account()
77
+ if account:
78
+ for item in result.get("data", []):
79
+ for value_entry in item.get("values", []):
80
+ db.insert_user_insights([{
81
+ "account_id": account["id"],
82
+ "metric_name": item.get("name", ""),
83
+ "metric_value": float(value_entry.get("value", 0)),
84
+ "period": period,
85
+ "end_time": value_entry.get("end_time", ""),
86
+ }])
87
+
88
+ await api.close()
89
+ print(json.dumps(result, indent=2, ensure_ascii=False))
90
+
91
+
92
+ async def fetch_all_insights(limit: int = 20) -> None:
93
+ """Busca insights de todos os posts recentes."""
94
+ await auto_refresh_if_needed()
95
+ api = InstagramAPI()
96
+
97
+ media_result = await api.get_user_media(limit=limit)
98
+ media_list = media_result.get("data", [])
99
+
100
+ results = []
101
+ for media in media_list:
102
+ media_id = media["id"]
103
+ media_type = media.get("media_type", "IMAGE")
104
+ try:
105
+ # Métricas variam por tipo
106
+ metrics = ["impressions", "reach", "engagement", "saved"]
107
+ if media_type == "VIDEO":
108
+ metrics.append("video_views")
109
+ if media_type == "REELS" or "reel" in media.get("permalink", "").lower():
110
+ metrics = ["impressions", "reach", "likes", "comments", "saves", "shares", "plays"]
111
+
112
+ insights = await api.get_media_insights(media_id, metrics=metrics)
113
+
114
+ # Salvar
115
+ account = db.get_active_account()
116
+ if account:
117
+ raw = json.dumps(insights, ensure_ascii=False)
118
+ for item in insights.get("data", []):
119
+ values = item.get("values", [{}])
120
+ value = values[0].get("value", 0) if values else 0
121
+ db.insert_insights([{
122
+ "account_id": account["id"],
123
+ "ig_media_id": media_id,
124
+ "metric_name": item.get("name", ""),
125
+ "metric_value": float(value) if isinstance(value, (int, float)) else 0,
126
+ "period": item.get("period", ""),
127
+ "raw_json": raw,
128
+ }])
129
+
130
+ results.append({
131
+ "media_id": media_id,
132
+ "type": media_type,
133
+ "caption": (media.get("caption", "") or "")[:50],
134
+ "metrics": {
135
+ d["name"]: d["values"][0]["value"] if d.get("values") else 0
136
+ for d in insights.get("data", [])
137
+ },
138
+ })
139
+ except Exception as e:
140
+ results.append({"media_id": media_id, "error": str(e)})
141
+
142
+ await api.close()
143
+ print(json.dumps({"fetched": len(results), "insights": results}, indent=2, ensure_ascii=False))
144
+
145
+
146
+ def main():
147
+ parser = argparse.ArgumentParser(description="Insights do Instagram")
148
+ group = parser.add_mutually_exclusive_group(required=True)
149
+ group.add_argument("--media", action="store_true", help="Insights de um post")
150
+ group.add_argument("--user", action="store_true", help="Insights da conta")
151
+ group.add_argument("--fetch-all", action="store_true", help="Buscar insights de todos os posts recentes")
152
+ parser.add_argument("--media-id", help="ID da mídia")
153
+ parser.add_argument("--period", default="day", choices=["day", "week", "days_28", "month", "lifetime"])
154
+ parser.add_argument("--since", type=int, default=7, help="Dias atrás (default: 7)")
155
+ parser.add_argument("--metrics", nargs="+", help="Métricas específicas")
156
+ parser.add_argument("--limit", type=int, default=20, help="Limite de posts para --fetch-all")
157
+ args = parser.parse_args()
158
+
159
+ if args.media:
160
+ if not args.media_id:
161
+ parser.error("--media-id é obrigatório com --media")
162
+ asyncio.run(media_insights(args.media_id, args.metrics))
163
+ elif args.user:
164
+ asyncio.run(user_insights(args.period, args.since, args.metrics))
165
+ elif args.fetch_all:
166
+ asyncio.run(fetch_all_insights(args.limit))
167
+
168
+
169
+ if __name__ == "__main__":
170
+ main()
@@ -0,0 +1,65 @@
1
+ """
2
+ Listagem e detalhes de mídia do Instagram.
3
+
4
+ Uso:
5
+ python scripts/media.py --list [--limit 10]
6
+ python scripts/media.py --details --media-id 12345
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import asyncio
12
+ import json
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ sys.path.insert(0, str(Path(__file__).parent))
17
+
18
+ from api_client import InstagramAPI
19
+ from auth import auto_refresh_if_needed
20
+
21
+
22
+ async def list_media(limit: int = 25, after: str = None) -> None:
23
+ """Lista mídia do usuário."""
24
+ await auto_refresh_if_needed()
25
+ api = InstagramAPI()
26
+ result = await api.get_user_media(limit=limit, after=after)
27
+ await api.close()
28
+
29
+ data = result.get("data", [])
30
+ print(json.dumps({
31
+ "total": len(data),
32
+ "media": data,
33
+ "paging": result.get("paging", {}),
34
+ }, indent=2, ensure_ascii=False))
35
+
36
+
37
+ async def media_details(media_id: str) -> None:
38
+ """Detalhes de uma mídia específica."""
39
+ await auto_refresh_if_needed()
40
+ api = InstagramAPI()
41
+ result = await api.get_media_details(media_id)
42
+ await api.close()
43
+ print(json.dumps(result, indent=2, ensure_ascii=False))
44
+
45
+
46
+ def main():
47
+ parser = argparse.ArgumentParser(description="Mídia do Instagram")
48
+ group = parser.add_mutually_exclusive_group(required=True)
49
+ group.add_argument("--list", action="store_true", help="Listar mídia")
50
+ group.add_argument("--details", action="store_true", help="Detalhes de uma mídia")
51
+ parser.add_argument("--limit", type=int, default=25, help="Limite de resultados")
52
+ parser.add_argument("--media-id", help="ID da mídia")
53
+ parser.add_argument("--after", help="Cursor de paginação")
54
+ args = parser.parse_args()
55
+
56
+ if args.list:
57
+ asyncio.run(list_media(args.limit, args.after))
58
+ elif args.details:
59
+ if not args.media_id:
60
+ parser.error("--media-id é obrigatório com --details")
61
+ asyncio.run(media_details(args.media_id))
62
+
63
+
64
+ if __name__ == "__main__":
65
+ main()
@@ -0,0 +1,103 @@
1
+ """
2
+ Mensagens diretas do Instagram (DMs).
3
+
4
+ Uso:
5
+ python scripts/messages.py --send --user-id 12345 --text "Olá!"
6
+ python scripts/messages.py --conversations
7
+ python scripts/messages.py --thread --conversation-id 12345
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import asyncio
13
+ import json
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ sys.path.insert(0, str(Path(__file__).parent))
18
+
19
+ from api_client import InstagramAPI
20
+ from auth import auto_refresh_if_needed
21
+ from db import Database
22
+ from governance import GovernanceManager
23
+
24
+ db = Database()
25
+ db.init()
26
+ gov = GovernanceManager(db)
27
+
28
+
29
+ async def send_message(user_id: str, text: str) -> None:
30
+ """Envia DM para um usuário."""
31
+ await auto_refresh_if_needed()
32
+
33
+ if gov.requires_confirmation("send_dm"):
34
+ result = gov.create_confirmation_request(
35
+ "send_dm",
36
+ {"recipient_id": user_id, "text": text},
37
+ )
38
+ print(json.dumps(result, indent=2, ensure_ascii=False))
39
+ return
40
+
41
+ api = InstagramAPI()
42
+ result = await api.send_message(user_id, text)
43
+ await api.close()
44
+
45
+ account = db.get_active_account()
46
+ gov.log_action(
47
+ "send_dm",
48
+ params={"recipient_id": user_id, "text": text},
49
+ result=result,
50
+ account_id=account["id"] if account else None,
51
+ )
52
+
53
+ print(json.dumps({"status": "sent", "result": result}, indent=2, ensure_ascii=False))
54
+
55
+
56
+ async def list_conversations(limit: int = 20) -> None:
57
+ """Lista conversas recentes."""
58
+ await auto_refresh_if_needed()
59
+ api = InstagramAPI()
60
+ result = await api.get_conversations(limit=limit)
61
+ await api.close()
62
+ print(json.dumps(result, indent=2, ensure_ascii=False))
63
+
64
+
65
+ async def show_thread(conversation_id: str) -> None:
66
+ """Mostra mensagens de uma conversa."""
67
+ await auto_refresh_if_needed()
68
+ api = InstagramAPI()
69
+ result = await api.get(
70
+ f"{conversation_id}/messages",
71
+ params={"fields": "id,message,from,created_time"},
72
+ action="get_thread",
73
+ )
74
+ await api.close()
75
+ print(json.dumps(result, indent=2, ensure_ascii=False))
76
+
77
+
78
+ def main():
79
+ parser = argparse.ArgumentParser(description="DMs do Instagram")
80
+ group = parser.add_mutually_exclusive_group(required=True)
81
+ group.add_argument("--send", action="store_true", help="Enviar DM")
82
+ group.add_argument("--conversations", action="store_true", help="Listar conversas")
83
+ group.add_argument("--thread", action="store_true", help="Ver mensagens de uma conversa")
84
+ parser.add_argument("--user-id", help="ID do destinatário")
85
+ parser.add_argument("--text", help="Texto da mensagem")
86
+ parser.add_argument("--conversation-id", help="ID da conversa")
87
+ parser.add_argument("--limit", type=int, default=20, help="Limite")
88
+ args = parser.parse_args()
89
+
90
+ if args.send:
91
+ if not args.user_id or not args.text:
92
+ parser.error("--user-id e --text são obrigatórios com --send")
93
+ asyncio.run(send_message(args.user_id, args.text))
94
+ elif args.conversations:
95
+ asyncio.run(list_conversations(args.limit))
96
+ elif args.thread:
97
+ if not args.conversation_id:
98
+ parser.error("--conversation-id é obrigatório com --thread")
99
+ asyncio.run(show_thread(args.conversation_id))
100
+
101
+
102
+ if __name__ == "__main__":
103
+ main()