New plugins: core-tools New skills: auto-expense, ticket-triage, design, security-check, aiktop-tasks, daily-digest, imap-triage, index-update, mindmap, notebooklm, proc-creator, tasks-overview, validate-component, perfex-module, report, calendar-manager New agents: design-critic, design-generator, design-lead, design-prompt-architect, design-researcher, compliance-auditor, metabase-analyst, gitea-integration-specialist Updated: all plugin configs, knowledge datasets, existing skills Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
97 lines
2.5 KiB
Bash
Executable File
97 lines
2.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# spec-gate.sh - PreToolUse hook for Write/Edit
|
|
# Avisa quando se tenta editar ficheiros sem SPEC.md aprovado
|
|
# Modo: HARD (bloqueia sem SPEC.md aprovado)
|
|
# Autor: Descomplicar® | 2026-02-07
|
|
|
|
INPUT=$(cat)
|
|
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
|
|
# So intercepta Write e Edit
|
|
if [ "$TOOL_NAME" != "Write" ] && [ "$TOOL_NAME" != "Edit" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
# Extrair file path
|
|
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
|
|
# ========== BYPASSES ==========
|
|
|
|
# Sem file path
|
|
if [ -z "$FILE_PATH" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
# Ficheiros de sistema
|
|
if echo "$FILE_PATH" | grep -qE '(\.claude/|CLAUDE\.md|settings\.json|\.env|\.claude-work/)'; then
|
|
exit 0
|
|
fi
|
|
|
|
# O proprio SPEC.md ou SPRINT.md
|
|
if echo "$FILE_PATH" | grep -qE '(SPEC\.md|SPRINT\.md)$'; then
|
|
exit 0
|
|
fi
|
|
|
|
# Ficheiros fora de pastas de projecto
|
|
if ! echo "$FILE_PATH" | grep -qE '^/media/ealmeida/Dados/(Dev|Arquivo_de_Clientes)/'; then
|
|
exit 0
|
|
fi
|
|
|
|
# Bypass temporario (30 min)
|
|
BYPASS_FILE="/tmp/claude-spec-gate-bypass"
|
|
if [ -f "$BYPASS_FILE" ]; then
|
|
BYPASS_AGE=$(( $(date +%s) - $(stat -c %Y "$BYPASS_FILE" 2>/dev/null || echo 0) ))
|
|
if [ "$BYPASS_AGE" -lt 1800 ]; then
|
|
exit 0
|
|
else
|
|
rm -f "$BYPASS_FILE"
|
|
fi
|
|
fi
|
|
|
|
# Docs e configs (CHANGELOG, README, .txt, docs/)
|
|
if echo "$FILE_PATH" | grep -qiE '(CHANGELOG|README|\.txt$|\.json$|docs/|\.desk-project)'; then
|
|
exit 0
|
|
fi
|
|
|
|
# Plan files
|
|
if echo "$FILE_PATH" | grep -qE '\.claude/plans/'; then
|
|
exit 0
|
|
fi
|
|
|
|
# ========== SPEC CHECK ==========
|
|
|
|
DIR=$(dirname "$FILE_PATH")
|
|
SPEC_FOUND=""
|
|
|
|
# Procurar SPEC.md subindo ate 5 niveis
|
|
for i in 1 2 3 4 5; do
|
|
if [ -f "$DIR/SPEC.md" ]; then
|
|
SPEC_FOUND="$DIR/SPEC.md"
|
|
break
|
|
fi
|
|
PARENT=$(dirname "$DIR")
|
|
# Parar em raizes conhecidas
|
|
if [ "$PARENT" = "$DIR" ] || [ "$DIR" = "/media/ealmeida/Dados/Dev" ] || [ "$DIR" = "/media/ealmeida/Dados" ]; then
|
|
break
|
|
fi
|
|
DIR="$PARENT"
|
|
done
|
|
|
|
# Sem SPEC.md - aviso suave
|
|
if [ -z "$SPEC_FOUND" ]; then
|
|
echo "SPEC-GATE: Sem SPEC.md neste projecto. Considere /spec create antes de comecar."
|
|
exit 2 # hard mode: bloqueia
|
|
fi
|
|
|
|
# SPEC.md existe - verificar aprovacao
|
|
if grep -q '<!-- APPROVED:' "$SPEC_FOUND" 2>/dev/null; then
|
|
# Spec aprovado - tudo OK, silencio total
|
|
exit 0
|
|
fi
|
|
|
|
# Spec existe mas nao aprovado
|
|
echo "SPEC-GATE: SPEC.md existe mas NAO esta aprovado."
|
|
echo " Ficheiro: $SPEC_FOUND"
|
|
echo " Accao: /spec approve para aprovar, ou /spec bypass para quick fix (30min)"
|
|
exit 2 # hard mode: bloqueia
|