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,319 @@
1
+ """
2
+ Gerador de resumos estruturados de sessão.
3
+ Analisa mensagens e gera session-NNN.md.
4
+ """
5
+
6
+ import re
7
+ from datetime import datetime
8
+ from pathlib import Path
9
+
10
+ from config import (
11
+ SESSIONS_DIR,
12
+ DECISION_MARKERS,
13
+ PENDING_MARKERS,
14
+ )
15
+ from models import SessionSummary, PendingTask, SessionEntry
16
+
17
+
18
+ def get_next_session_number() -> int:
19
+ """Retorna o próximo número de sessão disponível."""
20
+ SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
21
+ existing = list(SESSIONS_DIR.glob("session-*.md"))
22
+ if not existing:
23
+ return 1
24
+ numbers = []
25
+ for f in existing:
26
+ try:
27
+ num = int(f.stem.split("-")[1])
28
+ numbers.append(num)
29
+ except (IndexError, ValueError):
30
+ continue
31
+ return max(numbers) + 1 if numbers else 1
32
+
33
+
34
+ def generate_summary(
35
+ entries: list[SessionEntry],
36
+ session_number: int,
37
+ metadata: dict,
38
+ ) -> SessionSummary:
39
+ """Gera um resumo estruturado a partir das entradas da sessão."""
40
+ user_messages = [e.content for e in entries if e.role == "user" and e.content.strip()]
41
+ assistant_messages = [e.content for e in entries if e.role == "assistant" and e.content.strip()]
42
+ all_messages = user_messages + assistant_messages
43
+ all_tool_calls = []
44
+ all_files_modified = []
45
+
46
+ for e in entries:
47
+ all_tool_calls.extend(e.tool_calls)
48
+ all_files_modified.extend(e.files_modified)
49
+
50
+ # Deduplicate files
51
+ seen_files = set()
52
+ unique_files = []
53
+ for f in all_files_modified:
54
+ if f["path"] not in seen_files:
55
+ seen_files.add(f["path"])
56
+ unique_files.append(f)
57
+
58
+ # Extrair data
59
+ date_str = ""
60
+ start_time = metadata.get("start_time", "")
61
+ if start_time:
62
+ try:
63
+ dt = datetime.fromisoformat(start_time.replace("Z", "+00:00"))
64
+ date_str = dt.strftime("%Y-%m-%d")
65
+ except ValueError:
66
+ date_str = datetime.now().strftime("%Y-%m-%d")
67
+ else:
68
+ date_str = datetime.now().strftime("%Y-%m-%d")
69
+
70
+ summary = SessionSummary(
71
+ session_number=session_number,
72
+ session_id=metadata.get("session_id", ""),
73
+ slug=metadata.get("slug", ""),
74
+ date=date_str,
75
+ start_time=start_time,
76
+ end_time=metadata.get("end_time", ""),
77
+ duration_minutes=metadata.get("duration_minutes", 0),
78
+ model=metadata.get("model", ""),
79
+ total_input_tokens=metadata.get("total_input_tokens", 0),
80
+ total_output_tokens=metadata.get("total_output_tokens", 0),
81
+ total_cache_tokens=metadata.get("total_cache_tokens", 0),
82
+ message_count=metadata.get("message_count", 0),
83
+ tool_call_count=metadata.get("tool_call_count", 0),
84
+ files_modified=unique_files,
85
+ )
86
+
87
+ # Extrair tópicos das mensagens do usuário
88
+ summary.topics = _extract_topics(user_messages)
89
+
90
+ # Extrair decisões
91
+ summary.decisions = _extract_decisions(all_messages)
92
+
93
+ # Extrair tarefas
94
+ summary.tasks_completed = _extract_completed_tasks(all_messages)
95
+ summary.tasks_pending = _extract_pending_tasks(all_messages, session_number, date_str)
96
+
97
+ # Extrair erros
98
+ summary.errors_resolved = _extract_errors(assistant_messages)
99
+
100
+ # Extrair findings
101
+ summary.key_findings = _extract_findings(assistant_messages)
102
+
103
+ return summary
104
+
105
+
106
+ def _extract_topics(user_messages: list[str]) -> list[str]:
107
+ """Identifica tópicos principais das mensagens do usuário."""
108
+ topics = []
109
+ for msg in user_messages:
110
+ # Limpar mensagens muito longas
111
+ msg_clean = msg[:500] if len(msg) > 500 else msg
112
+ # Pegar a primeira frase significativa como tópico
113
+ sentences = re.split(r'[.!?\n]', msg_clean)
114
+ for s in sentences:
115
+ s = s.strip()
116
+ if len(s) > 10 and len(s) < 200:
117
+ topics.append(s)
118
+ break
119
+
120
+ # Deduplicate e limitar
121
+ seen = set()
122
+ unique = []
123
+ for t in topics:
124
+ t_lower = t.lower()
125
+ if t_lower not in seen:
126
+ seen.add(t_lower)
127
+ unique.append(t)
128
+
129
+ return unique[:10]
130
+
131
+
132
+ def _extract_decisions(messages: list[str]) -> list[str]:
133
+ """Encontra decisões nas mensagens."""
134
+ decisions = []
135
+ for msg in messages:
136
+ for line in msg.split("\n"):
137
+ line_lower = line.lower().strip()
138
+ for marker in DECISION_MARKERS:
139
+ if marker in line_lower:
140
+ clean = line.strip()
141
+ if 15 < len(clean) < 300:
142
+ decisions.append(clean)
143
+ break
144
+ return list(dict.fromkeys(decisions))[:10] # Deduplicate, max 10
145
+
146
+
147
+ def _extract_completed_tasks(messages: list[str]) -> list[str]:
148
+ """Encontra tarefas concluídas."""
149
+ completed = []
150
+ patterns = [
151
+ r"- \[x\]\s+(.+)",
152
+ r"✅\s+(.+)",
153
+ r"(?:concluí|completei|terminei|finalizei|done|completed|finished)\s+(.+)",
154
+ ]
155
+ for msg in messages:
156
+ for line in msg.split("\n"):
157
+ for pattern in patterns:
158
+ m = re.search(pattern, line, re.IGNORECASE)
159
+ if m:
160
+ task = m.group(1).strip()
161
+ if len(task) > 5:
162
+ completed.append(task)
163
+ return list(dict.fromkeys(completed))[:15]
164
+
165
+
166
+ def _extract_pending_tasks(
167
+ messages: list[str],
168
+ session_number: int,
169
+ date: str,
170
+ ) -> list[PendingTask]:
171
+ """Encontra tarefas pendentes. Foca em checkboxes não marcados nas mensagens do user."""
172
+ tasks = []
173
+ for msg in messages:
174
+ # Ignorar mensagens muito longas (provavelmente tool results, não conversação)
175
+ if len(msg) > 5000:
176
+ continue
177
+
178
+ for line in msg.split("\n"):
179
+ stripped = line.strip()
180
+
181
+ # Checkbox não marcado — sinal claro de tarefa
182
+ m = re.match(r"- \[ \]\s+(.+)", stripped)
183
+ if m:
184
+ desc = m.group(1).strip()
185
+ # Filtrar descrições que parecem código/documentação
186
+ if 10 < len(desc) < 200 and not desc.startswith("`") and not desc.startswith("-"):
187
+ tasks.append(PendingTask(
188
+ description=desc,
189
+ source_session=session_number,
190
+ created_date=date,
191
+ ))
192
+
193
+ # Deduplicate
194
+ seen = set()
195
+ unique = []
196
+ for t in tasks:
197
+ if t.description not in seen:
198
+ seen.add(t.description)
199
+ unique.append(t)
200
+
201
+ return unique[:10]
202
+
203
+
204
+ def _extract_errors(assistant_messages: list[str]) -> list[dict]:
205
+ """Encontra erros e suas soluções."""
206
+ errors = []
207
+ error_patterns = [
208
+ r"(?:error|erro|falha|failed|exception)[\s:]+(.+)",
209
+ ]
210
+ for msg in assistant_messages:
211
+ for pattern in error_patterns:
212
+ matches = re.findall(pattern, msg, re.IGNORECASE)
213
+ for match in matches:
214
+ if len(match) > 10:
215
+ errors.append({"error": match[:200], "solution": ""})
216
+ return errors[:5]
217
+
218
+
219
+ def _extract_findings(assistant_messages: list[str]) -> list[str]:
220
+ """Extrai descobertas/findings importantes."""
221
+ findings = []
222
+ markers = [
223
+ "descobri que", "encontrei", "notei que", "importante:",
224
+ "found that", "noticed that", "important:", "key finding",
225
+ ]
226
+ for msg in assistant_messages:
227
+ for line in msg.split("\n"):
228
+ line_lower = line.lower().strip()
229
+ for marker in markers:
230
+ if marker in line_lower and len(line.strip()) > 20:
231
+ findings.append(line.strip()[:200])
232
+ break
233
+ return list(dict.fromkeys(findings))[:5]
234
+
235
+
236
+ def save_session_summary(summary: SessionSummary):
237
+ """Salva resumo como arquivo markdown."""
238
+ SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
239
+ path = SESSIONS_DIR / f"session-{summary.session_number:03d}.md"
240
+
241
+ lines = [
242
+ f"# Sessão {summary.session_number:03d} — {summary.date}",
243
+ f"**Slug:** {summary.slug} | **Duração:** ~{summary.duration_minutes}min | **Modelo:** {summary.model}",
244
+ "",
245
+ ]
246
+
247
+ if summary.topics:
248
+ lines.append("## Tópicos")
249
+ for t in summary.topics:
250
+ lines.append(f"- {t}")
251
+ lines.append("")
252
+
253
+ if summary.decisions:
254
+ lines.append("## Decisões")
255
+ for d in summary.decisions:
256
+ lines.append(f"- {d}")
257
+ lines.append("")
258
+
259
+ if summary.tasks_completed:
260
+ lines.append("## Tarefas Concluídas")
261
+ for t in summary.tasks_completed:
262
+ lines.append(f"- [x] {t}")
263
+ lines.append("")
264
+
265
+ if summary.tasks_pending:
266
+ lines.append("## Tarefas Pendentes")
267
+ for t in summary.tasks_pending:
268
+ if isinstance(t, PendingTask):
269
+ lines.append(f"- [ ] {t.description} (prioridade: {t.priority})")
270
+ else:
271
+ lines.append(f"- [ ] {t}")
272
+ lines.append("")
273
+
274
+ if summary.files_modified:
275
+ lines.append("## Arquivos Modificados")
276
+ for f in summary.files_modified:
277
+ lines.append(f"- `{f['path']}` — {f['action']}")
278
+ lines.append("")
279
+
280
+ if summary.key_findings:
281
+ lines.append("## Descobertas")
282
+ for f in summary.key_findings:
283
+ lines.append(f"- {f}")
284
+ lines.append("")
285
+
286
+ if summary.errors_resolved:
287
+ lines.append("## Erros Resolvidos")
288
+ for e in summary.errors_resolved:
289
+ lines.append(f"- {e['error']}")
290
+ lines.append("")
291
+
292
+ if summary.open_questions:
293
+ lines.append("## Questões em Aberto")
294
+ for q in summary.open_questions:
295
+ lines.append(f"- {q}")
296
+ lines.append("")
297
+
298
+ if summary.technical_debt:
299
+ lines.append("## Dívida Técnica")
300
+ for d in summary.technical_debt:
301
+ lines.append(f"- {d}")
302
+ lines.append("")
303
+
304
+ lines.append("## Métricas")
305
+ lines.append(f"- Input tokens: {summary.total_input_tokens:,}")
306
+ lines.append(f"- Output tokens: {summary.total_output_tokens:,}")
307
+ lines.append(f"- Cache tokens: {summary.total_cache_tokens:,}")
308
+ lines.append(f"- Mensagens: {summary.message_count}")
309
+ lines.append(f"- Tool calls: {summary.tool_call_count}")
310
+ lines.append("")
311
+
312
+ # Link para sessão anterior
313
+ if summary.session_number > 1:
314
+ prev = summary.session_number - 1
315
+ lines.append("---")
316
+ lines.append(f"*Sessão anterior: [session-{prev:03d}](session-{prev:03d}.md)*")
317
+
318
+ path.write_text("\n".join(lines), encoding="utf-8")
319
+ return path
@@ -0,0 +1,229 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Context Guardian — Snapshot Manager.
4
+
5
+ Cria, lista e le snapshots de contexto para preservacao
6
+ pre-compactacao. Os snapshots sao arquivos .md estruturados
7
+ com todas as informacoes criticas de uma sessao.
8
+
9
+ Uso:
10
+ python context_snapshot.py save --project "nome" --phase "fase" --summary "resumo"
11
+ python context_snapshot.py list
12
+ python context_snapshot.py latest
13
+ python context_snapshot.py read <snapshot-file>
14
+ python context_snapshot.py prune --keep 10
15
+ """
16
+
17
+ import json
18
+ import sys
19
+ import os
20
+ from datetime import datetime
21
+ from pathlib import Path
22
+
23
+ # ── Paths ──────────────────────────────────────────────────────────────────
24
+ SCRIPT_DIR = Path(__file__).resolve().parent
25
+ SKILL_DIR = SCRIPT_DIR.parent
26
+ DATA_DIR = SKILL_DIR / "data"
27
+
28
+ # ── Functions ──────────────────────────────────────────────────────────────
29
+
30
+ def ensure_data_dir():
31
+ """Create data directory if it doesn't exist."""
32
+ DATA_DIR.mkdir(parents=True, exist_ok=True)
33
+
34
+
35
+ def save_snapshot(project: str = "", phase: str = "", summary: str = "") -> str:
36
+ """
37
+ Create a new snapshot file with metadata header.
38
+ Returns the path to the created file.
39
+
40
+ The Claude agent is expected to APPEND the actual content
41
+ (extracted from the conversation) after this header is created.
42
+ """
43
+ ensure_data_dir()
44
+
45
+ timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
46
+ filename = f"snapshot-{timestamp}.md"
47
+ filepath = DATA_DIR / filename
48
+
49
+ header = f"""# Context Guardian Snapshot — {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
50
+ **Projeto**: {project or 'nao especificado'}
51
+ **Fase**: {phase or 'nao especificada'}
52
+ **Resumo**: {summary or 'snapshot pre-compactacao'}
53
+ **Modelo**: claude-opus-4-6
54
+
55
+ ---
56
+
57
+ <!-- O Claude deve preencher as secoes abaixo seguindo references/extraction-protocol.md -->
58
+
59
+ ## Arquivos Tocados
60
+ | Arquivo | Acao | Detalhes |
61
+ |---------|------|----------|
62
+ | | | |
63
+
64
+ ## Decisoes
65
+ - (preencher)
66
+
67
+ ## Correcoes
68
+ - (preencher)
69
+
70
+ ## Progresso
71
+ - Total de tarefas:
72
+ - Concluidas:
73
+ - Pendentes:
74
+
75
+ ## Trechos Criticos
76
+ - (preencher)
77
+
78
+ ## Padroes Observados
79
+ - (preencher)
80
+
81
+ ## Dependencias
82
+ - (preencher)
83
+
84
+ ## Contexto do Usuario
85
+ - Objetivo:
86
+ - Proxima acao esperada:
87
+
88
+ ---
89
+ *Snapshot gerado por context-guardian v1.0.0*
90
+ *Para restaurar: leia este arquivo + MEMORY.md + context_manager.py load*
91
+ """
92
+
93
+ filepath.write_text(header, encoding="utf-8")
94
+ return str(filepath)
95
+
96
+
97
+ def list_snapshots() -> list[dict]:
98
+ """List all snapshots with metadata."""
99
+ ensure_data_dir()
100
+ snapshots = []
101
+
102
+ for f in sorted(DATA_DIR.glob("snapshot-*.md"), reverse=True):
103
+ stat = f.stat()
104
+ snapshots.append({
105
+ "file": f.name,
106
+ "path": str(f),
107
+ "size_kb": round(stat.st_size / 1024, 1),
108
+ "modified": datetime.fromtimestamp(stat.st_mtime).strftime("%Y-%m-%d %H:%M:%S"),
109
+ })
110
+
111
+ return snapshots
112
+
113
+
114
+ def read_latest() -> dict:
115
+ """Read the most recent snapshot."""
116
+ snapshots = list_snapshots()
117
+ if not snapshots:
118
+ return {"error": "Nenhum snapshot encontrado."}
119
+
120
+ latest = snapshots[0]
121
+ path = Path(latest["path"])
122
+ content = path.read_text(encoding="utf-8")
123
+
124
+ return {
125
+ "file": latest["file"],
126
+ "path": latest["path"],
127
+ "size_kb": latest["size_kb"],
128
+ "content": content,
129
+ }
130
+
131
+
132
+ def read_snapshot(filename: str) -> dict:
133
+ """Read a specific snapshot by filename."""
134
+ filepath = DATA_DIR / filename
135
+ if not filepath.exists():
136
+ return {"error": f"Arquivo nao encontrado: {filename}"}
137
+
138
+ content = filepath.read_text(encoding="utf-8")
139
+ return {
140
+ "file": filename,
141
+ "path": str(filepath),
142
+ "content": content,
143
+ }
144
+
145
+
146
+ def prune_snapshots(keep: int = 10) -> dict:
147
+ """Remove old snapshots, keeping the N most recent."""
148
+ snapshots = list_snapshots()
149
+ if len(snapshots) <= keep:
150
+ return {"pruned": 0, "remaining": len(snapshots)}
151
+
152
+ to_remove = snapshots[keep:]
153
+ for s in to_remove:
154
+ Path(s["path"]).unlink()
155
+
156
+ return {"pruned": len(to_remove), "remaining": keep}
157
+
158
+
159
+ # ── CLI ────────────────────────────────────────────────────────────────────
160
+
161
+ def main():
162
+ args = sys.argv[1:]
163
+
164
+ if not args:
165
+ print(json.dumps({
166
+ "error": "Comando necessario: save, list, latest, read, prune",
167
+ "usage": "python context_snapshot.py <command> [options]",
168
+ }, indent=2, ensure_ascii=False))
169
+ sys.exit(1)
170
+
171
+ cmd = args[0]
172
+
173
+ if cmd == "save":
174
+ project = ""
175
+ phase = ""
176
+ summary = ""
177
+ i = 1
178
+ while i < len(args):
179
+ if args[i] == "--project" and i + 1 < len(args):
180
+ project = args[i + 1]
181
+ i += 2
182
+ elif args[i] == "--phase" and i + 1 < len(args):
183
+ phase = args[i + 1]
184
+ i += 2
185
+ elif args[i] == "--summary" and i + 1 < len(args):
186
+ summary = args[i + 1]
187
+ i += 2
188
+ else:
189
+ i += 1
190
+
191
+ path = save_snapshot(project, phase, summary)
192
+ print(json.dumps({
193
+ "status": "ok",
194
+ "action": "snapshot_created",
195
+ "path": path,
196
+ "next_step": "Preencher o snapshot com dados extraidos da conversa",
197
+ }, indent=2, ensure_ascii=False))
198
+
199
+ elif cmd == "list":
200
+ snapshots = list_snapshots()
201
+ print(json.dumps({
202
+ "total": len(snapshots),
203
+ "snapshots": snapshots,
204
+ }, indent=2, ensure_ascii=False))
205
+
206
+ elif cmd == "latest":
207
+ result = read_latest()
208
+ print(json.dumps(result, indent=2, ensure_ascii=False))
209
+
210
+ elif cmd == "read" and len(args) > 1:
211
+ result = read_snapshot(args[1])
212
+ print(json.dumps(result, indent=2, ensure_ascii=False))
213
+
214
+ elif cmd == "prune":
215
+ keep = 10
216
+ if "--keep" in args:
217
+ idx = args.index("--keep")
218
+ if idx + 1 < len(args):
219
+ keep = int(args[idx + 1])
220
+ result = prune_snapshots(keep)
221
+ print(json.dumps(result, indent=2, ensure_ascii=False))
222
+
223
+ else:
224
+ print(json.dumps({"error": f"Comando desconhecido: {cmd}"}, indent=2))
225
+ sys.exit(1)
226
+
227
+
228
+ if __name__ == "__main__":
229
+ main()
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Tool to pack a directory into a .docx, .pptx, or .xlsx file with XML formatting undone.
4
+
5
+ Example usage:
6
+ python pack.py <input_directory> <office_file> [--force]
7
+ """
8
+
9
+ import argparse
10
+ import shutil
11
+ import subprocess
12
+ import sys
13
+ import tempfile
14
+ import defusedxml.minidom
15
+ import zipfile
16
+ from pathlib import Path
17
+
18
+
19
+ def main():
20
+ parser = argparse.ArgumentParser(description="Pack a directory into an Office file")
21
+ parser.add_argument("input_directory", help="Unpacked Office document directory")
22
+ parser.add_argument("output_file", help="Output Office file (.docx/.pptx/.xlsx)")
23
+ parser.add_argument("--force", action="store_true", help="Skip validation")
24
+ args = parser.parse_args()
25
+
26
+ try:
27
+ success = pack_document(
28
+ args.input_directory, args.output_file, validate=not args.force
29
+ )
30
+
31
+ # Show warning if validation was skipped
32
+ if args.force:
33
+ print("Warning: Skipped validation, file may be corrupt", file=sys.stderr)
34
+ # Exit with error if validation failed
35
+ elif not success:
36
+ print("Contents would produce a corrupt file.", file=sys.stderr)
37
+ print("Please validate XML before repacking.", file=sys.stderr)
38
+ print("Use --force to skip validation and pack anyway.", file=sys.stderr)
39
+ sys.exit(1)
40
+
41
+ except ValueError as e:
42
+ sys.exit(f"Error: {e}")
43
+
44
+
45
+ def pack_document(input_dir, output_file, validate=False):
46
+ """Pack a directory into an Office file (.docx/.pptx/.xlsx).
47
+
48
+ Args:
49
+ input_dir: Path to unpacked Office document directory
50
+ output_file: Path to output Office file
51
+ validate: If True, validates with soffice (default: False)
52
+
53
+ Returns:
54
+ bool: True if successful, False if validation failed
55
+ """
56
+ input_dir = Path(input_dir)
57
+ output_file = Path(output_file)
58
+
59
+ if not input_dir.is_dir():
60
+ raise ValueError(f"{input_dir} is not a directory")
61
+ if output_file.suffix.lower() not in {".docx", ".pptx", ".xlsx"}:
62
+ raise ValueError(f"{output_file} must be a .docx, .pptx, or .xlsx file")
63
+
64
+ # Work in temporary directory to avoid modifying original
65
+ with tempfile.TemporaryDirectory() as temp_dir:
66
+ temp_content_dir = Path(temp_dir) / "content"
67
+ shutil.copytree(input_dir, temp_content_dir)
68
+
69
+ # Process XML files to remove pretty-printing whitespace
70
+ for pattern in ["*.xml", "*.rels"]:
71
+ for xml_file in temp_content_dir.rglob(pattern):
72
+ condense_xml(xml_file)
73
+
74
+ # Create final Office file as zip archive
75
+ output_file.parent.mkdir(parents=True, exist_ok=True)
76
+ with zipfile.ZipFile(output_file, "w", zipfile.ZIP_DEFLATED) as zf:
77
+ for f in temp_content_dir.rglob("*"):
78
+ if f.is_file():
79
+ zf.write(f, f.relative_to(temp_content_dir))
80
+
81
+ # Validate if requested
82
+ if validate:
83
+ if not validate_document(output_file):
84
+ output_file.unlink() # Delete the corrupt file
85
+ return False
86
+
87
+ return True
88
+
89
+
90
+ def validate_document(doc_path):
91
+ """Validate document by converting to HTML with soffice."""
92
+ # Determine the correct filter based on file extension
93
+ match doc_path.suffix.lower():
94
+ case ".docx":
95
+ filter_name = "html:HTML"
96
+ case ".pptx":
97
+ filter_name = "html:impress_html_Export"
98
+ case ".xlsx":
99
+ filter_name = "html:HTML (StarCalc)"
100
+
101
+ with tempfile.TemporaryDirectory() as temp_dir:
102
+ try:
103
+ result = subprocess.run(
104
+ [
105
+ "soffice",
106
+ "--headless",
107
+ "--convert-to",
108
+ filter_name,
109
+ "--outdir",
110
+ temp_dir,
111
+ str(doc_path),
112
+ ],
113
+ capture_output=True,
114
+ timeout=10,
115
+ text=True,
116
+ )
117
+ if not (Path(temp_dir) / f"{doc_path.stem}.html").exists():
118
+ error_msg = result.stderr.strip() or "Document validation failed"
119
+ print(f"Validation error: {error_msg}", file=sys.stderr)
120
+ return False
121
+ return True
122
+ except FileNotFoundError:
123
+ print("Warning: soffice not found. Skipping validation.", file=sys.stderr)
124
+ return True
125
+ except subprocess.TimeoutExpired:
126
+ print("Validation error: Timeout during conversion", file=sys.stderr)
127
+ return False
128
+ except Exception as e:
129
+ print(f"Validation error: {e}", file=sys.stderr)
130
+ return False
131
+
132
+
133
+ def condense_xml(xml_file):
134
+ """Strip unnecessary whitespace and remove comments."""
135
+ with open(xml_file, "r", encoding="utf-8") as f:
136
+ dom = defusedxml.minidom.parse(f)
137
+
138
+ # Process each element to remove whitespace and comments
139
+ for element in dom.getElementsByTagName("*"):
140
+ # Skip w:t elements and their processing
141
+ if element.tagName.endswith(":t"):
142
+ continue
143
+
144
+ # Remove whitespace-only text nodes and comment nodes
145
+ for child in list(element.childNodes):
146
+ if (
147
+ child.nodeType == child.TEXT_NODE
148
+ and child.nodeValue
149
+ and child.nodeValue.strip() == ""
150
+ ) or child.nodeType == child.COMMENT_NODE:
151
+ element.removeChild(child)
152
+
153
+ # Write back the condensed XML
154
+ with open(xml_file, "wb") as f:
155
+ f.write(dom.toxml(encoding="UTF-8"))
156
+
157
+
158
+ if __name__ == "__main__":
159
+ main()