sinapse-ai 1.2.1 → 1.4.0

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 (257) hide show
  1. package/.claude/hooks/README.md +16 -10
  2. package/.claude/hooks/mind-clone-governance.py +212 -212
  3. package/.claude/hooks/read-protection.py +152 -152
  4. package/.claude/hooks/slug-validation.py +175 -175
  5. package/.claude/hooks/sql-governance.py +183 -183
  6. package/.claude/rules/documentation-first.md +69 -0
  7. package/.claude/rules/project-intelligence.md +121 -16
  8. package/.claude/rules/safe-collaboration.md +2 -2
  9. package/.codex/agents/developer.md +1 -0
  10. package/.codex/agents/product-lead.md +1 -0
  11. package/.codex/agents/project-lead.md +1 -0
  12. package/.codex/agents/quality-gate.md +1 -0
  13. package/.codex/agents/snps-orqx.md +72 -10
  14. package/.codex/agents/sprint-lead.md +1 -0
  15. package/.sinapse-ai/constitution.md +5 -5
  16. package/.sinapse-ai/core/grounding/vault.cjs +1 -1
  17. package/.sinapse-ai/core/orchestration/bob-orchestrator.js +341 -21
  18. package/.sinapse-ai/core/orchestration/brownfield-handler.js +27 -5
  19. package/.sinapse-ai/core/orchestration/greenfield-handler.js +61 -2
  20. package/.sinapse-ai/core-config.yaml +0 -3
  21. package/.sinapse-ai/data/entity-registry.yaml +13540 -13688
  22. package/.sinapse-ai/development/agents/developer.md +1 -0
  23. package/.sinapse-ai/development/agents/product-lead.md +1 -0
  24. package/.sinapse-ai/development/agents/project-lead.md +1 -0
  25. package/.sinapse-ai/development/agents/quality-gate.md +1 -0
  26. package/.sinapse-ai/development/agents/snps-orqx.md +72 -10
  27. package/.sinapse-ai/development/agents/sprint-lead.md +1 -0
  28. package/.sinapse-ai/development/scripts/unified-activation-pipeline.js +4 -9
  29. package/.sinapse-ai/development/tasks/brownfield-create-story.md +13 -0
  30. package/.sinapse-ai/development/tasks/create-brownfield-story.md +14 -0
  31. package/.sinapse-ai/development/tasks/push-and-pr.md +89 -0
  32. package/.sinapse-ai/development/tasks/self-heal.md +84 -0
  33. package/.sinapse-ai/development/templates/service-template/README.md.hbs +159 -159
  34. package/.sinapse-ai/development/templates/service-template/__tests__/index.test.ts.hbs +238 -238
  35. package/.sinapse-ai/development/templates/service-template/client.ts.hbs +404 -404
  36. package/.sinapse-ai/development/templates/service-template/errors.ts.hbs +183 -183
  37. package/.sinapse-ai/development/templates/service-template/index.ts.hbs +121 -121
  38. package/.sinapse-ai/development/templates/service-template/package.json.hbs +88 -88
  39. package/.sinapse-ai/development/templates/service-template/types.ts.hbs +146 -146
  40. package/.sinapse-ai/development/templates/squad-template/LICENSE +22 -22
  41. package/.sinapse-ai/development/workflows/development-cycle.yaml +6 -6
  42. package/.sinapse-ai/hooks/unified/runners/precompact-runner.js +15 -61
  43. package/.sinapse-ai/infrastructure/templates/coderabbit.yaml.template +280 -280
  44. package/.sinapse-ai/infrastructure/templates/config/env.example +16 -16
  45. package/.sinapse-ai/infrastructure/templates/config/gitignore-additions.tmpl +59 -59
  46. package/.sinapse-ai/infrastructure/templates/github/CODEOWNERS.template +12 -12
  47. package/.sinapse-ai/infrastructure/templates/github-workflows/ci.yml.template +170 -170
  48. package/.sinapse-ai/infrastructure/templates/github-workflows/pr-automation.yml.template +331 -331
  49. package/.sinapse-ai/infrastructure/templates/github-workflows/release.yml.template +197 -197
  50. package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +19 -19
  51. package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-node.tmpl +86 -86
  52. package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-python.tmpl +146 -146
  53. package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-sinapse-base.tmpl +64 -64
  54. package/.sinapse-ai/infrastructure/templates/safe-collab/CODEOWNERS.template +16 -16
  55. package/.sinapse-ai/infrastructure/templates/sinapse-sync.yaml.template +183 -183
  56. package/.sinapse-ai/install-manifest.yaml +98 -90
  57. package/.sinapse-ai/local-config.yaml.template +65 -65
  58. package/.sinapse-ai/monitor/hooks/lib/__init__.py +2 -2
  59. package/.sinapse-ai/monitor/hooks/lib/enrich.py +59 -59
  60. package/.sinapse-ai/monitor/hooks/lib/send_event.py +48 -48
  61. package/.sinapse-ai/monitor/hooks/notification.py +30 -30
  62. package/.sinapse-ai/monitor/hooks/post_tool_use.py +46 -46
  63. package/.sinapse-ai/monitor/hooks/pre_compact.py +30 -30
  64. package/.sinapse-ai/monitor/hooks/pre_tool_use.py +41 -41
  65. package/.sinapse-ai/monitor/hooks/stop.py +30 -30
  66. package/.sinapse-ai/monitor/hooks/subagent_stop.py +30 -30
  67. package/.sinapse-ai/monitor/hooks/user_prompt_submit.py +39 -39
  68. package/.sinapse-ai/product/templates/adr.hbs +126 -126
  69. package/.sinapse-ai/product/templates/dbdr.hbs +242 -242
  70. package/.sinapse-ai/product/templates/epic.hbs +213 -213
  71. package/.sinapse-ai/product/templates/ide-rules/codex-rules.md +1 -1
  72. package/.sinapse-ai/product/templates/pmdr.hbs +187 -187
  73. package/.sinapse-ai/product/templates/prd-v2.0.hbs +217 -217
  74. package/.sinapse-ai/product/templates/prd.hbs +202 -202
  75. package/.sinapse-ai/product/templates/story.hbs +264 -264
  76. package/.sinapse-ai/product/templates/task.hbs +171 -171
  77. package/.sinapse-ai/product/templates/tmpl-comment-on-examples.sql +159 -159
  78. package/.sinapse-ai/product/templates/tmpl-migration-script.sql +92 -92
  79. package/.sinapse-ai/product/templates/tmpl-rls-granular-policies.sql +105 -105
  80. package/.sinapse-ai/product/templates/tmpl-rls-kiss-policy.sql +11 -11
  81. package/.sinapse-ai/product/templates/tmpl-rls-roles.sql +136 -136
  82. package/.sinapse-ai/product/templates/tmpl-rls-simple.sql +78 -78
  83. package/.sinapse-ai/product/templates/tmpl-rls-tenant.sql +153 -153
  84. package/.sinapse-ai/product/templates/tmpl-rollback-script.sql +78 -78
  85. package/.sinapse-ai/product/templates/tmpl-seed-data.sql +141 -141
  86. package/.sinapse-ai/product/templates/tmpl-smoke-test.sql +17 -17
  87. package/.sinapse-ai/product/templates/tmpl-staging-copy-merge.sql +140 -140
  88. package/.sinapse-ai/product/templates/tmpl-stored-proc.sql +141 -141
  89. package/.sinapse-ai/product/templates/tmpl-trigger.sql +153 -153
  90. package/.sinapse-ai/product/templates/tmpl-view-materialized.sql +134 -134
  91. package/.sinapse-ai/product/templates/tmpl-view.sql +178 -178
  92. package/.sinapse-ai/project-config.yaml +0 -3
  93. package/LICENSE +63 -63
  94. package/README.en.md +6 -6
  95. package/README.md +14 -14
  96. package/bin/commands/install.js +34 -2
  97. package/bin/lib/register-grounding-hooks.js +1 -1
  98. package/docs/README.md +24 -58
  99. package/docs/agent-reference-guide.md +108 -0
  100. package/docs/constitution-compliance.md +87 -0
  101. package/docs/framework/orqx-plan.md +1 -1
  102. package/docs/framework/source-tree.md +1 -1
  103. package/docs/getting-started.md +68 -0
  104. package/docs/guides/development-setup.md +2 -2
  105. package/docs/guides/grounding-setup.md +3 -3
  106. package/docs/guides/parallel-collaboration-source-of-truth.md +1 -1
  107. package/docs/guides/squad-commands-reference.md +1 -1
  108. package/docs/guides/template-engine-v2.md +1 -1
  109. package/docs/installation/v4-quick-start.md +1 -1
  110. package/docs/pt/DOCUMENTATION-ROADMAP.md +6 -5
  111. package/docs/pt/architecture/dual-register-pattern.md +7 -7
  112. package/docs/pt/architecture/source-tree.md +1 -1
  113. package/docs/pt/architecture/sub-orqx-pattern.md +5 -5
  114. package/docs/pt/framework/source-tree.md +1 -1
  115. package/docs/pt/guides/development-setup.md +2 -2
  116. package/docs/pt/guides/template-engine-v2.md +1 -1
  117. package/docs/pt/installation/v4-quick-start.md +1 -1
  118. package/docs/troubleshooting.md +114 -0
  119. package/package.json +11 -18
  120. package/packages/installer/src/wizard/feedback.js +1 -1
  121. package/packages/installer/src/wizard/questions.js +1 -1
  122. package/packages/installer/src/wizard/wizard.js +113 -13
  123. package/packages/installer/templates/vault-routing.example.json +1 -1
  124. package/packages/sinapse-install/bin/edmcp.js +0 -0
  125. package/packages/sinapse-install/bin/sinapse-install.js +0 -0
  126. package/scripts/check-markdown-links.py +352 -353
  127. package/scripts/perf-baseline.sh +98 -0
  128. package/scripts/sync-squad-yaml-components.js +137 -0
  129. package/scripts/validate-all.js +153 -0
  130. package/scripts/validate-cross-refs.js +225 -0
  131. package/scripts/validate-no-personal-leaks.js +204 -0
  132. package/scripts/validate-orqx-discipline.js +160 -0
  133. package/sinapse/agents/snps-orqx.md +18 -9
  134. package/sinapse/knowledge-base/routing-catalog.md +2 -2
  135. package/sinapse/squad.yaml +2 -2
  136. package/squads/{squad-claude → claude-code-mastery}/agents/claude-orqx.md +50 -1
  137. package/squads/{squad-claude → claude-code-mastery}/knowledge-base/context-window-optimization.md +1 -1
  138. package/squads/{squad-claude → claude-code-mastery}/knowledge-base/knowledge-architecture-reference.md +3 -25
  139. package/squads/{squad-claude → claude-code-mastery}/knowledge-base/skill-creation-patterns.md +3 -3
  140. package/squads/{squad-claude → claude-code-mastery}/knowledge-base/swarm-orchestration-patterns.md +12 -15
  141. package/squads/claude-code-mastery/squad.yaml +14 -0
  142. package/squads/{squad-claude → claude-code-mastery}/workflows/optimization-cycle.yaml +1 -1
  143. package/squads/{squad-claude → claude-code-mastery}/workflows/project-setup-cycle.yaml +1 -1
  144. package/squads/squad-animations/agents/animations-orqx.md +53 -0
  145. package/squads/squad-animations/squad.yaml +15 -0
  146. package/squads/squad-artdir/agents/artdir-orqx.md +69 -0
  147. package/squads/squad-artdir/squad.yaml +20 -0
  148. package/squads/squad-cloning/squad.yaml +15 -0
  149. package/squads/squad-commercial/squad.yaml +17 -0
  150. package/squads/squad-copy/squad.yaml +20 -0
  151. package/squads/squad-council/squad.yaml +17 -0
  152. package/squads/squad-courses/squad.yaml +14 -0
  153. package/squads/squad-design/agents/design-orqx.md +49 -0
  154. package/squads/squad-design/squad.yaml +17 -0
  155. package/squads/squad-finance/squad.yaml +11 -0
  156. package/squads/squad-growth/agents/growth-orqx.md +59 -0
  157. package/squads/squad-growth/squad.yaml +13 -0
  158. package/squads/squad-paidmedia/squad.yaml +16 -0
  159. package/squads/squad-product/agents/product-orqx.md +58 -0
  160. package/squads/squad-product/squad.yaml +13 -0
  161. package/squads/squad-research/knowledge-base/agentic-second-brain-reference.md +2 -48
  162. package/squads/squad-research/squad.yaml +14 -0
  163. package/.claude/hooks/enforce-architecture-first.py +0 -197
  164. package/.claude/hooks/write-path-validation.py +0 -195
  165. package/.sinapse-ai/lib/build.json +0 -1
  166. package/bin/utils/pro-detector.js +0 -114
  167. package/docs/guides/agents/ANALYST-SYSTEM.md +0 -674
  168. package/docs/guides/agents/ARCHITECT-SYSTEM.md +0 -736
  169. package/docs/guides/agents/DATA-ENGINEER-SYSTEM.md +0 -802
  170. package/docs/guides/agents/DEV-SYSTEM.md +0 -580
  171. package/docs/guides/agents/DEVOPS-SYSTEM.md +0 -638
  172. package/docs/guides/agents/PM-SYSTEM.md +0 -728
  173. package/docs/guides/agents/QA-SYSTEM.md +0 -655
  174. package/docs/guides/agents/SINAPSE-AGENT-FLOWS.zip +0 -0
  175. package/docs/guides/agents/SINAPSE-MASTER-SYSTEM.md +0 -576
  176. package/docs/guides/agents/SM-SYSTEM.md +0 -496
  177. package/docs/guides/agents/SQUAD-CREATOR-SYSTEM.md +0 -699
  178. package/docs/guides/agents/UX-DESIGN-EXPERT-SYSTEM.md +0 -835
  179. package/packages/sinapse-pro-cli/bin/sinapse-pro.js +0 -233
  180. package/packages/sinapse-pro-cli/package.json +0 -36
  181. package/packages/sinapse-pro-cli/src/recover.js +0 -101
  182. package/packages/sinapse-pro-cli/tests/sinapse-pro-bin.smoke.test.js +0 -70
  183. package/squads/squad-claude/README.md +0 -84
  184. package/squads/squad-claude/agents/config-engineer.md +0 -73
  185. package/squads/squad-claude/agents/hooks-architect.md +0 -68
  186. package/squads/squad-claude/agents/mcp-integrator.md +0 -67
  187. package/squads/squad-claude/agents/project-integrator.md +0 -73
  188. package/squads/squad-claude/agents/roadmap-sentinel.md +0 -69
  189. package/squads/squad-claude/agents/skill-craftsman.md +0 -73
  190. package/squads/squad-claude/agents/swarm-orqx.md +0 -106
  191. package/squads/squad-claude/knowledge-base/obsidian-claude-integration.md +0 -423
  192. package/squads/squad-claude/preferences/README.md +0 -15
  193. package/squads/squad-claude/squad.yaml +0 -32
  194. package/squads/squad-claude/tasks/audit-settings.md +0 -72
  195. package/squads/squad-claude/tasks/audit-setup.md +0 -85
  196. package/squads/squad-claude/tasks/brownfield-setup.md +0 -77
  197. package/squads/squad-claude/tasks/ci-cd-setup.md +0 -56
  198. package/squads/squad-claude/tasks/claude-md-engineer.md +0 -58
  199. package/squads/squad-claude/tasks/context-rot-audit.md +0 -83
  200. package/squads/squad-claude/tasks/create-agent-definition.md +0 -59
  201. package/squads/squad-claude/tasks/create-rules.md +0 -55
  202. package/squads/squad-claude/tasks/create-team-topology.md +0 -72
  203. package/squads/squad-claude/tasks/diagnose.md +0 -76
  204. package/squads/squad-claude/tasks/enterprise-config.md +0 -74
  205. package/squads/squad-claude/tasks/hook-designer.md +0 -72
  206. package/squads/squad-claude/tasks/integrate-project.md +0 -73
  207. package/squads/squad-claude/tasks/mcp-integration-plan.md +0 -75
  208. package/squads/squad-claude/tasks/mcp-workflow.md +0 -75
  209. package/squads/squad-claude/tasks/multi-project-setup.md +0 -72
  210. package/squads/squad-claude/tasks/optimize-context.md +0 -75
  211. package/squads/squad-claude/tasks/optimize-workflow.md +0 -75
  212. package/squads/squad-claude/tasks/parallel-decomposition.md +0 -77
  213. package/squads/squad-claude/tasks/permission-strategy.md +0 -74
  214. package/squads/squad-claude/tasks/sandbox-setup.md +0 -75
  215. package/squads/squad-claude/tasks/setup-repository.md +0 -58
  216. package/squads/squad-claude/tasks/setup-wizard.md +0 -78
  217. package/squads/squad-claude/tasks/worktree-strategy.md +0 -77
  218. package/squads/squad-design/agents/brad-frost.md +0 -56
  219. package/squads/squad-design/agents/dan-mall.md +0 -53
  220. package/squads/squad-design/agents/dave-malouf.md +0 -53
  221. package/squads/squad-design/agents/nano-banana-generator.md +0 -42
  222. /package/squads/{squad-claude → claude-code-mastery}/agents/db-sage.md +0 -0
  223. /package/squads/{squad-claude → claude-code-mastery}/agents/tools-orqx.md +0 -0
  224. /package/squads/{squad-claude → claude-code-mastery}/knowledge-base/agent-team-patterns.md +0 -0
  225. /package/squads/{squad-claude → claude-code-mastery}/knowledge-base/claude-code-configuration-reference.md +0 -0
  226. /package/squads/{squad-claude → claude-code-mastery}/knowledge-base/claude-code-hooks-reference.md +0 -0
  227. /package/squads/{squad-claude → claude-code-mastery}/knowledge-base/claude-code-internals-deep.md +0 -0
  228. /package/squads/{squad-claude → claude-code-mastery}/knowledge-base/claude-code-tools-reference.md +0 -0
  229. /package/squads/{squad-claude → claude-code-mastery}/knowledge-base/context-engineering-guide.md +0 -0
  230. /package/squads/{squad-claude → claude-code-mastery}/knowledge-base/mcp-integration-patterns.md +0 -0
  231. /package/squads/{squad-claude → claude-code-mastery}/knowledge-base/memory-systems-reference.md +0 -0
  232. /package/squads/{squad-claude → claude-code-mastery}/knowledge-base/retrieval-augmented-generation.md +0 -0
  233. /package/squads/{squad-claude → claude-code-mastery}/tasks/agent-persona-creation.md +0 -0
  234. /package/squads/{squad-claude → claude-code-mastery}/tasks/ai-testing-automation.md +0 -0
  235. /package/squads/{squad-claude → claude-code-mastery}/tasks/audit-hooks.md +0 -0
  236. /package/squads/{squad-claude → claude-code-mastery}/tasks/automated-code-review-pipeline.md +0 -0
  237. /package/squads/{squad-claude → claude-code-mastery}/tasks/batch-processing-workflow.md +0 -0
  238. /package/squads/{squad-claude → claude-code-mastery}/tasks/chain-of-thought-optimization.md +0 -0
  239. /package/squads/{squad-claude → claude-code-mastery}/tasks/claude-code-hooks-setup.md +0 -0
  240. /package/squads/{squad-claude → claude-code-mastery}/tasks/claude-code-project-setup.md +0 -0
  241. /package/squads/{squad-claude → claude-code-mastery}/tasks/configure-settings.md +0 -0
  242. /package/squads/{squad-claude → claude-code-mastery}/tasks/content-curation-pipeline.md +0 -0
  243. /package/squads/{squad-claude → claude-code-mastery}/tasks/context-window-audit.md +0 -0
  244. /package/squads/{squad-claude → claude-code-mastery}/tasks/end-to-end-ai-workflow.md +0 -0
  245. /package/squads/{squad-claude → claude-code-mastery}/tasks/few-shot-example-library.md +0 -0
  246. /package/squads/{squad-claude → claude-code-mastery}/tasks/human-in-the-loop-design.md +0 -0
  247. /package/squads/{squad-claude → claude-code-mastery}/tasks/knowledge-base-architecture.md +0 -0
  248. /package/squads/{squad-claude → claude-code-mastery}/tasks/knowledge-retrieval-optimization.md +0 -0
  249. /package/squads/{squad-claude → claude-code-mastery}/tasks/mcp-integration-audit.md +0 -0
  250. /package/squads/{squad-claude → claude-code-mastery}/tasks/mcp-server-design.md +0 -0
  251. /package/squads/{squad-claude → claude-code-mastery}/tasks/memory-system-design.md +0 -0
  252. /package/squads/{squad-claude → claude-code-mastery}/tasks/multi-agent-orchestration.md +0 -0
  253. /package/squads/{squad-claude → claude-code-mastery}/tasks/multi-turn-conversation-design.md +0 -0
  254. /package/squads/{squad-claude → claude-code-mastery}/tasks/prompt-testing-framework.md +0 -0
  255. /package/squads/{squad-claude → claude-code-mastery}/tasks/slash-command-library-design.md +0 -0
  256. /package/squads/{squad-claude → claude-code-mastery}/tasks/system-prompt-design.md +0 -0
  257. /package/squads/{squad-claude → claude-code-mastery}/tasks/tool-orchestration-pattern.md +0 -0
@@ -1,152 +1,152 @@
1
- #!/usr/bin/env python3
2
- """
3
- Hook: Read Protection
4
-
5
- REGRA: Arquivos protegidos DEVEM ser lidos completamente (sem limit/offset).
6
-
7
- Este hook intercepta chamadas Read e bloqueia leitura parcial em arquivos
8
- que requerem contexto completo para edição segura.
9
-
10
- Exit Codes:
11
- - 0: Permitido
12
- - 2: Bloqueado (arquivo protegido com limit/offset)
13
- """
14
-
15
- import json
16
- import sys
17
- import os
18
- import fnmatch
19
- from pathlib import Path
20
-
21
- # =============================================================================
22
- # CONFIGURAÇÃO: Arquivos que DEVEM ser lidos completamente
23
- # =============================================================================
24
-
25
- PROTECTED_PATTERNS = [
26
- # Configuração do Claude
27
- ".claude/CLAUDE.md",
28
- ".claude/rules/*.md",
29
- ".claude/settings*.json",
30
-
31
- # Definições de agentes
32
- ".sinapse-ai/development/agents/*.md",
33
- ".sinapse-upstream/.sinapse-ai/development/agents/*.md",
34
-
35
- # Documentação crítica
36
- "docs/mmos/ARCHITECTURE_RULES.md",
37
- "supabase/docs/SCHEMA.md",
38
-
39
- # Configuração do projeto
40
- "package.json",
41
- "tsconfig.json",
42
- "tsconfig.*.json",
43
-
44
- # Arquivos de código críticos
45
- "app/components/ui/icons/icon-map.ts",
46
-
47
- # Migrations (sempre ler completo antes de editar)
48
- "supabase/migrations/*.sql",
49
- ]
50
-
51
- # =============================================================================
52
- # LÓGICA DO HOOK
53
- # =============================================================================
54
-
55
- def get_project_root():
56
- """Obtém o root do projeto via variável de ambiente ou cwd."""
57
- return os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
58
-
59
- def normalize_path(file_path: str, project_root: str) -> str:
60
- """Normaliza path para relativo ao projeto."""
61
- if file_path.startswith(project_root):
62
- return file_path[len(project_root):].lstrip("/")
63
- if file_path.startswith("/"):
64
- # Path absoluto fora do projeto
65
- return file_path
66
- return file_path
67
-
68
- def matches_protected_pattern(relative_path: str) -> bool:
69
- """Verifica se o path corresponde a algum padrão protegido."""
70
- for pattern in PROTECTED_PATTERNS:
71
- if fnmatch.fnmatch(relative_path, pattern):
72
- return True
73
- # Também verificar se é substring (para paths com wildcards)
74
- if "*" not in pattern and pattern in relative_path:
75
- return True
76
- return False
77
-
78
- def has_partial_read_params(tool_input: dict) -> tuple[bool, str]:
79
- """Verifica se a chamada Read tem parâmetros de leitura parcial."""
80
- limit = tool_input.get("limit")
81
- offset = tool_input.get("offset")
82
-
83
- reasons = []
84
- if limit is not None:
85
- reasons.append(f"limit={limit}")
86
- if offset is not None and offset != 0:
87
- reasons.append(f"offset={offset}")
88
-
89
- return len(reasons) > 0, ", ".join(reasons)
90
-
91
- def main():
92
- # Ler input do stdin
93
- try:
94
- input_data = json.load(sys.stdin)
95
- except json.JSONDecodeError:
96
- # Se não conseguir parsear, permitir (fail-open)
97
- sys.exit(0)
98
-
99
- tool_name = input_data.get("tool_name", "")
100
- tool_input = input_data.get("tool_input", {})
101
-
102
- # Só processar Read
103
- if tool_name != "Read":
104
- sys.exit(0)
105
-
106
- file_path = tool_input.get("file_path", "")
107
- if not file_path:
108
- sys.exit(0)
109
-
110
- # Normalizar path
111
- project_root = get_project_root()
112
- relative_path = normalize_path(file_path, project_root)
113
-
114
- # Verificar se é arquivo protegido
115
- if not matches_protected_pattern(relative_path):
116
- sys.exit(0)
117
-
118
- # Verificar se tem parâmetros de leitura parcial
119
- is_partial, partial_reason = has_partial_read_params(tool_input)
120
-
121
- if not is_partial:
122
- # Leitura completa, permitir
123
- sys.exit(0)
124
-
125
- # BLOQUEAR: Tentando ler arquivo protegido parcialmente
126
- error_message = f"""
127
- ╔══════════════════════════════════════════════════════════════════════════════╗
128
- ║ 🛑 READ PROTECTION: Arquivo protegido deve ser lido completamente ║
129
- ╠══════════════════════════════════════════════════════════════════════════════╣
130
- ║ ║
131
- ║ Arquivo: {relative_path[:58]:<58} ║
132
- ║ Problema: {partial_reason:<57} ║
133
- ║ ║
134
- ║ REGRA: Este arquivo está na lista de arquivos protegidos. ║
135
- ║ Arquivos protegidos DEVEM ser lidos completamente para evitar: ║
136
- ║ - Edições com contexto incompleto ║
137
- ║ - Duplicações acidentais ║
138
- ║ - Breaking changes não intencionais ║
139
- ║ ║
140
- ║ SOLUÇÃO: Remova os parâmetros 'limit' e 'offset' da chamada Read. ║
141
- ║ ║
142
- ║ ✅ Read(file_path="{relative_path[:40]}")
143
- ║ ❌ Read(file_path="...", limit=100) ║
144
- ║ ║
145
- ╚══════════════════════════════════════════════════════════════════════════════╝
146
- """
147
- print(error_message, file=sys.stderr)
148
- sys.exit(2)
149
-
150
- if __name__ == "__main__":
151
- main()
152
-
1
+ #!/usr/bin/env python3
2
+ """
3
+ Hook: Read Protection
4
+
5
+ REGRA: Arquivos protegidos DEVEM ser lidos completamente (sem limit/offset).
6
+
7
+ Este hook intercepta chamadas Read e bloqueia leitura parcial em arquivos
8
+ que requerem contexto completo para edição segura.
9
+
10
+ Exit Codes:
11
+ - 0: Permitido
12
+ - 2: Bloqueado (arquivo protegido com limit/offset)
13
+ """
14
+
15
+ import json
16
+ import sys
17
+ import os
18
+ import fnmatch
19
+ from pathlib import Path
20
+
21
+ # =============================================================================
22
+ # CONFIGURAÇÃO: Arquivos que DEVEM ser lidos completamente
23
+ # =============================================================================
24
+
25
+ PROTECTED_PATTERNS = [
26
+ # Configuração do Claude
27
+ ".claude/CLAUDE.md",
28
+ ".claude/rules/*.md",
29
+ ".claude/settings*.json",
30
+
31
+ # Definições de agentes
32
+ ".sinapse-ai/development/agents/*.md",
33
+ ".sinapse-upstream/.sinapse-ai/development/agents/*.md",
34
+
35
+ # Documentação crítica
36
+ "docs/mmos/ARCHITECTURE_RULES.md",
37
+ "supabase/docs/SCHEMA.md",
38
+
39
+ # Configuração do projeto
40
+ "package.json",
41
+ "tsconfig.json",
42
+ "tsconfig.*.json",
43
+
44
+ # Arquivos de código críticos
45
+ "app/components/ui/icons/icon-map.ts",
46
+
47
+ # Migrations (sempre ler completo antes de editar)
48
+ "supabase/migrations/*.sql",
49
+ ]
50
+
51
+ # =============================================================================
52
+ # LÓGICA DO HOOK
53
+ # =============================================================================
54
+
55
+ def get_project_root():
56
+ """Obtém o root do projeto via variável de ambiente ou cwd."""
57
+ return os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
58
+
59
+ def normalize_path(file_path: str, project_root: str) -> str:
60
+ """Normaliza path para relativo ao projeto."""
61
+ if file_path.startswith(project_root):
62
+ return file_path[len(project_root):].lstrip("/")
63
+ if file_path.startswith("/"):
64
+ # Path absoluto fora do projeto
65
+ return file_path
66
+ return file_path
67
+
68
+ def matches_protected_pattern(relative_path: str) -> bool:
69
+ """Verifica se o path corresponde a algum padrão protegido."""
70
+ for pattern in PROTECTED_PATTERNS:
71
+ if fnmatch.fnmatch(relative_path, pattern):
72
+ return True
73
+ # Também verificar se é substring (para paths com wildcards)
74
+ if "*" not in pattern and pattern in relative_path:
75
+ return True
76
+ return False
77
+
78
+ def has_partial_read_params(tool_input: dict) -> tuple[bool, str]:
79
+ """Verifica se a chamada Read tem parâmetros de leitura parcial."""
80
+ limit = tool_input.get("limit")
81
+ offset = tool_input.get("offset")
82
+
83
+ reasons = []
84
+ if limit is not None:
85
+ reasons.append(f"limit={limit}")
86
+ if offset is not None and offset != 0:
87
+ reasons.append(f"offset={offset}")
88
+
89
+ return len(reasons) > 0, ", ".join(reasons)
90
+
91
+ def main():
92
+ # Ler input do stdin
93
+ try:
94
+ input_data = json.load(sys.stdin)
95
+ except json.JSONDecodeError:
96
+ # Se não conseguir parsear, permitir (fail-open)
97
+ sys.exit(0)
98
+
99
+ tool_name = input_data.get("tool_name", "")
100
+ tool_input = input_data.get("tool_input", {})
101
+
102
+ # Só processar Read
103
+ if tool_name != "Read":
104
+ sys.exit(0)
105
+
106
+ file_path = tool_input.get("file_path", "")
107
+ if not file_path:
108
+ sys.exit(0)
109
+
110
+ # Normalizar path
111
+ project_root = get_project_root()
112
+ relative_path = normalize_path(file_path, project_root)
113
+
114
+ # Verificar se é arquivo protegido
115
+ if not matches_protected_pattern(relative_path):
116
+ sys.exit(0)
117
+
118
+ # Verificar se tem parâmetros de leitura parcial
119
+ is_partial, partial_reason = has_partial_read_params(tool_input)
120
+
121
+ if not is_partial:
122
+ # Leitura completa, permitir
123
+ sys.exit(0)
124
+
125
+ # BLOQUEAR: Tentando ler arquivo protegido parcialmente
126
+ error_message = f"""
127
+ ╔══════════════════════════════════════════════════════════════════════════════╗
128
+ ║ 🛑 READ PROTECTION: Arquivo protegido deve ser lido completamente ║
129
+ ╠══════════════════════════════════════════════════════════════════════════════╣
130
+ ║ ║
131
+ ║ Arquivo: {relative_path[:58]:<58} ║
132
+ ║ Problema: {partial_reason:<57} ║
133
+ ║ ║
134
+ ║ REGRA: Este arquivo está na lista de arquivos protegidos. ║
135
+ ║ Arquivos protegidos DEVEM ser lidos completamente para evitar: ║
136
+ ║ - Edições com contexto incompleto ║
137
+ ║ - Duplicações acidentais ║
138
+ ║ - Breaking changes não intencionais ║
139
+ ║ ║
140
+ ║ SOLUÇÃO: Remova os parâmetros 'limit' e 'offset' da chamada Read. ║
141
+ ║ ║
142
+ ║ ✅ Read(file_path="{relative_path[:40]}")
143
+ ║ ❌ Read(file_path="...", limit=100) ║
144
+ ║ ║
145
+ ╚══════════════════════════════════════════════════════════════════════════════╝
146
+ """
147
+ print(error_message, file=sys.stderr)
148
+ sys.exit(2)
149
+
150
+ if __name__ == "__main__":
151
+ main()
152
+
@@ -1,175 +1,175 @@
1
- #!/usr/bin/env python3
2
- """
3
- Hook: Slug Validation
4
-
5
- REGRA: Todos os slugs DEVEM usar snake_case (underscores, não hyphens).
6
-
7
- Este hook intercepta comandos SQL que inserem/atualizam slugs e valida
8
- o formato antes de permitir a operação.
9
-
10
- Pattern válido: ^[a-z0-9]+(_[a-z0-9]+)*$
11
- Exemplos válidos: jose_carlos_amorim, elon_musk
12
- Exemplos inválidos: jose-carlos-amorim, JoseAmorim, ELON_MUSK
13
-
14
- Exit Codes:
15
- - 0: Permitido
16
- - 2: Bloqueado (slug com formato inválido)
17
- """
18
-
19
- import json
20
- import sys
21
- import re
22
-
23
- # =============================================================================
24
- # CONFIGURAÇÃO
25
- # =============================================================================
26
-
27
- # Pattern válido para slugs
28
- SLUG_PATTERN = re.compile(r"^[a-z0-9]+(_[a-z0-9]+)*$")
29
-
30
- # Tabelas que têm coluna slug
31
- TABLES_WITH_SLUG = [
32
- "minds",
33
- "contents",
34
- "content_projects",
35
- "tools",
36
- "drivers",
37
- "mapping_systems",
38
- "frameworks",
39
- ]
40
-
41
- # =============================================================================
42
- # LÓGICA DO HOOK
43
- # =============================================================================
44
-
45
- def extract_slug_values(command: str) -> list[tuple[str, str]]:
46
- """
47
- Extrai valores de slug de comandos SQL INSERT/UPDATE.
48
-
49
- Returns:
50
- Lista de tuplas (table, slug_value)
51
- """
52
- found = []
53
- command_upper = command.upper()
54
-
55
- for table in TABLES_WITH_SLUG:
56
- table_upper = table.upper()
57
-
58
- # Detectar INSERT INTO table (..., slug, ...) VALUES (..., 'value', ...)
59
- insert_pattern = rf"INSERT\s+INTO\s+{table}\s*\([^)]*\bslug\b[^)]*\)\s*VALUES\s*\(([^)]+)\)"
60
- insert_match = re.search(insert_pattern, command, re.IGNORECASE)
61
- if insert_match:
62
- values_str = insert_match.group(1)
63
- # Extrair valores entre aspas
64
- slug_values = re.findall(r"'([^']+)'", values_str)
65
- for sv in slug_values:
66
- # Verificar se parece um slug (não é UUID, não é número)
67
- if not re.match(r"^[0-9a-f-]{36}$", sv) and not sv.isdigit():
68
- found.append((table, sv))
69
-
70
- # Detectar UPDATE table SET slug = 'value'
71
- update_pattern = rf"UPDATE\s+{table}\s+.*SET\s+.*\bslug\s*=\s*'([^']+)'"
72
- update_match = re.search(update_pattern, command, re.IGNORECASE)
73
- if update_match:
74
- found.append((table, update_match.group(1)))
75
-
76
- return found
77
-
78
- def validate_slug(slug: str) -> tuple[bool, str]:
79
- """
80
- Valida se o slug está no formato correto.
81
-
82
- Returns:
83
- (is_valid, error_message)
84
- """
85
- if SLUG_PATTERN.match(slug):
86
- return True, ""
87
-
88
- errors = []
89
-
90
- if "-" in slug:
91
- errors.append("contém hyphens (use underscores)")
92
- if any(c.isupper() for c in slug):
93
- errors.append("contém maiúsculas (use lowercase)")
94
- if slug.startswith("_") or slug.endswith("_"):
95
- errors.append("começa ou termina com underscore")
96
- if "__" in slug:
97
- errors.append("contém underscores duplos")
98
- if not errors:
99
- errors.append("formato inválido")
100
-
101
- return False, ", ".join(errors)
102
-
103
- def main():
104
- # Ler input do stdin
105
- try:
106
- input_data = json.load(sys.stdin)
107
- except json.JSONDecodeError:
108
- sys.exit(0)
109
-
110
- tool_name = input_data.get("tool_name", "")
111
- tool_input = input_data.get("tool_input", {})
112
-
113
- # Só processar Bash
114
- if tool_name != "Bash":
115
- sys.exit(0)
116
-
117
- command = tool_input.get("command", "")
118
- if not command:
119
- sys.exit(0)
120
-
121
- # Extrair slugs do comando
122
- slug_values = extract_slug_values(command)
123
-
124
- if not slug_values:
125
- sys.exit(0)
126
-
127
- # Validar cada slug
128
- invalid_slugs = []
129
- for table, slug in slug_values:
130
- is_valid, error = validate_slug(slug)
131
- if not is_valid:
132
- invalid_slugs.append((table, slug, error))
133
-
134
- if not invalid_slugs:
135
- sys.exit(0)
136
-
137
- # BLOQUEAR: Slug inválido detectado
138
- slug_errors = "\n".join([
139
- f"║ • {table}.slug = '{slug[:30]}' → {error[:30]:<30} ║"
140
- for table, slug, error in invalid_slugs[:5]
141
- ])
142
-
143
- # Sugerir correção
144
- suggestions = "\n".join([
145
- f"║ • '{slug}' → '{slug.lower().replace('-', '_')}'{'':>30} ║"
146
- for _, slug, _ in invalid_slugs[:5]
147
- ])
148
-
149
- error_message = f"""
150
- ╔══════════════════════════════════════════════════════════════════════════════╗
151
- ║ 🛑 SLUG VALIDATION: Formato de slug inválido ║
152
- ╠══════════════════════════════════════════════════════════════════════════════╣
153
- ║ ║
154
- ║ Slugs inválidos detectados: ║
155
- {slug_errors}
156
- ║ ║
157
- ║ REGRA: Todos os slugs DEVEM usar snake_case ║
158
- ║ ║
159
- ║ Pattern válido: ^[a-z0-9]+(_[a-z0-9]+)*$ ║
160
- ║ ✅ jose_carlos_amorim ║
161
- ║ ❌ jose-carlos-amorim (hyphen) ║
162
- ║ ❌ JoseAmorim (camelCase) ║
163
- ║ ║
164
- ║ Sugestões de correção: ║
165
- {suggestions}
166
- ║ ║
167
- ║ POR QUÊ: Slugs inconsistentes causam falhas silenciosas no frontend. ║
168
- ║ ║
169
- ╚══════════════════════════════════════════════════════════════════════════════╝
170
- """
171
- print(error_message, file=sys.stderr)
172
- sys.exit(2)
173
-
174
- if __name__ == "__main__":
175
- main()
1
+ #!/usr/bin/env python3
2
+ """
3
+ Hook: Slug Validation
4
+
5
+ REGRA: Todos os slugs DEVEM usar snake_case (underscores, não hyphens).
6
+
7
+ Este hook intercepta comandos SQL que inserem/atualizam slugs e valida
8
+ o formato antes de permitir a operação.
9
+
10
+ Pattern válido: ^[a-z0-9]+(_[a-z0-9]+)*$
11
+ Exemplos válidos: jose_carlos_amorim, elon_musk
12
+ Exemplos inválidos: jose-carlos-amorim, JoseAmorim, ELON_MUSK
13
+
14
+ Exit Codes:
15
+ - 0: Permitido
16
+ - 2: Bloqueado (slug com formato inválido)
17
+ """
18
+
19
+ import json
20
+ import sys
21
+ import re
22
+
23
+ # =============================================================================
24
+ # CONFIGURAÇÃO
25
+ # =============================================================================
26
+
27
+ # Pattern válido para slugs
28
+ SLUG_PATTERN = re.compile(r"^[a-z0-9]+(_[a-z0-9]+)*$")
29
+
30
+ # Tabelas que têm coluna slug
31
+ TABLES_WITH_SLUG = [
32
+ "minds",
33
+ "contents",
34
+ "content_projects",
35
+ "tools",
36
+ "drivers",
37
+ "mapping_systems",
38
+ "frameworks",
39
+ ]
40
+
41
+ # =============================================================================
42
+ # LÓGICA DO HOOK
43
+ # =============================================================================
44
+
45
+ def extract_slug_values(command: str) -> list[tuple[str, str]]:
46
+ """
47
+ Extrai valores de slug de comandos SQL INSERT/UPDATE.
48
+
49
+ Returns:
50
+ Lista de tuplas (table, slug_value)
51
+ """
52
+ found = []
53
+ command_upper = command.upper()
54
+
55
+ for table in TABLES_WITH_SLUG:
56
+ table_upper = table.upper()
57
+
58
+ # Detectar INSERT INTO table (..., slug, ...) VALUES (..., 'value', ...)
59
+ insert_pattern = rf"INSERT\s+INTO\s+{table}\s*\([^)]*\bslug\b[^)]*\)\s*VALUES\s*\(([^)]+)\)"
60
+ insert_match = re.search(insert_pattern, command, re.IGNORECASE)
61
+ if insert_match:
62
+ values_str = insert_match.group(1)
63
+ # Extrair valores entre aspas
64
+ slug_values = re.findall(r"'([^']+)'", values_str)
65
+ for sv in slug_values:
66
+ # Verificar se parece um slug (não é UUID, não é número)
67
+ if not re.match(r"^[0-9a-f-]{36}$", sv) and not sv.isdigit():
68
+ found.append((table, sv))
69
+
70
+ # Detectar UPDATE table SET slug = 'value'
71
+ update_pattern = rf"UPDATE\s+{table}\s+.*SET\s+.*\bslug\s*=\s*'([^']+)'"
72
+ update_match = re.search(update_pattern, command, re.IGNORECASE)
73
+ if update_match:
74
+ found.append((table, update_match.group(1)))
75
+
76
+ return found
77
+
78
+ def validate_slug(slug: str) -> tuple[bool, str]:
79
+ """
80
+ Valida se o slug está no formato correto.
81
+
82
+ Returns:
83
+ (is_valid, error_message)
84
+ """
85
+ if SLUG_PATTERN.match(slug):
86
+ return True, ""
87
+
88
+ errors = []
89
+
90
+ if "-" in slug:
91
+ errors.append("contém hyphens (use underscores)")
92
+ if any(c.isupper() for c in slug):
93
+ errors.append("contém maiúsculas (use lowercase)")
94
+ if slug.startswith("_") or slug.endswith("_"):
95
+ errors.append("começa ou termina com underscore")
96
+ if "__" in slug:
97
+ errors.append("contém underscores duplos")
98
+ if not errors:
99
+ errors.append("formato inválido")
100
+
101
+ return False, ", ".join(errors)
102
+
103
+ def main():
104
+ # Ler input do stdin
105
+ try:
106
+ input_data = json.load(sys.stdin)
107
+ except json.JSONDecodeError:
108
+ sys.exit(0)
109
+
110
+ tool_name = input_data.get("tool_name", "")
111
+ tool_input = input_data.get("tool_input", {})
112
+
113
+ # Só processar Bash
114
+ if tool_name != "Bash":
115
+ sys.exit(0)
116
+
117
+ command = tool_input.get("command", "")
118
+ if not command:
119
+ sys.exit(0)
120
+
121
+ # Extrair slugs do comando
122
+ slug_values = extract_slug_values(command)
123
+
124
+ if not slug_values:
125
+ sys.exit(0)
126
+
127
+ # Validar cada slug
128
+ invalid_slugs = []
129
+ for table, slug in slug_values:
130
+ is_valid, error = validate_slug(slug)
131
+ if not is_valid:
132
+ invalid_slugs.append((table, slug, error))
133
+
134
+ if not invalid_slugs:
135
+ sys.exit(0)
136
+
137
+ # BLOQUEAR: Slug inválido detectado
138
+ slug_errors = "\n".join([
139
+ f"║ • {table}.slug = '{slug[:30]}' → {error[:30]:<30} ║"
140
+ for table, slug, error in invalid_slugs[:5]
141
+ ])
142
+
143
+ # Sugerir correção
144
+ suggestions = "\n".join([
145
+ f"║ • '{slug}' → '{slug.lower().replace('-', '_')}'{'':>30} ║"
146
+ for _, slug, _ in invalid_slugs[:5]
147
+ ])
148
+
149
+ error_message = f"""
150
+ ╔══════════════════════════════════════════════════════════════════════════════╗
151
+ ║ 🛑 SLUG VALIDATION: Formato de slug inválido ║
152
+ ╠══════════════════════════════════════════════════════════════════════════════╣
153
+ ║ ║
154
+ ║ Slugs inválidos detectados: ║
155
+ {slug_errors}
156
+ ║ ║
157
+ ║ REGRA: Todos os slugs DEVEM usar snake_case ║
158
+ ║ ║
159
+ ║ Pattern válido: ^[a-z0-9]+(_[a-z0-9]+)*$ ║
160
+ ║ ✅ jose_carlos_amorim ║
161
+ ║ ❌ jose-carlos-amorim (hyphen) ║
162
+ ║ ❌ JoseAmorim (camelCase) ║
163
+ ║ ║
164
+ ║ Sugestões de correção: ║
165
+ {suggestions}
166
+ ║ ║
167
+ ║ POR QUÊ: Slugs inconsistentes causam falhas silenciosas no frontend. ║
168
+ ║ ║
169
+ ╚══════════════════════════════════════════════════════════════════════════════╝
170
+ """
171
+ print(error_message, file=sys.stderr)
172
+ sys.exit(2)
173
+
174
+ if __name__ == "__main__":
175
+ main()