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,467 @@
1
+ """
2
+ Camada de persistência SQLite para a skill Instagram.
3
+
4
+ Uso:
5
+ from db import Database
6
+ db = Database()
7
+ db.init()
8
+ db.upsert_account({...})
9
+ db.insert_post({...})
10
+ stats = db.get_stats()
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import sqlite3
16
+ from datetime import datetime, timezone
17
+ from pathlib import Path
18
+ from typing import Any, Dict, List, Optional
19
+
20
+ from config import DB_PATH
21
+
22
+ DDL = """
23
+ -- Contas Instagram (multi-conta ready)
24
+ CREATE TABLE IF NOT EXISTS accounts (
25
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
26
+ ig_user_id TEXT UNIQUE NOT NULL,
27
+ username TEXT,
28
+ account_type TEXT,
29
+ access_token TEXT NOT NULL,
30
+ token_expires_at TEXT,
31
+ facebook_page_id TEXT,
32
+ app_id TEXT,
33
+ app_secret TEXT,
34
+ is_active INTEGER DEFAULT 1,
35
+ created_at TEXT DEFAULT (datetime('now'))
36
+ );
37
+
38
+ -- Pipeline de conteúdo: draft → approved → scheduled → container_created → published | failed
39
+ CREATE TABLE IF NOT EXISTS posts (
40
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
41
+ account_id INTEGER REFERENCES accounts(id),
42
+ media_type TEXT,
43
+ media_url TEXT,
44
+ local_path TEXT,
45
+ caption TEXT,
46
+ hashtags TEXT,
47
+ template_id INTEGER REFERENCES templates(id),
48
+ status TEXT DEFAULT 'draft',
49
+ scheduled_at TEXT,
50
+ published_at TEXT,
51
+ ig_media_id TEXT,
52
+ ig_container_id TEXT,
53
+ permalink TEXT,
54
+ error_msg TEXT,
55
+ created_at TEXT DEFAULT (datetime('now'))
56
+ );
57
+
58
+ CREATE TABLE IF NOT EXISTS comments (
59
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
60
+ account_id INTEGER REFERENCES accounts(id),
61
+ ig_comment_id TEXT UNIQUE,
62
+ ig_media_id TEXT,
63
+ username TEXT,
64
+ text TEXT,
65
+ timestamp TEXT,
66
+ replied INTEGER DEFAULT 0,
67
+ reply_text TEXT,
68
+ hidden INTEGER DEFAULT 0,
69
+ fetched_at TEXT DEFAULT (datetime('now'))
70
+ );
71
+
72
+ CREATE TABLE IF NOT EXISTS insights (
73
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
74
+ account_id INTEGER REFERENCES accounts(id),
75
+ ig_media_id TEXT,
76
+ metric_name TEXT,
77
+ metric_value REAL,
78
+ period TEXT,
79
+ fetched_at TEXT DEFAULT (datetime('now')),
80
+ raw_json TEXT
81
+ );
82
+
83
+ CREATE TABLE IF NOT EXISTS user_insights (
84
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
85
+ account_id INTEGER REFERENCES accounts(id),
86
+ metric_name TEXT,
87
+ metric_value REAL,
88
+ period TEXT,
89
+ end_time TEXT,
90
+ fetched_at TEXT DEFAULT (datetime('now'))
91
+ );
92
+
93
+ CREATE TABLE IF NOT EXISTS templates (
94
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
95
+ name TEXT UNIQUE NOT NULL,
96
+ caption_template TEXT,
97
+ hashtag_set TEXT,
98
+ default_schedule_time TEXT,
99
+ created_at TEXT DEFAULT (datetime('now'))
100
+ );
101
+
102
+ CREATE TABLE IF NOT EXISTS hashtag_searches (
103
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
104
+ account_id INTEGER REFERENCES accounts(id),
105
+ hashtag TEXT,
106
+ ig_hashtag_id TEXT,
107
+ searched_at TEXT DEFAULT (datetime('now'))
108
+ );
109
+
110
+ CREATE TABLE IF NOT EXISTS action_log (
111
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
112
+ account_id INTEGER,
113
+ action TEXT NOT NULL,
114
+ params TEXT,
115
+ result TEXT,
116
+ confirmed INTEGER,
117
+ rate_remaining TEXT,
118
+ created_at TEXT DEFAULT (datetime('now'))
119
+ );
120
+
121
+ -- Índices
122
+ CREATE INDEX IF NOT EXISTS idx_posts_status ON posts (status);
123
+ CREATE INDEX IF NOT EXISTS idx_posts_account ON posts (account_id);
124
+ CREATE INDEX IF NOT EXISTS idx_posts_scheduled ON posts (scheduled_at);
125
+ CREATE INDEX IF NOT EXISTS idx_comments_media ON comments (ig_media_id);
126
+ CREATE INDEX IF NOT EXISTS idx_comments_account ON comments (account_id);
127
+ CREATE INDEX IF NOT EXISTS idx_insights_media ON insights (ig_media_id);
128
+ CREATE INDEX IF NOT EXISTS idx_insights_account ON insights (account_id);
129
+ CREATE INDEX IF NOT EXISTS idx_user_insights_acct ON user_insights (account_id);
130
+ CREATE INDEX IF NOT EXISTS idx_action_log_action ON action_log (action);
131
+ CREATE INDEX IF NOT EXISTS idx_action_log_time ON action_log (created_at);
132
+ CREATE INDEX IF NOT EXISTS idx_hashtag_searched ON hashtag_searches (searched_at);
133
+ """
134
+
135
+
136
+ _POSTS_COLUMNS = frozenset({
137
+ "account_id", "media_type", "media_url", "local_path", "caption",
138
+ "hashtags", "template_id", "status", "scheduled_at", "published_at",
139
+ "ig_media_id", "ig_container_id", "permalink", "error_msg", "created_at",
140
+ })
141
+
142
+
143
+ class Database:
144
+ def __init__(self, db_path: Path = DB_PATH):
145
+ self.db_path = Path(db_path)
146
+ self.db_path.parent.mkdir(parents=True, exist_ok=True)
147
+
148
+ def _connect(self) -> sqlite3.Connection:
149
+ conn = sqlite3.connect(self.db_path)
150
+ conn.row_factory = sqlite3.Row
151
+ conn.execute("PRAGMA journal_mode=WAL")
152
+ conn.execute("PRAGMA synchronous=NORMAL")
153
+ conn.execute("PRAGMA foreign_keys=ON")
154
+ return conn
155
+
156
+ def init(self) -> None:
157
+ """Cria tabelas e índices se não existirem."""
158
+ with self._connect() as conn:
159
+ conn.executescript(DDL)
160
+
161
+ # ── Accounts ──────────────────────────────────────────────────────────────
162
+
163
+ def upsert_account(self, data: Dict[str, Any]) -> int:
164
+ """Insere ou atualiza conta. Retorna o id da conta."""
165
+ sql = """
166
+ INSERT INTO accounts (ig_user_id, username, account_type, access_token,
167
+ token_expires_at, facebook_page_id, app_id, app_secret)
168
+ VALUES (:ig_user_id, :username, :account_type, :access_token,
169
+ :token_expires_at, :facebook_page_id, :app_id, :app_secret)
170
+ ON CONFLICT(ig_user_id) DO UPDATE SET
171
+ username = excluded.username,
172
+ account_type = excluded.account_type,
173
+ access_token = excluded.access_token,
174
+ token_expires_at = excluded.token_expires_at,
175
+ facebook_page_id = excluded.facebook_page_id,
176
+ app_id = excluded.app_id,
177
+ app_secret = excluded.app_secret,
178
+ is_active = 1
179
+ """
180
+ with self._connect() as conn:
181
+ conn.execute(sql, data)
182
+ row = conn.execute(
183
+ "SELECT id FROM accounts WHERE ig_user_id = ?",
184
+ [data["ig_user_id"]]
185
+ ).fetchone()
186
+ return row["id"]
187
+
188
+ def get_active_account(self) -> Optional[Dict[str, Any]]:
189
+ """Retorna a conta ativa (primeira ativa encontrada)."""
190
+ with self._connect() as conn:
191
+ row = conn.execute(
192
+ "SELECT * FROM accounts WHERE is_active = 1 ORDER BY id LIMIT 1"
193
+ ).fetchone()
194
+ return dict(row) if row else None
195
+
196
+ def get_account_by_id(self, account_id: int) -> Optional[Dict[str, Any]]:
197
+ with self._connect() as conn:
198
+ row = conn.execute(
199
+ "SELECT * FROM accounts WHERE id = ?", [account_id]
200
+ ).fetchone()
201
+ return dict(row) if row else None
202
+
203
+ def update_token(self, account_id: int, access_token: str, expires_at: str) -> None:
204
+ with self._connect() as conn:
205
+ conn.execute(
206
+ "UPDATE accounts SET access_token = ?, token_expires_at = ? WHERE id = ?",
207
+ [access_token, expires_at, account_id],
208
+ )
209
+
210
+ # ── Posts (Pipeline) ──────────────────────────────────────────────────────
211
+
212
+ def insert_post(self, data: Dict[str, Any]) -> int:
213
+ """Cria um novo post (draft por padrão). Retorna o id."""
214
+ keys = [k for k in data.keys() if k != "id" and k in _POSTS_COLUMNS]
215
+ if not keys:
216
+ raise ValueError("No valid columns provided for insert_post")
217
+ placeholders = ", ".join("?" for _ in keys)
218
+ columns = ", ".join(keys)
219
+ values = [data[k] for k in keys]
220
+ sql = f"INSERT INTO posts ({columns}) VALUES ({placeholders})"
221
+ with self._connect() as conn:
222
+ cursor = conn.execute(sql, values)
223
+ return cursor.lastrowid
224
+
225
+ def update_post_status(self, post_id: int, status: str, **extra) -> None:
226
+ """Atualiza status de um post e campos adicionais."""
227
+ sets = ["status = ?"]
228
+ params: list = [status]
229
+ for k, v in extra.items():
230
+ if k not in _POSTS_COLUMNS:
231
+ raise ValueError(f"Invalid column name for update_post_status: {k}")
232
+ sets.append(f"{k} = ?")
233
+ params.append(v)
234
+ params.append(post_id)
235
+ sql = f"UPDATE posts SET {', '.join(sets)} WHERE id = ?"
236
+ with self._connect() as conn:
237
+ conn.execute(sql, params)
238
+
239
+ def get_posts(
240
+ self,
241
+ account_id: Optional[int] = None,
242
+ status: Optional[str] = None,
243
+ limit: int = 50,
244
+ offset: int = 0,
245
+ ) -> List[Dict[str, Any]]:
246
+ conditions = []
247
+ params: list = []
248
+ if account_id:
249
+ conditions.append("account_id = ?")
250
+ params.append(account_id)
251
+ if status:
252
+ conditions.append("status = ?")
253
+ params.append(status)
254
+ where = f"WHERE {' AND '.join(conditions)}" if conditions else ""
255
+ sql = f"SELECT * FROM posts {where} ORDER BY created_at DESC LIMIT ? OFFSET ?"
256
+ params.extend([limit, offset])
257
+ with self._connect() as conn:
258
+ rows = conn.execute(sql, params).fetchall()
259
+ return [dict(r) for r in rows]
260
+
261
+ def get_posts_for_publishing(self, account_id: int) -> List[Dict[str, Any]]:
262
+ """Posts aprovados/agendados prontos para publicar."""
263
+ now = datetime.now(timezone.utc).isoformat()
264
+ sql = """
265
+ SELECT * FROM posts
266
+ WHERE account_id = ? AND (
267
+ status = 'approved'
268
+ OR (status = 'scheduled' AND scheduled_at <= ?)
269
+ OR status = 'container_created'
270
+ )
271
+ ORDER BY scheduled_at ASC, created_at ASC
272
+ """
273
+ with self._connect() as conn:
274
+ rows = conn.execute(sql, [account_id, now]).fetchall()
275
+ return [dict(r) for r in rows]
276
+
277
+ def get_post_by_id(self, post_id: int) -> Optional[Dict[str, Any]]:
278
+ with self._connect() as conn:
279
+ row = conn.execute("SELECT * FROM posts WHERE id = ?", [post_id]).fetchone()
280
+ return dict(row) if row else None
281
+
282
+ # ── Comments ──────────────────────────────────────────────────────────────
283
+
284
+ def upsert_comments(self, comments: List[Dict[str, Any]]) -> int:
285
+ sql = """
286
+ INSERT INTO comments (account_id, ig_comment_id, ig_media_id, username, text, timestamp)
287
+ VALUES (:account_id, :ig_comment_id, :ig_media_id, :username, :text, :timestamp)
288
+ ON CONFLICT(ig_comment_id) DO UPDATE SET
289
+ text = excluded.text,
290
+ timestamp = excluded.timestamp
291
+ """
292
+ with self._connect() as conn:
293
+ conn.executemany(sql, comments)
294
+ return len(comments)
295
+
296
+ def get_comments(
297
+ self,
298
+ ig_media_id: Optional[str] = None,
299
+ account_id: Optional[int] = None,
300
+ unreplied_only: bool = False,
301
+ limit: int = 50,
302
+ ) -> List[Dict[str, Any]]:
303
+ conditions = []
304
+ params: list = []
305
+ if ig_media_id:
306
+ conditions.append("ig_media_id = ?")
307
+ params.append(ig_media_id)
308
+ if account_id:
309
+ conditions.append("account_id = ?")
310
+ params.append(account_id)
311
+ if unreplied_only:
312
+ conditions.append("replied = 0")
313
+ where = f"WHERE {' AND '.join(conditions)}" if conditions else ""
314
+ sql = f"SELECT * FROM comments {where} ORDER BY timestamp DESC LIMIT ?"
315
+ params.append(limit)
316
+ with self._connect() as conn:
317
+ rows = conn.execute(sql, params).fetchall()
318
+ return [dict(r) for r in rows]
319
+
320
+ # ── Insights ──────────────────────────────────────────────────────────────
321
+
322
+ def insert_insights(self, records: List[Dict[str, Any]]) -> int:
323
+ sql = """
324
+ INSERT INTO insights (account_id, ig_media_id, metric_name, metric_value, period, raw_json)
325
+ VALUES (:account_id, :ig_media_id, :metric_name, :metric_value, :period, :raw_json)
326
+ """
327
+ with self._connect() as conn:
328
+ conn.executemany(sql, records)
329
+ return len(records)
330
+
331
+ def insert_user_insights(self, records: List[Dict[str, Any]]) -> int:
332
+ sql = """
333
+ INSERT INTO user_insights (account_id, metric_name, metric_value, period, end_time)
334
+ VALUES (:account_id, :metric_name, :metric_value, :period, :end_time)
335
+ """
336
+ with self._connect() as conn:
337
+ conn.executemany(sql, records)
338
+ return len(records)
339
+
340
+ # ── Templates ─────────────────────────────────────────────────────────────
341
+
342
+ def upsert_template(self, data: Dict[str, Any]) -> int:
343
+ sql = """
344
+ INSERT INTO templates (name, caption_template, hashtag_set, default_schedule_time)
345
+ VALUES (:name, :caption_template, :hashtag_set, :default_schedule_time)
346
+ ON CONFLICT(name) DO UPDATE SET
347
+ caption_template = excluded.caption_template,
348
+ hashtag_set = excluded.hashtag_set,
349
+ default_schedule_time = excluded.default_schedule_time
350
+ """
351
+ with self._connect() as conn:
352
+ conn.execute(sql, data)
353
+ row = conn.execute("SELECT id FROM templates WHERE name = ?", [data["name"]]).fetchone()
354
+ return row["id"]
355
+
356
+ def get_templates(self) -> List[Dict[str, Any]]:
357
+ with self._connect() as conn:
358
+ rows = conn.execute("SELECT * FROM templates ORDER BY name").fetchall()
359
+ return [dict(r) for r in rows]
360
+
361
+ def get_template_by_name(self, name: str) -> Optional[Dict[str, Any]]:
362
+ with self._connect() as conn:
363
+ row = conn.execute("SELECT * FROM templates WHERE name = ?", [name]).fetchone()
364
+ return dict(row) if row else None
365
+
366
+ def delete_template(self, name: str) -> bool:
367
+ with self._connect() as conn:
368
+ cursor = conn.execute("DELETE FROM templates WHERE name = ?", [name])
369
+ return cursor.rowcount > 0
370
+
371
+ # ── Hashtag Searches ──────────────────────────────────────────────────────
372
+
373
+ def insert_hashtag_search(self, data: Dict[str, Any]) -> None:
374
+ sql = """
375
+ INSERT INTO hashtag_searches (account_id, hashtag, ig_hashtag_id)
376
+ VALUES (:account_id, :hashtag, :ig_hashtag_id)
377
+ """
378
+ with self._connect() as conn:
379
+ conn.execute(sql, data)
380
+
381
+ def count_hashtag_searches_last_week(self, account_id: int) -> int:
382
+ sql = """
383
+ SELECT COUNT(DISTINCT hashtag) FROM hashtag_searches
384
+ WHERE account_id = ? AND searched_at >= datetime('now', '-7 days')
385
+ """
386
+ with self._connect() as conn:
387
+ return conn.execute(sql, [account_id]).fetchone()[0]
388
+
389
+ # ── Action Log ────────────────────────────────────────────────────────────
390
+
391
+ def log_action(self, data: Dict[str, Any]) -> None:
392
+ sql = """
393
+ INSERT INTO action_log (account_id, action, params, result, confirmed, rate_remaining)
394
+ VALUES (:account_id, :action, :params, :result, :confirmed, :rate_remaining)
395
+ """
396
+ with self._connect() as conn:
397
+ conn.execute(sql, data)
398
+
399
+ def get_recent_actions(self, limit: int = 20, action: Optional[str] = None) -> List[Dict[str, Any]]:
400
+ if action:
401
+ sql = "SELECT * FROM action_log WHERE action = ? ORDER BY created_at DESC LIMIT ?"
402
+ params = [action, limit]
403
+ else:
404
+ sql = "SELECT * FROM action_log ORDER BY created_at DESC LIMIT ?"
405
+ params = [limit]
406
+ with self._connect() as conn:
407
+ rows = conn.execute(sql, params).fetchall()
408
+ return [dict(r) for r in rows]
409
+
410
+ # ── Stats ─────────────────────────────────────────────────────────────────
411
+
412
+ def get_stats(self) -> Dict[str, Any]:
413
+ """Retorna estatísticas gerais do banco."""
414
+ with self._connect() as conn:
415
+ accounts = conn.execute("SELECT COUNT(*) FROM accounts WHERE is_active = 1").fetchone()[0]
416
+ posts_total = conn.execute("SELECT COUNT(*) FROM posts").fetchone()[0]
417
+ posts_published = conn.execute("SELECT COUNT(*) FROM posts WHERE status = 'published'").fetchone()[0]
418
+ posts_draft = conn.execute("SELECT COUNT(*) FROM posts WHERE status = 'draft'").fetchone()[0]
419
+ posts_scheduled = conn.execute("SELECT COUNT(*) FROM posts WHERE status = 'scheduled'").fetchone()[0]
420
+ comments_total = conn.execute("SELECT COUNT(*) FROM comments").fetchone()[0]
421
+ comments_unreplied = conn.execute("SELECT COUNT(*) FROM comments WHERE replied = 0").fetchone()[0]
422
+ templates = conn.execute("SELECT COUNT(*) FROM templates").fetchone()[0]
423
+ actions_today = conn.execute(
424
+ "SELECT COUNT(*) FROM action_log WHERE created_at >= date('now')"
425
+ ).fetchone()[0]
426
+
427
+ return {
428
+ "accounts_active": accounts,
429
+ "posts": {
430
+ "total": posts_total,
431
+ "published": posts_published,
432
+ "draft": posts_draft,
433
+ "scheduled": posts_scheduled,
434
+ },
435
+ "comments": {
436
+ "total": comments_total,
437
+ "unreplied": comments_unreplied,
438
+ },
439
+ "templates": templates,
440
+ "actions_today": actions_today,
441
+ }
442
+
443
+ def count_requests_last_hour(self) -> int:
444
+ """Conta requests na última hora (para rate limiting)."""
445
+ sql = """
446
+ SELECT COUNT(*) FROM action_log
447
+ WHERE created_at >= datetime('now', '-1 hour')
448
+ """
449
+ with self._connect() as conn:
450
+ return conn.execute(sql).fetchone()[0]
451
+
452
+ def count_publishes_today(self) -> int:
453
+ """Conta publicações hoje (para rate limiting)."""
454
+ sql = """
455
+ SELECT COUNT(*) FROM action_log
456
+ WHERE action LIKE 'publish_%' AND created_at >= date('now')
457
+ """
458
+ with self._connect() as conn:
459
+ return conn.execute(sql).fetchone()[0]
460
+
461
+
462
+ # ── CLI rápido para verificação ──────────────────────────────────────────────
463
+ if __name__ == "__main__":
464
+ db = Database()
465
+ db.init()
466
+ stats = db.get_stats()
467
+ print(json.dumps(stats, indent=2, ensure_ascii=False))
@@ -0,0 +1,138 @@
1
+ """
2
+ Exportação de dados do Instagram para diferentes formatos.
3
+
4
+ Uso:
5
+ python scripts/export.py --type insights --format csv
6
+ python scripts/export.py --type comments --format json
7
+ python scripts/export.py --type posts --format jsonl
8
+ python scripts/export.py --type all --format csv
9
+ python scripts/export.py --type actions --format json --output /caminho/
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import csv
15
+ import json
16
+ import sys
17
+ from datetime import datetime, timezone
18
+ from pathlib import Path
19
+
20
+ sys.path.insert(0, str(Path(__file__).parent))
21
+
22
+ from config import EXPORTS_DIR
23
+ from db import Database
24
+
25
+ db = Database()
26
+ db.init()
27
+
28
+
29
+ def export_json(records: list, output_dir: Path, name: str) -> Path:
30
+ output_dir.mkdir(parents=True, exist_ok=True)
31
+ ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
32
+ path = output_dir / f"instagram_{name}_{ts}.json"
33
+ with open(path, "w", encoding="utf-8") as f:
34
+ json.dump(
35
+ {"exported_at": datetime.now(timezone.utc).isoformat(), "total": len(records), "data": records},
36
+ f, ensure_ascii=False, indent=2,
37
+ )
38
+ print(f"[JSON] {len(records)} registros ->{path}")
39
+ return path
40
+
41
+
42
+ def export_jsonl(records: list, output_dir: Path, name: str) -> Path:
43
+ output_dir.mkdir(parents=True, exist_ok=True)
44
+ ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
45
+ path = output_dir / f"instagram_{name}_{ts}.jsonl"
46
+ with open(path, "w", encoding="utf-8") as f:
47
+ for rec in records:
48
+ f.write(json.dumps(rec, ensure_ascii=False) + "\n")
49
+ print(f"[JSONL] {len(records)} registros ->{path}")
50
+ return path
51
+
52
+
53
+ def export_csv_file(records: list, output_dir: Path, name: str) -> Path:
54
+ if not records:
55
+ print("[CSV] Nenhum registro para exportar.")
56
+ return None
57
+ output_dir.mkdir(parents=True, exist_ok=True)
58
+ ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
59
+ path = output_dir / f"instagram_{name}_{ts}.csv"
60
+ with open(path, "w", newline="", encoding="utf-8-sig") as f:
61
+ writer = csv.DictWriter(f, fieldnames=list(records[0].keys()), extrasaction="ignore")
62
+ writer.writeheader()
63
+ writer.writerows(records)
64
+ print(f"[CSV] {len(records)} registros ->{path}")
65
+ return path
66
+
67
+
68
+ def get_data(data_type: str) -> tuple:
69
+ """Retorna (records, name) para o tipo de dados."""
70
+ conn = db._connect()
71
+
72
+ if data_type == "posts":
73
+ rows = conn.execute("SELECT * FROM posts ORDER BY created_at DESC").fetchall()
74
+ return [dict(r) for r in rows], "posts"
75
+ elif data_type == "comments":
76
+ rows = conn.execute("SELECT * FROM comments ORDER BY timestamp DESC").fetchall()
77
+ return [dict(r) for r in rows], "comments"
78
+ elif data_type == "insights":
79
+ rows = conn.execute("""
80
+ SELECT i.*, p.caption, p.permalink
81
+ FROM insights i
82
+ LEFT JOIN posts p ON p.ig_media_id = i.ig_media_id
83
+ ORDER BY i.fetched_at DESC
84
+ """).fetchall()
85
+ return [dict(r) for r in rows], "insights"
86
+ elif data_type == "user_insights":
87
+ rows = conn.execute("SELECT * FROM user_insights ORDER BY end_time DESC").fetchall()
88
+ return [dict(r) for r in rows], "user_insights"
89
+ elif data_type == "templates":
90
+ rows = conn.execute("SELECT * FROM templates ORDER BY name").fetchall()
91
+ return [dict(r) for r in rows], "templates"
92
+ elif data_type == "actions":
93
+ rows = conn.execute("SELECT * FROM action_log ORDER BY created_at DESC").fetchall()
94
+ return [dict(r) for r in rows], "actions"
95
+ elif data_type == "all":
96
+ return None, "all"
97
+ else:
98
+ return [], data_type
99
+
100
+
101
+ def do_export(records: list, name: str, fmt: str, output_dir: Path) -> None:
102
+ if fmt in ("json", "all"):
103
+ export_json(records, output_dir, name)
104
+ if fmt in ("jsonl", "all"):
105
+ export_jsonl(records, output_dir, name)
106
+ if fmt in ("csv", "all"):
107
+ export_csv_file(records, output_dir, name)
108
+
109
+
110
+ def main():
111
+ parser = argparse.ArgumentParser(description="Exportar dados do Instagram")
112
+ parser.add_argument("--type", required=True,
113
+ choices=["posts", "comments", "insights", "user_insights", "templates", "actions", "all"],
114
+ help="Tipo de dados")
115
+ parser.add_argument("--format", default="csv", choices=["json", "jsonl", "csv", "all"],
116
+ help="Formato (default: csv)")
117
+ parser.add_argument("--output", default=str(EXPORTS_DIR), help=f"Diretório (default: {EXPORTS_DIR})")
118
+ args = parser.parse_args()
119
+
120
+ output_dir = Path(args.output)
121
+
122
+ if args.type == "all":
123
+ for dtype in ["posts", "comments", "insights", "user_insights", "templates", "actions"]:
124
+ records, name = get_data(dtype)
125
+ if records:
126
+ do_export(records, name, args.format, output_dir)
127
+ else:
128
+ print(f"[{dtype}] Sem dados.")
129
+ else:
130
+ records, name = get_data(args.type)
131
+ if not records:
132
+ print("Sem dados para exportar.")
133
+ return
134
+ do_export(records, name, args.format, output_dir)
135
+
136
+
137
+ if __name__ == "__main__":
138
+ main()