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,411 @@
1
+ """
2
+ Autenticação OAuth 2.0 para Instagram Graph API.
3
+
4
+ Uso:
5
+ python scripts/auth.py --setup # Configuração inicial completa
6
+ python scripts/auth.py --refresh # Renovar token
7
+ python scripts/auth.py --status # Ver status do token
8
+ python scripts/auth.py --revoke # Revogar token
9
+
10
+ O fluxo:
11
+ 1. Usuário fornece App ID e App Secret (do Facebook Developer Console)
12
+ 2. Script abre browser para autorização OAuth
13
+ 3. Servidor local (localhost:8765) captura o redirect com o code
14
+ 4. Troca code por token curto (1hr) → token longo (60 dias)
15
+ 5. Descobre Instagram User ID via Facebook Pages
16
+ 6. Salva tudo no banco SQLite (accounts table)
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import argparse
21
+ import asyncio
22
+ import json
23
+ import os
24
+ import sys
25
+ import webbrowser
26
+ from datetime import datetime, timedelta, timezone
27
+ from http.server import HTTPServer, BaseHTTPRequestHandler
28
+ from pathlib import Path
29
+ from typing import Optional
30
+ from urllib.parse import parse_qs, urlparse
31
+
32
+ sys.path.insert(0, str(Path(__file__).parent))
33
+
34
+ import httpx
35
+
36
+ from config import (
37
+ GRAPH_API_BASE,
38
+ OAUTH_AUTHORIZE_URL,
39
+ OAUTH_REDIRECT_PORT,
40
+ OAUTH_REDIRECT_URI,
41
+ OAUTH_SCOPES,
42
+ OAUTH_TOKEN_URL,
43
+ )
44
+ from db import Database
45
+
46
+ db = Database()
47
+ db.init()
48
+
49
+
50
+ # ── OAuth Callback Server ────────────────────────────────────────────────────
51
+
52
+ class OAuthCallbackHandler(BaseHTTPRequestHandler):
53
+ """Servidor HTTP mínimo para capturar o callback OAuth."""
54
+ authorization_code: Optional[str] = None
55
+
56
+ def do_GET(self):
57
+ parsed = urlparse(self.path)
58
+ params = parse_qs(parsed.query)
59
+
60
+ if "code" in params:
61
+ OAuthCallbackHandler.authorization_code = params["code"][0]
62
+ self.send_response(200)
63
+ self.send_header("Content-Type", "text/html; charset=utf-8")
64
+ self.end_headers()
65
+ self.wfile.write(
66
+ b"<html><body><h2>Autorizado com sucesso!</h2>"
67
+ b"<p>Pode fechar esta janela e voltar ao terminal.</p></body></html>"
68
+ )
69
+ elif "error" in params:
70
+ error = params.get("error_description", params.get("error", ["desconhecido"]))[0]
71
+ self.send_response(400)
72
+ self.send_header("Content-Type", "text/html; charset=utf-8")
73
+ self.end_headers()
74
+ self.wfile.write(f"<html><body><h2>Erro: {error}</h2></body></html>".encode())
75
+ else:
76
+ self.send_response(404)
77
+ self.end_headers()
78
+
79
+ def log_message(self, format, *args):
80
+ pass # silencia logs do servidor
81
+
82
+
83
+ def wait_for_oauth_code() -> Optional[str]:
84
+ """Inicia servidor local e espera pelo código de autorização."""
85
+ server = HTTPServer(("localhost", OAUTH_REDIRECT_PORT), OAuthCallbackHandler)
86
+ server.timeout = 120 # 2 minutos
87
+ print(f"Aguardando autorização em http://localhost:{OAUTH_REDIRECT_PORT}/callback ...")
88
+ print("(Timeout: 2 minutos)\n")
89
+
90
+ while OAuthCallbackHandler.authorization_code is None:
91
+ server.handle_request()
92
+ if OAuthCallbackHandler.authorization_code is not None:
93
+ break
94
+
95
+ server.server_close()
96
+ return OAuthCallbackHandler.authorization_code
97
+
98
+
99
+ # ── Token Exchange ────────────────────────────────────────────────────────────
100
+
101
+ async def exchange_code_for_short_token(
102
+ code: str, app_id: str, app_secret: str,
103
+ ) -> dict:
104
+ """Troca authorization code por short-lived token (~1hr)."""
105
+ async with httpx.AsyncClient(timeout=30) as client:
106
+ resp = await client.get(
107
+ OAUTH_TOKEN_URL,
108
+ params={
109
+ "client_id": app_id,
110
+ "redirect_uri": OAUTH_REDIRECT_URI,
111
+ "client_secret": app_secret,
112
+ "code": code,
113
+ },
114
+ )
115
+ resp.raise_for_status()
116
+ return resp.json()
117
+
118
+
119
+ async def exchange_for_long_lived_token(
120
+ short_token: str, app_id: str, app_secret: str,
121
+ ) -> dict:
122
+ """Troca short-lived token por long-lived token (60 dias)."""
123
+ async with httpx.AsyncClient(timeout=30) as client:
124
+ resp = await client.get(
125
+ OAUTH_TOKEN_URL,
126
+ params={
127
+ "grant_type": "fb_exchange_token",
128
+ "client_id": app_id,
129
+ "client_secret": app_secret,
130
+ "fb_exchange_token": short_token,
131
+ },
132
+ )
133
+ resp.raise_for_status()
134
+ return resp.json()
135
+
136
+
137
+ async def refresh_long_lived_token(access_token: str, app_id: str, app_secret: str) -> dict:
138
+ """Renova um long-lived token (deve ter mais de 24hr e menos de 60 dias)."""
139
+ async with httpx.AsyncClient(timeout=30) as client:
140
+ resp = await client.get(
141
+ OAUTH_TOKEN_URL,
142
+ params={
143
+ "grant_type": "fb_exchange_token",
144
+ "client_id": app_id,
145
+ "client_secret": app_secret,
146
+ "fb_exchange_token": access_token,
147
+ },
148
+ )
149
+ resp.raise_for_status()
150
+ return resp.json()
151
+
152
+
153
+ # ── Instagram User Discovery ─────────────────────────────────────────────────
154
+
155
+ async def discover_instagram_account(access_token: str) -> dict:
156
+ """
157
+ Descobre o Instagram Business/Creator account via Facebook Pages.
158
+ Retorna: {ig_user_id, username, account_type, facebook_page_id}
159
+ """
160
+ async with httpx.AsyncClient(timeout=30) as client:
161
+ # 1. Listar Facebook Pages
162
+ resp = await client.get(
163
+ f"{GRAPH_API_BASE}/me/accounts",
164
+ params={"access_token": access_token, "fields": "id,name,access_token"},
165
+ )
166
+ resp.raise_for_status()
167
+ pages = resp.json().get("data", [])
168
+
169
+ if not pages:
170
+ raise ValueError(
171
+ "Nenhuma Facebook Page encontrada. "
172
+ "Crie uma Facebook Page e vincule à sua conta Instagram."
173
+ )
174
+
175
+ # 2. Para cada page, verificar se tem Instagram Business Account
176
+ for page in pages:
177
+ page_id = page["id"]
178
+ resp = await client.get(
179
+ f"{GRAPH_API_BASE}/{page_id}",
180
+ params={
181
+ "access_token": access_token,
182
+ "fields": "instagram_business_account",
183
+ },
184
+ )
185
+ resp.raise_for_status()
186
+ ig_account = resp.json().get("instagram_business_account")
187
+
188
+ if ig_account:
189
+ ig_user_id = ig_account["id"]
190
+ # 3. Buscar detalhes da conta Instagram
191
+ resp = await client.get(
192
+ f"{GRAPH_API_BASE}/{ig_user_id}",
193
+ params={
194
+ "access_token": access_token,
195
+ "fields": "id,username,account_type,name,profile_picture_url,"
196
+ "followers_count,follows_count,media_count",
197
+ },
198
+ )
199
+ resp.raise_for_status()
200
+ ig_info = resp.json()
201
+ return {
202
+ "ig_user_id": ig_user_id,
203
+ "username": ig_info.get("username"),
204
+ "account_type": ig_info.get("account_type", "BUSINESS"),
205
+ "facebook_page_id": page_id,
206
+ "profile": ig_info,
207
+ }
208
+
209
+ raise ValueError(
210
+ "Nenhuma conta Instagram Business/Creator vinculada às Facebook Pages encontradas. "
211
+ "Vincule sua conta Instagram a uma Facebook Page nas configurações do Instagram."
212
+ )
213
+
214
+
215
+ # ── Auto-Refresh ──────────────────────────────────────────────────────────────
216
+
217
+ async def auto_refresh_if_needed(account_id: Optional[int] = None) -> Optional[str]:
218
+ """
219
+ Verifica se o token está próximo de expirar (< 7 dias) e renova.
220
+ Retorna o token atual (renovado ou não).
221
+ """
222
+ account = db.get_active_account() if account_id is None else db.get_account_by_id(account_id)
223
+ if not account:
224
+ return None
225
+
226
+ token = account["access_token"]
227
+ expires_at = account.get("token_expires_at")
228
+
229
+ if not expires_at:
230
+ return token
231
+
232
+ try:
233
+ expiry = datetime.fromisoformat(expires_at.replace("Z", "+00:00"))
234
+ except (ValueError, AttributeError):
235
+ return token
236
+
237
+ now = datetime.now(timezone.utc)
238
+ days_left = (expiry - now).days
239
+
240
+ if days_left <= 7:
241
+ print(f"Token expira em {days_left} dias. Renovando...")
242
+ try:
243
+ result = await refresh_long_lived_token(
244
+ token, account["app_id"], account["app_secret"]
245
+ )
246
+ new_token = result["access_token"]
247
+ new_expires = (now + timedelta(seconds=result.get("expires_in", 5184000))).isoformat()
248
+ db.update_token(account["id"], new_token, new_expires)
249
+ print(f"Token renovado. Nova expiração: {new_expires[:10]}")
250
+ return new_token
251
+ except Exception as e:
252
+ print(f"AVISO: Falha ao renovar token: {e}")
253
+ return token
254
+
255
+ return token
256
+
257
+
258
+ # ── Setup Flow ────────────────────────────────────────────────────────────────
259
+
260
+ async def setup() -> None:
261
+ """Fluxo completo de setup OAuth."""
262
+ print("=" * 60)
263
+ print("CONFIGURAÇÃO OAUTH - INSTAGRAM GRAPH API")
264
+ print("=" * 60)
265
+ print()
266
+ print("Você precisa de um Meta App com o produto Instagram Graph API.")
267
+ print("Crie em: https://developers.facebook.com/apps/")
268
+ print()
269
+
270
+ # App credentials
271
+ app_id = os.environ.get("INSTAGRAM_APP_ID") or input("App ID: ").strip()
272
+ app_secret = os.environ.get("INSTAGRAM_APP_SECRET") or input("App Secret: ").strip()
273
+
274
+ if not app_id or not app_secret:
275
+ print("ERRO: App ID e App Secret são obrigatórios.")
276
+ sys.exit(1)
277
+
278
+ # Construir URL de autorização
279
+ scopes = ",".join(OAUTH_SCOPES)
280
+ auth_url = (
281
+ f"{OAUTH_AUTHORIZE_URL}?"
282
+ f"client_id={app_id}&"
283
+ f"redirect_uri={OAUTH_REDIRECT_URI}&"
284
+ f"scope={scopes}&"
285
+ f"response_type=code"
286
+ )
287
+
288
+ print(f"\nAbrindo browser para autorização...")
289
+ # Mask client_id in auth URL to avoid logging credentials
290
+ masked_url = auth_url.replace(app_id, app_id[:4] + "...masked") if app_id else auth_url
291
+ print(f"URL: {masked_url}\n")
292
+ webbrowser.open(auth_url)
293
+
294
+ # Esperar callback
295
+ OAuthCallbackHandler.authorization_code = None
296
+ code = wait_for_oauth_code()
297
+
298
+ if not code:
299
+ print("ERRO: Timeout ou falha na autorização.")
300
+ sys.exit(1)
301
+
302
+ print("Código de autorização recebido. Trocando por token...")
303
+
304
+ # Trocar por short-lived token
305
+ short_result = await exchange_code_for_short_token(code, app_id, app_secret)
306
+ short_token = short_result["access_token"]
307
+ print("Token curto obtido.")
308
+
309
+ # Trocar por long-lived token
310
+ long_result = await exchange_for_long_lived_token(short_token, app_id, app_secret)
311
+ long_token = long_result["access_token"]
312
+ expires_in = long_result.get("expires_in", 5184000) # 60 dias default
313
+ expires_at = (datetime.now(timezone.utc) + timedelta(seconds=expires_in)).isoformat()
314
+ print(f"Token longo obtido. Expira em: {expires_at[:10]}")
315
+
316
+ # Descobrir conta Instagram
317
+ print("Buscando conta Instagram vinculada...")
318
+ ig_info = await discover_instagram_account(long_token)
319
+
320
+ # Salvar no banco
321
+ account_id = db.upsert_account({
322
+ "ig_user_id": ig_info["ig_user_id"],
323
+ "username": ig_info["username"],
324
+ "account_type": ig_info["account_type"],
325
+ "access_token": long_token,
326
+ "token_expires_at": expires_at,
327
+ "facebook_page_id": ig_info["facebook_page_id"],
328
+ "app_id": app_id,
329
+ "app_secret": app_secret,
330
+ })
331
+
332
+ print()
333
+ print("=" * 60)
334
+ print("CONFIGURAÇÃO CONCLUÍDA")
335
+ print("=" * 60)
336
+ profile = ig_info.get("profile", {})
337
+ print(f" Conta: @{ig_info['username']}")
338
+ print(f" Tipo: {ig_info['account_type']}")
339
+ print(f" Seguidores: {profile.get('followers_count', '?')}")
340
+ print(f" Posts: {profile.get('media_count', '?')}")
341
+ print(f" Token expira: {expires_at[:10]}")
342
+ print(f" Account ID (interno): {account_id}")
343
+ print()
344
+ print("Pronto! Use 'python scripts/status.py' para verificar.")
345
+
346
+
347
+ async def show_status() -> None:
348
+ """Mostra status da autenticação."""
349
+ account = db.get_active_account()
350
+ if not account:
351
+ print(json.dumps({"status": "not_configured", "message": "Nenhuma conta configurada. Execute: python scripts/auth.py --setup"}, indent=2))
352
+ return
353
+
354
+ expires_at = account.get("token_expires_at", "")
355
+ now = datetime.now(timezone.utc)
356
+ try:
357
+ expiry = datetime.fromisoformat(expires_at.replace("Z", "+00:00"))
358
+ days_left = (expiry - now).days
359
+ token_status = "valid" if days_left > 0 else "expired"
360
+ except (ValueError, AttributeError):
361
+ days_left = -1
362
+ token_status = "unknown"
363
+
364
+ result = {
365
+ "status": token_status,
366
+ "username": account["username"],
367
+ "account_type": account["account_type"],
368
+ "ig_user_id": account["ig_user_id"],
369
+ "token_expires_at": expires_at,
370
+ "days_remaining": days_left,
371
+ "auto_refresh": days_left <= 7 if days_left >= 0 else False,
372
+ }
373
+ print(json.dumps(result, indent=2, ensure_ascii=False))
374
+
375
+
376
+ async def do_refresh() -> None:
377
+ """Força renovação do token."""
378
+ token = await auto_refresh_if_needed()
379
+ if token:
380
+ print("Token renovado com sucesso.")
381
+ await show_status()
382
+ else:
383
+ print("Nenhuma conta configurada para renovar.")
384
+
385
+
386
+ def main():
387
+ parser = argparse.ArgumentParser(description="Autenticação OAuth Instagram")
388
+ group = parser.add_mutually_exclusive_group(required=True)
389
+ group.add_argument("--setup", action="store_true", help="Configuração inicial completa")
390
+ group.add_argument("--refresh", action="store_true", help="Renovar token")
391
+ group.add_argument("--status", action="store_true", help="Ver status do token")
392
+ group.add_argument("--revoke", action="store_true", help="Revogar token (desativar conta)")
393
+ args = parser.parse_args()
394
+
395
+ if args.setup:
396
+ asyncio.run(setup())
397
+ elif args.refresh:
398
+ asyncio.run(do_refresh())
399
+ elif args.status:
400
+ asyncio.run(show_status())
401
+ elif args.revoke:
402
+ account = db.get_active_account()
403
+ if account:
404
+ db._connect().execute("UPDATE accounts SET is_active = 0 WHERE id = ?", [account["id"]])
405
+ print(f"Conta @{account['username']} desativada.")
406
+ else:
407
+ print("Nenhuma conta ativa para revogar.")
408
+
409
+
410
+ if __name__ == "__main__":
411
+ main()
@@ -0,0 +1,160 @@
1
+ """
2
+ Gestão de comentários do Instagram.
3
+
4
+ Uso:
5
+ python scripts/comments.py --list --media-id 12345
6
+ python scripts/comments.py --reply --comment-id 67890 --text "Obrigado!"
7
+ python scripts/comments.py --delete --comment-id 67890
8
+ python scripts/comments.py --mentions
9
+ python scripts/comments.py --unreplied
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import asyncio
15
+ import json
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ sys.path.insert(0, str(Path(__file__).parent))
20
+
21
+ from api_client import InstagramAPI
22
+ from auth import auto_refresh_if_needed
23
+ from db import Database
24
+ from governance import GovernanceManager
25
+
26
+ db = Database()
27
+ db.init()
28
+ gov = GovernanceManager(db)
29
+
30
+
31
+ async def list_comments(media_id: str, limit: int = 50) -> None:
32
+ """Lista comentários de um post."""
33
+ await auto_refresh_if_needed()
34
+ api = InstagramAPI()
35
+ result = await api.get_comments(media_id, limit=limit)
36
+ await api.close()
37
+
38
+ comments = result.get("data", [])
39
+
40
+ # Salvar no banco
41
+ account = db.get_active_account()
42
+ if account:
43
+ for c in comments:
44
+ db.upsert_comments([{
45
+ "account_id": account["id"],
46
+ "ig_comment_id": c["id"],
47
+ "ig_media_id": media_id,
48
+ "username": c.get("username", ""),
49
+ "text": c.get("text", ""),
50
+ "timestamp": c.get("timestamp", ""),
51
+ }])
52
+
53
+ print(json.dumps({"total": len(comments), "comments": comments}, indent=2, ensure_ascii=False))
54
+
55
+
56
+ async def reply_to_comment(comment_id: str, text: str) -> None:
57
+ """Responde a um comentário."""
58
+ await auto_refresh_if_needed()
59
+
60
+ if gov.requires_confirmation("reply_comment"):
61
+ result = gov.create_confirmation_request(
62
+ "reply_comment",
63
+ {"comment_id": comment_id, "reply_text": text},
64
+ )
65
+ print(json.dumps(result, indent=2, ensure_ascii=False))
66
+ return
67
+
68
+ api = InstagramAPI()
69
+ result = await api.reply_to_comment(comment_id, text)
70
+ await api.close()
71
+
72
+ gov.log_action(
73
+ "reply_comment",
74
+ params={"comment_id": comment_id, "text": text},
75
+ result=result,
76
+ account_id=db.get_active_account()["id"] if db.get_active_account() else None,
77
+ )
78
+
79
+ print(json.dumps({"status": "replied", "result": result}, indent=2, ensure_ascii=False))
80
+
81
+
82
+ async def delete_comment(comment_id: str) -> None:
83
+ """Deleta um comentário."""
84
+ await auto_refresh_if_needed()
85
+
86
+ if gov.requires_confirmation("delete_comment"):
87
+ result = gov.create_confirmation_request(
88
+ "delete_comment",
89
+ {"comment_id": comment_id},
90
+ )
91
+ print(json.dumps(result, indent=2, ensure_ascii=False))
92
+ return
93
+
94
+ api = InstagramAPI()
95
+ result = await api.delete_comment(comment_id)
96
+ await api.close()
97
+
98
+ gov.log_action(
99
+ "delete_comment",
100
+ params={"comment_id": comment_id},
101
+ result=result,
102
+ account_id=db.get_active_account()["id"] if db.get_active_account() else None,
103
+ )
104
+
105
+ print(json.dumps({"status": "deleted", "comment_id": comment_id}, indent=2, ensure_ascii=False))
106
+
107
+
108
+ async def show_mentions(limit: int = 25) -> None:
109
+ """Mostra menções recentes."""
110
+ await auto_refresh_if_needed()
111
+ api = InstagramAPI()
112
+ result = await api.get_mentions(limit=limit)
113
+ await api.close()
114
+ print(json.dumps(result, indent=2, ensure_ascii=False))
115
+
116
+
117
+ async def show_unreplied() -> None:
118
+ """Mostra comentários não respondidos."""
119
+ account = db.get_active_account()
120
+ if not account:
121
+ print(json.dumps({"error": "Nenhuma conta configurada"}, indent=2))
122
+ return
123
+ comments = db.get_comments(account_id=account["id"], unreplied_only=True)
124
+ print(json.dumps({"total": len(comments), "unreplied": comments}, indent=2, ensure_ascii=False))
125
+
126
+
127
+ def main():
128
+ parser = argparse.ArgumentParser(description="Comentários do Instagram")
129
+ group = parser.add_mutually_exclusive_group(required=True)
130
+ group.add_argument("--list", action="store_true", help="Listar comentários")
131
+ group.add_argument("--reply", action="store_true", help="Responder comentário")
132
+ group.add_argument("--delete", action="store_true", help="Deletar comentário")
133
+ group.add_argument("--mentions", action="store_true", help="Ver menções")
134
+ group.add_argument("--unreplied", action="store_true", help="Comentários não respondidos")
135
+ parser.add_argument("--media-id", help="ID da mídia")
136
+ parser.add_argument("--comment-id", help="ID do comentário")
137
+ parser.add_argument("--text", help="Texto da resposta")
138
+ parser.add_argument("--limit", type=int, default=50, help="Limite de resultados")
139
+ args = parser.parse_args()
140
+
141
+ if args.list:
142
+ if not args.media_id:
143
+ parser.error("--media-id é obrigatório com --list")
144
+ asyncio.run(list_comments(args.media_id, args.limit))
145
+ elif args.reply:
146
+ if not args.comment_id or not args.text:
147
+ parser.error("--comment-id e --text são obrigatórios com --reply")
148
+ asyncio.run(reply_to_comment(args.comment_id, args.text))
149
+ elif args.delete:
150
+ if not args.comment_id:
151
+ parser.error("--comment-id é obrigatório com --delete")
152
+ asyncio.run(delete_comment(args.comment_id))
153
+ elif args.mentions:
154
+ asyncio.run(show_mentions(args.limit))
155
+ elif args.unreplied:
156
+ asyncio.run(show_unreplied())
157
+
158
+
159
+ if __name__ == "__main__":
160
+ main()
@@ -0,0 +1,111 @@
1
+ """
2
+ Configuração central da skill Instagram.
3
+
4
+ Todos os paths, constantes da API e specs de mídia ficam aqui.
5
+ Importado por todos os outros scripts.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from pathlib import Path
10
+ from typing import Any, Dict
11
+
12
+ # ── Paths ─────────────────────────────────────────────────────────────────────
13
+ ROOT_DIR = Path(__file__).parent.parent
14
+ SCRIPTS_DIR = ROOT_DIR / "scripts"
15
+ DATA_DIR = ROOT_DIR / "data"
16
+ EXPORTS_DIR = DATA_DIR / "exports"
17
+ STATIC_DIR = ROOT_DIR / "static"
18
+ DB_PATH = DATA_DIR / "instagram.db"
19
+
20
+ # Garante que diretórios existem
21
+ DATA_DIR.mkdir(parents=True, exist_ok=True)
22
+ EXPORTS_DIR.mkdir(parents=True, exist_ok=True)
23
+
24
+ # ── Instagram Graph API ───────────────────────────────────────────────────────
25
+ API_VERSION = "v21.0"
26
+ GRAPH_API_BASE = f"https://graph.facebook.com/{API_VERSION}"
27
+ GRAPH_IG_BASE = f"https://graph.instagram.com/{API_VERSION}"
28
+
29
+ # OAuth
30
+ OAUTH_REDIRECT_PORT = 8765
31
+ OAUTH_REDIRECT_URI = f"http://localhost:{OAUTH_REDIRECT_PORT}/callback"
32
+ OAUTH_AUTHORIZE_URL = f"https://www.facebook.com/{API_VERSION}/dialog/oauth"
33
+ OAUTH_TOKEN_URL = f"{GRAPH_API_BASE}/oauth/access_token"
34
+
35
+ # Scopes necessários
36
+ OAUTH_SCOPES = [
37
+ "instagram_basic",
38
+ "instagram_content_publish",
39
+ "instagram_manage_comments",
40
+ "instagram_manage_insights",
41
+ "instagram_manage_messages",
42
+ "pages_show_list",
43
+ "pages_read_engagement",
44
+ ]
45
+
46
+ # ── Rate Limits ───────────────────────────────────────────────────────────────
47
+ RATE_LIMIT_REQUESTS_PER_HOUR = 200
48
+ RATE_LIMIT_PUBLISHES_PER_DAY = 25
49
+ RATE_LIMIT_HASHTAGS_PER_WEEK = 30
50
+ RATE_LIMIT_DMS_PER_HOUR = 200
51
+ RATE_LIMIT_WARNING_THRESHOLD = 0.9 # alerta em 90% do limite
52
+
53
+ # ── Media Specs ───────────────────────────────────────────────────────────────
54
+ MEDIA_SPECS: Dict[str, Dict[str, Any]] = {
55
+ "PHOTO": {
56
+ "formats": ["JPEG"],
57
+ "min_width": 320,
58
+ "max_width": 1440,
59
+ "aspect_ratio_min": 4 / 5, # 0.8
60
+ "aspect_ratio_max": 1.91,
61
+ "max_size_mb": 8,
62
+ },
63
+ "VIDEO": {
64
+ "formats": ["MP4", "MOV"],
65
+ "codec": "H.264",
66
+ "audio": "AAC",
67
+ "min_duration_sec": 3,
68
+ "max_duration_sec": 60,
69
+ "max_size_mb": 100,
70
+ },
71
+ "REEL": {
72
+ "formats": ["MP4", "MOV"],
73
+ "codec": "H.264",
74
+ "audio": "AAC",
75
+ "recommended_width": 1080,
76
+ "recommended_height": 1920,
77
+ "aspect_ratio": "9:16",
78
+ "min_duration_sec": 3,
79
+ "max_duration_sec": 90,
80
+ "max_size_mb": 1024,
81
+ },
82
+ "STORY": {
83
+ "recommended_width": 1080,
84
+ "recommended_height": 1920,
85
+ "aspect_ratio": "9:16",
86
+ },
87
+ "CAROUSEL": {
88
+ "min_items": 2,
89
+ "max_items": 10,
90
+ },
91
+ }
92
+
93
+ # ── Imgur (upload de mídia local) ─────────────────────────────────────────────
94
+ IMGUR_UPLOAD_URL = "https://api.imgur.com/3/image"
95
+ IMGUR_CLIENT_ID = "546c25a59c58ad7" # anonymous uploads (público)
96
+
97
+ # ── Retry / Backoff ──────────────────────────────────────────────────────────
98
+ MAX_RETRIES = 3
99
+ RETRY_BACKOFF_BASE = 2 # segundos: 2^1, 2^2, 2^3
100
+ REQUEST_TIMEOUT = 30.0
101
+
102
+ # ── Governance ────────────────────────────────────────────────────────────────
103
+ # Categorias de ação para confirmação
104
+ ACTION_CATEGORIES = {
105
+ "READ": [], # sem confirmação
106
+ "ENGAGE": ["reply_comment", "hide_comment", "unhide_comment"],
107
+ "PUBLISH": ["publish_photo", "publish_video", "publish_reel",
108
+ "publish_story", "publish_carousel", "schedule_post"],
109
+ "DELETE": ["delete_comment"],
110
+ "MESSAGE": ["send_dm"],
111
+ }