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,189 @@
1
+ """
2
+ Sync completo: busca perfil, mídia, insights e comentários do Instagram.
3
+
4
+ Uso:
5
+ python scripts/run_all.py # Sync completo
6
+ python scripts/run_all.py --only media # Só mídia
7
+ python scripts/run_all.py --only insights # Só insights
8
+ python scripts/run_all.py --only comments # Só comentários
9
+ python scripts/run_all.py --dry-run # Mostra o que seria feito
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import asyncio
15
+ import json
16
+ import logging
17
+ import sys
18
+ from datetime import datetime, timezone
19
+ from pathlib import Path
20
+
21
+ sys.path.insert(0, str(Path(__file__).parent))
22
+
23
+ from api_client import InstagramAPI
24
+ from auth import auto_refresh_if_needed
25
+ from db import Database
26
+
27
+ logging.basicConfig(
28
+ level=logging.INFO,
29
+ format="%(asctime)s [%(levelname)s] %(message)s",
30
+ datefmt="%H:%M:%S",
31
+ )
32
+ logger = logging.getLogger(__name__)
33
+
34
+ db = Database()
35
+ db.init()
36
+
37
+
38
+ async def sync_profile(api: InstagramAPI) -> dict:
39
+ """Sync perfil."""
40
+ logger.info("Buscando perfil...")
41
+ profile = await api.get_user_profile()
42
+ logger.info("Perfil: @%s (%s)", profile.get("username"), profile.get("account_type"))
43
+ return {"status": "ok", "username": profile.get("username")}
44
+
45
+
46
+ async def sync_media(api: InstagramAPI, limit: int = 50) -> dict:
47
+ """Sync mídia recente."""
48
+ logger.info("Buscando %d mídias recentes...", limit)
49
+ result = await api.get_user_media(limit=limit)
50
+ media_list = result.get("data", [])
51
+
52
+ # Salvar como posts publicados
53
+ count = 0
54
+ for m in media_list:
55
+ existing = db.get_posts(account_id=api.account_id, limit=1000)
56
+ existing_ig_ids = {p["ig_media_id"] for p in existing if p.get("ig_media_id")}
57
+
58
+ if m["id"] not in existing_ig_ids:
59
+ db.insert_post({
60
+ "account_id": api.account_id,
61
+ "media_type": m.get("media_type", "IMAGE"),
62
+ "media_url": m.get("media_url", ""),
63
+ "caption": m.get("caption", ""),
64
+ "status": "published",
65
+ "published_at": m.get("timestamp", ""),
66
+ "ig_media_id": m["id"],
67
+ "permalink": m.get("permalink", ""),
68
+ })
69
+ count += 1
70
+
71
+ logger.info("Mídia: %d encontradas, %d novas salvas", len(media_list), count)
72
+ return {"status": "ok", "found": len(media_list), "new": count}
73
+
74
+
75
+ async def sync_insights(api: InstagramAPI, limit: int = 20) -> dict:
76
+ """Sync insights dos posts recentes."""
77
+ logger.info("Buscando insights de %d posts...", limit)
78
+ media_result = await api.get_user_media(limit=limit)
79
+ media_list = media_result.get("data", [])
80
+
81
+ success = 0
82
+ errors = 0
83
+ for m in media_list:
84
+ try:
85
+ metrics = ["impressions", "reach", "engagement", "saved"]
86
+ if m.get("media_type") == "VIDEO":
87
+ metrics.append("video_views")
88
+ insights = await api.get_media_insights(m["id"], metrics=metrics)
89
+
90
+ raw = json.dumps(insights, ensure_ascii=False)
91
+ for item in insights.get("data", []):
92
+ values = item.get("values", [{}])
93
+ value = values[0].get("value", 0) if values else 0
94
+ db.insert_insights([{
95
+ "account_id": api.account_id,
96
+ "ig_media_id": m["id"],
97
+ "metric_name": item.get("name", ""),
98
+ "metric_value": float(value) if isinstance(value, (int, float)) else 0,
99
+ "period": item.get("period", ""),
100
+ "raw_json": raw,
101
+ }])
102
+ success += 1
103
+ except Exception as e:
104
+ errors += 1
105
+ logger.warning("Insights para %s: %s", m["id"], e)
106
+
107
+ logger.info("Insights: %d OK, %d erros", success, errors)
108
+ return {"status": "ok", "success": success, "errors": errors}
109
+
110
+
111
+ async def sync_comments(api: InstagramAPI, limit: int = 10) -> dict:
112
+ """Sync comentários dos posts recentes."""
113
+ logger.info("Buscando comentários dos últimos %d posts...", limit)
114
+ media_result = await api.get_user_media(limit=limit)
115
+ media_list = media_result.get("data", [])
116
+
117
+ total_comments = 0
118
+ for m in media_list:
119
+ try:
120
+ comments_result = await api.get_comments(m["id"], limit=50)
121
+ comments = comments_result.get("data", [])
122
+
123
+ for c in comments:
124
+ db.upsert_comments([{
125
+ "account_id": api.account_id,
126
+ "ig_comment_id": c["id"],
127
+ "ig_media_id": m["id"],
128
+ "username": c.get("username", ""),
129
+ "text": c.get("text", ""),
130
+ "timestamp": c.get("timestamp", ""),
131
+ }])
132
+ total_comments += len(comments)
133
+ except Exception as e:
134
+ logger.warning("Comentários para %s: %s", m["id"], e)
135
+
136
+ logger.info("Comentários: %d salvos", total_comments)
137
+ return {"status": "ok", "total": total_comments}
138
+
139
+
140
+ async def run(only: list = None, dry_run: bool = False, limit: int = 50) -> None:
141
+ tasks = only or ["profile", "media", "insights", "comments"]
142
+
143
+ if dry_run:
144
+ print(f"\n[DRY-RUN] Sync que seria executado: {', '.join(tasks)}")
145
+ return
146
+
147
+ await auto_refresh_if_needed()
148
+ api = InstagramAPI()
149
+
150
+ logger.info("Iniciando sync: %s", ", ".join(tasks))
151
+ results = {}
152
+
153
+ try:
154
+ if "profile" in tasks:
155
+ results["profile"] = await sync_profile(api)
156
+ if "media" in tasks:
157
+ results["media"] = await sync_media(api, limit=limit)
158
+ if "insights" in tasks:
159
+ results["insights"] = await sync_insights(api, limit=min(limit, 20))
160
+ if "comments" in tasks:
161
+ results["comments"] = await sync_comments(api, limit=min(limit, 10))
162
+ finally:
163
+ await api.close()
164
+
165
+ # Resumo
166
+ print("\n" + "=" * 60)
167
+ print("SYNC COMPLETO")
168
+ print("=" * 60)
169
+ for task, result in results.items():
170
+ print(f" {task}: {json.dumps(result, ensure_ascii=False)}")
171
+ print("=" * 60)
172
+
173
+ stats = db.get_stats()
174
+ print(f"\nBanco: {json.dumps(stats, indent=2, ensure_ascii=False)}")
175
+
176
+
177
+ def main():
178
+ parser = argparse.ArgumentParser(description="Sync completo do Instagram")
179
+ parser.add_argument("--only", nargs="+", choices=["profile", "media", "insights", "comments"],
180
+ help="Executar apenas tarefas específicas")
181
+ parser.add_argument("--limit", type=int, default=50, help="Limite de mídia a buscar")
182
+ parser.add_argument("--dry-run", action="store_true", help="Mostra o que seria feito")
183
+ args = parser.parse_args()
184
+
185
+ asyncio.run(run(only=args.only, dry_run=args.dry_run, limit=args.limit))
186
+
187
+
188
+ if __name__ == "__main__":
189
+ main()
@@ -0,0 +1,189 @@
1
+ """
2
+ Orquestrador de publicação: processa posts approved/scheduled.
3
+
4
+ Uso:
5
+ python scripts/schedule.py --process # Publica posts prontos
6
+ python scripts/schedule.py --list # Lista posts pendentes
7
+ python scripts/schedule.py --cancel --id 5 # Cancela agendamento
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 process_pending() -> None:
30
+ """Processa todos os posts approved/scheduled prontos para publicar."""
31
+ await auto_refresh_if_needed()
32
+ api = InstagramAPI()
33
+ account = db.get_active_account()
34
+ if not account:
35
+ print(json.dumps({"error": "Nenhuma conta configurada"}, indent=2))
36
+ return
37
+
38
+ posts = db.get_posts_for_publishing(account["id"])
39
+ if not posts:
40
+ print(json.dumps({"message": "Nenhum post pendente para publicar", "count": 0}, indent=2))
41
+ return
42
+
43
+ print(f"Processando {len(posts)} posts...")
44
+ results = []
45
+
46
+ for post in posts:
47
+ post_id = post["id"]
48
+ try:
49
+ gov.check_rate_limit(f"publish_{post['media_type'].lower()}", account["id"])
50
+ except RateLimitExceeded as e:
51
+ results.append({"post_id": post_id, "status": "rate_limited", "error": str(e)})
52
+ break
53
+
54
+ try:
55
+ # Recovery: se já tem container criado, tenta publicar direto
56
+ if post["status"] == "container_created" and post.get("ig_container_id"):
57
+ result = await api.publish_media(post["ig_container_id"])
58
+ ig_media_id = result.get("id")
59
+ details = await api.get_media_details(ig_media_id)
60
+ db.update_post_status(
61
+ post_id, "published",
62
+ ig_media_id=ig_media_id,
63
+ permalink=details.get("permalink", ""),
64
+ published_at=details.get("timestamp", ""),
65
+ )
66
+ results.append({"post_id": post_id, "status": "published", "ig_media_id": ig_media_id})
67
+ continue
68
+
69
+ # Publicação normal
70
+ media_url = post.get("media_url", "")
71
+ if not media_url and post.get("local_path"):
72
+ media_url = await api.upload_to_imgur(post["local_path"])
73
+ db.update_post_status(post_id, post["status"], media_url=media_url)
74
+
75
+ media_type = post["media_type"].upper()
76
+ ig_type_map = {"PHOTO": "IMAGE", "VIDEO": "VIDEO", "REEL": "REELS", "STORY": "STORIES"}
77
+ ig_type = ig_type_map.get(media_type, "IMAGE")
78
+
79
+ if media_type == "CAROUSEL":
80
+ results.append({"post_id": post_id, "status": "skipped", "reason": "Carrosséis precisam ser publicados via publish.py"})
81
+ continue
82
+
83
+ # Step 1: Container
84
+ container_params = {"caption": post.get("caption")}
85
+ if ig_type == "IMAGE":
86
+ container_params["media_type"] = "IMAGE"
87
+ container_params["image_url"] = media_url
88
+ else:
89
+ container_params["media_type"] = ig_type
90
+ container_params["video_url"] = media_url
91
+
92
+ container = await api.create_media_container(**container_params)
93
+ container_id = container["id"]
94
+ db.update_post_status(post_id, "container_created", ig_container_id=container_id)
95
+
96
+ # Para vídeos, aguardar processamento
97
+ if media_type in ("VIDEO", "REEL"):
98
+ for _ in range(60):
99
+ status = await api.check_container_status(container_id)
100
+ if status.get("status_code") == "FINISHED":
101
+ break
102
+ if status.get("status_code") == "ERROR":
103
+ raise Exception(status.get("status", "Erro no processamento"))
104
+ await asyncio.sleep(5)
105
+
106
+ # Step 2: Publicar
107
+ result = await api.publish_media(container_id)
108
+ ig_media_id = result.get("id")
109
+ details = await api.get_media_details(ig_media_id)
110
+ permalink = details.get("permalink", "")
111
+
112
+ db.update_post_status(
113
+ post_id, "published",
114
+ ig_media_id=ig_media_id,
115
+ permalink=permalink,
116
+ published_at=details.get("timestamp", ""),
117
+ )
118
+
119
+ gov.log_action(
120
+ f"publish_{media_type.lower()}",
121
+ params={"post_id": post_id},
122
+ result={"ig_media_id": ig_media_id, "permalink": permalink},
123
+ account_id=account["id"],
124
+ )
125
+
126
+ results.append({"post_id": post_id, "status": "published", "ig_media_id": ig_media_id, "permalink": permalink})
127
+
128
+ except Exception as e:
129
+ db.update_post_status(post_id, "failed", error_msg=str(e))
130
+ results.append({"post_id": post_id, "status": "failed", "error": str(e)})
131
+
132
+ await api.close()
133
+ print(json.dumps({"processed": len(results), "results": results}, indent=2, ensure_ascii=False))
134
+
135
+
136
+ async def list_pending() -> None:
137
+ """Lista posts pendentes."""
138
+ account = db.get_active_account()
139
+ if not account:
140
+ print(json.dumps({"error": "Nenhuma conta configurada"}, indent=2))
141
+ return
142
+
143
+ drafts = db.get_posts(account_id=account["id"], status="draft")
144
+ approved = db.get_posts(account_id=account["id"], status="approved")
145
+ scheduled = db.get_posts(account_id=account["id"], status="scheduled")
146
+ failed = db.get_posts(account_id=account["id"], status="failed")
147
+
148
+ print(json.dumps({
149
+ "draft": {"count": len(drafts), "posts": drafts},
150
+ "approved": {"count": len(approved), "posts": approved},
151
+ "scheduled": {"count": len(scheduled), "posts": scheduled},
152
+ "failed": {"count": len(failed), "posts": failed},
153
+ }, indent=2, ensure_ascii=False))
154
+
155
+
156
+ async def cancel_post(post_id: int) -> None:
157
+ """Cancela um post (move para status cancelled)."""
158
+ post = db.get_post_by_id(post_id)
159
+ if not post:
160
+ print(json.dumps({"error": f"Post {post_id} não encontrado"}, indent=2))
161
+ return
162
+ if post["status"] == "published":
163
+ print(json.dumps({"error": "Não é possível cancelar post já publicado"}, indent=2))
164
+ return
165
+ db.update_post_status(post_id, "draft")
166
+ print(json.dumps({"status": "cancelled", "post_id": post_id}, indent=2))
167
+
168
+
169
+ def main():
170
+ parser = argparse.ArgumentParser(description="Agendamento de posts Instagram")
171
+ group = parser.add_mutually_exclusive_group(required=True)
172
+ group.add_argument("--process", action="store_true", help="Processar posts pendentes")
173
+ group.add_argument("--list", action="store_true", help="Listar posts pendentes")
174
+ group.add_argument("--cancel", action="store_true", help="Cancelar agendamento")
175
+ parser.add_argument("--id", type=int, help="ID do post (para --cancel)")
176
+ args = parser.parse_args()
177
+
178
+ if args.process:
179
+ asyncio.run(process_pending())
180
+ elif args.list:
181
+ asyncio.run(list_pending())
182
+ elif args.cancel:
183
+ if not args.id:
184
+ parser.error("--id é obrigatório com --cancel")
185
+ asyncio.run(cancel_post(args.id))
186
+
187
+
188
+ if __name__ == "__main__":
189
+ main()
@@ -0,0 +1,234 @@
1
+ """
2
+ API REST e dashboard para dados do Instagram.
3
+
4
+ Uso:
5
+ python scripts/serve_api.py
6
+ python scripts/serve_api.py --port 8080 --host 0.0.0.0
7
+
8
+ Endpoints:
9
+ GET / → info da API
10
+ GET /api/posts → posts com filtros
11
+ GET /api/comments → comentários
12
+ GET /api/insights/summary → resumo de insights
13
+ GET /api/insights/best-times → melhores horários
14
+ GET /api/stats → estatísticas gerais
15
+ GET /api/export/{format} → exportação
16
+ GET /api/templates → templates
17
+ GET /api/actions → audit log
18
+ GET /dashboard → dashboard HTML
19
+ GET /webhook → stub para v2
20
+ """
21
+ from __future__ import annotations
22
+
23
+ import argparse
24
+ import csv
25
+ import io
26
+ import json
27
+ import sys
28
+ from pathlib import Path
29
+
30
+ sys.path.insert(0, str(Path(__file__).parent))
31
+
32
+ from config import STATIC_DIR
33
+ from db import Database
34
+
35
+ try:
36
+ from fastapi import FastAPI, Query
37
+ from fastapi.responses import FileResponse, HTMLResponse, JSONResponse, PlainTextResponse, StreamingResponse
38
+ import uvicorn
39
+ except ImportError:
40
+ print("FastAPI não instalado. Execute: pip install fastapi uvicorn")
41
+ sys.exit(1)
42
+
43
+ app = FastAPI(
44
+ title="Instagram Dashboard API",
45
+ description="API REST para dados e analytics do Instagram",
46
+ version="1.0.0",
47
+ )
48
+
49
+ db = Database()
50
+ db.init()
51
+
52
+
53
+ @app.get("/", summary="Info da API")
54
+ def root():
55
+ stats = db.get_stats()
56
+ return {
57
+ "name": "Instagram Dashboard API",
58
+ "version": "1.0.0",
59
+ "stats": stats,
60
+ "endpoints": {
61
+ "posts": "/api/posts",
62
+ "comments": "/api/comments",
63
+ "insights_summary": "/api/insights/summary",
64
+ "insights_best_times": "/api/insights/best-times",
65
+ "stats": "/api/stats",
66
+ "templates": "/api/templates",
67
+ "actions": "/api/actions",
68
+ "dashboard": "/dashboard",
69
+ },
70
+ }
71
+
72
+
73
+ @app.get("/api/posts", summary="Lista posts")
74
+ def list_posts(
75
+ status: str = Query(None, description="Filtrar por status"),
76
+ limit: int = Query(50, ge=1, le=500),
77
+ offset: int = Query(0, ge=0),
78
+ ):
79
+ account = db.get_active_account()
80
+ account_id = account["id"] if account else None
81
+ posts = db.get_posts(account_id=account_id, status=status, limit=limit, offset=offset)
82
+ return {"total": len(posts), "data": posts}
83
+
84
+
85
+ @app.get("/api/comments", summary="Lista comentários")
86
+ def list_comments(
87
+ media_id: str = Query(None),
88
+ unreplied: bool = Query(False),
89
+ limit: int = Query(50, ge=1, le=500),
90
+ ):
91
+ account = db.get_active_account()
92
+ account_id = account["id"] if account else None
93
+ comments = db.get_comments(
94
+ ig_media_id=media_id,
95
+ account_id=account_id,
96
+ unreplied_only=unreplied,
97
+ limit=limit,
98
+ )
99
+ return {"total": len(comments), "data": comments}
100
+
101
+
102
+ @app.get("/api/insights/summary", summary="Resumo de insights")
103
+ def insights_summary():
104
+ conn = db._connect()
105
+ # Engajamento médio por tipo de conteúdo
106
+ rows = conn.execute("""
107
+ SELECT p.media_type,
108
+ COUNT(DISTINCT p.id) as post_count,
109
+ AVG(CASE WHEN i.metric_name='engagement' THEN i.metric_value END) as avg_engagement,
110
+ AVG(CASE WHEN i.metric_name='reach' THEN i.metric_value END) as avg_reach,
111
+ AVG(CASE WHEN i.metric_name='impressions' THEN i.metric_value END) as avg_impressions
112
+ FROM posts p
113
+ LEFT JOIN insights i ON i.ig_media_id = p.ig_media_id
114
+ WHERE p.status = 'published'
115
+ GROUP BY p.media_type
116
+ """).fetchall()
117
+
118
+ return {"by_media_type": [dict(r) for r in rows]}
119
+
120
+
121
+ @app.get("/api/insights/best-times", summary="Melhores horários para postar")
122
+ def best_times():
123
+ conn = db._connect()
124
+ rows = conn.execute("""
125
+ SELECT
126
+ strftime('%H', p.published_at) as hour,
127
+ strftime('%w', p.published_at) as weekday,
128
+ COUNT(DISTINCT p.id) as post_count,
129
+ AVG(i.metric_value) as avg_engagement
130
+ FROM posts p
131
+ JOIN insights i ON i.ig_media_id = p.ig_media_id
132
+ WHERE p.status = 'published' AND p.published_at IS NOT NULL
133
+ AND i.metric_name IN ('engagement', 'reach')
134
+ GROUP BY hour, weekday
135
+ ORDER BY avg_engagement DESC
136
+ """).fetchall()
137
+
138
+ weekday_names = ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"]
139
+ data = []
140
+ for r in rows:
141
+ data.append({
142
+ "hour": f"{r['hour']}:00" if r["hour"] else "?",
143
+ "weekday": weekday_names[int(r["weekday"])] if r["weekday"] else "?",
144
+ "posts": r["post_count"],
145
+ "avg_engagement": round(r["avg_engagement"], 1) if r["avg_engagement"] else 0,
146
+ })
147
+ return {"data": data}
148
+
149
+
150
+ @app.get("/api/stats", summary="Estatísticas gerais")
151
+ def stats():
152
+ return db.get_stats()
153
+
154
+
155
+ @app.get("/api/templates", summary="Templates de conteúdo")
156
+ def list_templates():
157
+ templates = db.get_templates()
158
+ return {"total": len(templates), "data": templates}
159
+
160
+
161
+ @app.get("/api/actions", summary="Audit log recente")
162
+ def recent_actions(limit: int = Query(50, ge=1, le=500)):
163
+ actions = db.get_recent_actions(limit=limit)
164
+ return {"total": len(actions), "data": actions}
165
+
166
+
167
+ @app.get("/api/export/json", summary="Exportar posts em JSON")
168
+ def export_json():
169
+ account = db.get_active_account()
170
+ posts = db.get_posts(account_id=account["id"] if account else None, limit=5000)
171
+ return JSONResponse(
172
+ content={"total": len(posts), "data": posts},
173
+ headers={"Content-Disposition": "attachment; filename=instagram_posts.json"},
174
+ )
175
+
176
+
177
+ @app.get("/api/export/csv", summary="Exportar posts em CSV")
178
+ def export_csv():
179
+ account = db.get_active_account()
180
+ posts = db.get_posts(account_id=account["id"] if account else None, limit=5000)
181
+ if not posts:
182
+ return PlainTextResponse("Sem dados.")
183
+ output = io.StringIO()
184
+ writer = csv.DictWriter(output, fieldnames=list(posts[0].keys()), extrasaction="ignore")
185
+ writer.writeheader()
186
+ writer.writerows(posts)
187
+ output.seek(0)
188
+ return StreamingResponse(
189
+ iter([output.getvalue()]),
190
+ media_type="text/csv",
191
+ headers={"Content-Disposition": "attachment; filename=instagram_posts.csv"},
192
+ )
193
+
194
+
195
+ @app.get("/dashboard", summary="Dashboard visual")
196
+ def dashboard():
197
+ dashboard_path = STATIC_DIR / "dashboard.html"
198
+ if dashboard_path.exists():
199
+ return FileResponse(dashboard_path, media_type="text/html")
200
+ return HTMLResponse("<h1>Dashboard não encontrado</h1><p>Crie static/dashboard.html</p>")
201
+
202
+
203
+ @app.get("/webhook", summary="Webhook stub (v2)")
204
+ def webhook_stub():
205
+ return {"status": "ok", "message": "Webhook endpoint ready (v2)"}
206
+
207
+
208
+ @app.post("/webhook", summary="Webhook receiver (v2)")
209
+ def webhook_receive():
210
+ return {"status": "ok"}
211
+
212
+
213
+ def main():
214
+ parser = argparse.ArgumentParser(description="API Instagram Dashboard")
215
+ parser.add_argument("--host", default="127.0.0.1")
216
+ parser.add_argument("--port", type=int, default=8000)
217
+ parser.add_argument("--reload", action="store_true")
218
+ args = parser.parse_args()
219
+
220
+ print(f"\nAPI: http://{args.host}:{args.port}")
221
+ print(f"Dashboard: http://{args.host}:{args.port}/dashboard")
222
+ print(f"Docs: http://{args.host}:{args.port}/docs\n")
223
+
224
+ uvicorn.run(
225
+ "serve_api:app",
226
+ host=args.host,
227
+ port=args.port,
228
+ reload=args.reload,
229
+ app_dir=str(Path(__file__).parent),
230
+ )
231
+
232
+
233
+ if __name__ == "__main__":
234
+ main()