Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions hooks/block-interactive.sh
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#!/usr/bin/env bash
# block-interactive.sh — Blocks AskUserQuestion in unattended sessions
#
# PreToolUse hook: exits 2 to block, 0 to allow.
# When Claude tries to ask a question, this forces it to decide instead.
#
# Copyright 2026 Stackbilt LLC — Apache 2.0
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
if [[ "$TOOL" == "AskUserQuestion" ]]; then
echo "BLOCKED: Autonomous mode — do not ask questions. Make a reasonable decision and document your reasoning." >&2
exit 2
fi
exit 0
#!/usr/bin/env bash
# block-interactive.sh — Blocks AskUserQuestion in unattended sessions
#
# PreToolUse hook: exits 2 to block, 0 to allow.
# When Claude tries to ask a question, this forces it to decide instead.
#
# Copyright 2026 Stackbilt LLC — Apache 2.0

INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)

if [[ "$TOOL" == "AskUserQuestion" ]]; then
echo "BLOCKED: Autonomous mode — do not ask questions. Make a reasonable decision and document your reasoning." >&2
exit 2
fi

exit 0
96 changes: 48 additions & 48 deletions hooks/safety-gate.sh
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
#!/usr/bin/env bash
# safety-gate.sh — Blocks destructive commands in unattended sessions
#
# PreToolUse hook for Bash tool: checks command for dangerous patterns.
# Blocks: rm -rf, git push --force, DROP TABLE, deploys, secret access.
#
# Copyright 2026 Stackbilt LLC — Apache 2.0
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
if [[ "$TOOL" != "Bash" ]]; then
exit 0
fi
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
# Destructive filesystem operations
if echo "$CMD" | grep -qiE '(rm\s+-rf|rm\s+-r\s+/|>\s*/dev/)'; then
echo "BLOCKED: Destructive filesystem operation not allowed in autonomous mode" >&2
exit 2
fi
# Destructive git operations
if echo "$CMD" | grep -qiE '(git\s+reset\s+--hard|git\s+push\s+--force|git\s+push\s+-f|git\s+clean\s+-f)'; then
echo "BLOCKED: Destructive git operation not allowed in autonomous mode" >&2
exit 2
fi
# Database destruction
if echo "$CMD" | grep -qiE '(DROP\s+TABLE|TRUNCATE\s+TABLE|DELETE\s+FROM\s+\w+\s*$)'; then
echo "BLOCKED: Destructive database operation not allowed in autonomous mode" >&2
exit 2
fi
# Production deploys (require human approval)
if echo "$CMD" | grep -qiE '(wrangler\s+deploy|wrangler\s+publish|npm\s+run\s+deploy|kubectl\s+apply|terraform\s+apply)'; then
echo "BLOCKED: Production deploys require human approval. Commit your work and stop." >&2
exit 2
fi
# Secret management
if echo "$CMD" | grep -qiE '(wrangler\s+secret|echo\s+.*API_KEY|echo\s+.*TOKEN|echo\s+.*SECRET)'; then
echo "BLOCKED: Secret management not allowed in autonomous mode" >&2
exit 2
fi
exit 0
#!/usr/bin/env bash
# safety-gate.sh — Blocks destructive commands in unattended sessions
#
# PreToolUse hook for Bash tool: checks command for dangerous patterns.
# Blocks: rm -rf, git push --force, DROP TABLE, deploys, secret access.
#
# Copyright 2026 Stackbilt LLC — Apache 2.0

INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)

if [[ "$TOOL" != "Bash" ]]; then
exit 0
fi

CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)

# Destructive filesystem operations
if echo "$CMD" | grep -qiE '(rm\s+-rf|rm\s+-r\s+/|>\s*/dev/)'; then
echo "BLOCKED: Destructive filesystem operation not allowed in autonomous mode" >&2
exit 2
fi

# Destructive git operations
if echo "$CMD" | grep -qiE '(git\s+reset\s+--hard|git\s+push\s+--force|git\s+push\s+-f|git\s+clean\s+-f)'; then
echo "BLOCKED: Destructive git operation not allowed in autonomous mode" >&2
exit 2
fi

# Database destruction
if echo "$CMD" | grep -qiE '(DROP\s+TABLE|TRUNCATE\s+TABLE|DELETE\s+FROM\s+\w+\s*$)'; then
echo "BLOCKED: Destructive database operation not allowed in autonomous mode" >&2
exit 2
fi

# Production deploys (require human approval)
if echo "$CMD" | grep -qiE '(wrangler\s+deploy|wrangler\s+publish|npm\s+run\s+deploy|kubectl\s+apply|terraform\s+apply)'; then
echo "BLOCKED: Production deploys require human approval. Commit your work and stop." >&2
exit 2
fi

# Secret management
if echo "$CMD" | grep -qiE '(wrangler\s+secret|echo\s+.*API_KEY|echo\s+.*TOKEN|echo\s+.*SECRET)'; then
echo "BLOCKED: Secret management not allowed in autonomous mode" >&2
exit 2
fi

exit 0
84 changes: 42 additions & 42 deletions hooks/syntax-check.sh
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
#!/usr/bin/env bash
# syntax-check.sh — PostToolUse hook for Edit/Write
#
# After editing TypeScript/JavaScript files, runs a quick syntax check
# so errors are caught immediately rather than 50 tool calls later.
#
# Copyright 2026 Stackbilt LLC — Apache 2.0
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
if [[ "$TOOL" != "Edit" && "$TOOL" != "Write" ]]; then
exit 0
fi
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
# Only check TypeScript/JavaScript files
case "$FILE" in
*.ts|*.tsx|*.js|*.jsx)
# Find nearest tsconfig
DIR=$(dirname "$FILE")
TSCONFIG=""
while [[ "$DIR" != "/" && "$DIR" != "." ]]; do
if [[ -f "${DIR}/tsconfig.json" ]]; then
TSCONFIG="${DIR}/tsconfig.json"
break
fi
DIR=$(dirname "$DIR")
done
if [[ -n "$TSCONFIG" ]]; then
ERRORS=$(cd "$(dirname "$TSCONFIG")" && npx tsc --noEmit --pretty false 2>&1 | grep -c "error TS" || true)
if [[ "$ERRORS" -gt 0 ]]; then
echo "WARNING: ${ERRORS} TypeScript error(s) detected after editing ${FILE}. Run typecheck to see details." >&2
fi
fi
;;
esac
# Never block — advisory only
exit 0
#!/usr/bin/env bash
# syntax-check.sh — PostToolUse hook for Edit/Write
#
# After editing TypeScript/JavaScript files, runs a quick syntax check
# so errors are caught immediately rather than 50 tool calls later.
#
# Copyright 2026 Stackbilt LLC — Apache 2.0

INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)

if [[ "$TOOL" != "Edit" && "$TOOL" != "Write" ]]; then
exit 0
fi

FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)

# Only check TypeScript/JavaScript files
case "$FILE" in
*.ts|*.tsx|*.js|*.jsx)
# Find nearest tsconfig
DIR=$(dirname "$FILE")
TSCONFIG=""
while [[ "$DIR" != "/" && "$DIR" != "." ]]; do
if [[ -f "${DIR}/tsconfig.json" ]]; then
TSCONFIG="${DIR}/tsconfig.json"
break
fi
DIR=$(dirname "$DIR")
done

if [[ -n "$TSCONFIG" ]]; then
ERRORS=$(cd "$(dirname "$TSCONFIG")" && npx tsc --noEmit --pretty false 2>&1 | grep -c "error TS" || true)
if [[ "$ERRORS" -gt 0 ]]; then
echo "WARNING: ${ERRORS} TypeScript error(s) detected after editing ${FILE}. Run typecheck to see details." >&2
fi
fi
;;
esac

# Never block — advisory only
exit 0
34 changes: 17 additions & 17 deletions plugin/safety/block-interactive.sh
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#!/usr/bin/env bash
# block-interactive.sh — Blocks AskUserQuestion in unattended sessions
#
# PreToolUse hook: exits 2 to block, 0 to allow.
# When Claude tries to ask a question, this forces it to decide instead.
#
# Copyright 2026 Stackbilt LLC — Apache 2.0
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
if [[ "$TOOL" == "AskUserQuestion" ]]; then
echo "BLOCKED: Autonomous mode — do not ask questions. Make a reasonable decision and document your reasoning." >&2
exit 2
fi
exit 0
#!/usr/bin/env bash
# block-interactive.sh — Blocks AskUserQuestion in unattended sessions
#
# PreToolUse hook: exits 2 to block, 0 to allow.
# When Claude tries to ask a question, this forces it to decide instead.
#
# Copyright 2026 Stackbilt LLC — Apache 2.0

INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)

if [[ "$TOOL" == "AskUserQuestion" ]]; then
echo "BLOCKED: Autonomous mode — do not ask questions. Make a reasonable decision and document your reasoning." >&2
exit 2
fi

exit 0
96 changes: 48 additions & 48 deletions plugin/safety/safety-gate.sh
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
#!/usr/bin/env bash
# safety-gate.sh — Blocks destructive commands in unattended sessions
#
# PreToolUse hook for Bash tool: checks command for dangerous patterns.
# Blocks: rm -rf, git push --force, DROP TABLE, deploys, secret access.
#
# Copyright 2026 Stackbilt LLC — Apache 2.0
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
if [[ "$TOOL" != "Bash" ]]; then
exit 0
fi
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
# Destructive filesystem operations
if echo "$CMD" | grep -qiE '(rm\s+-rf|rm\s+-r\s+/|>\s*/dev/)'; then
echo "BLOCKED: Destructive filesystem operation not allowed in autonomous mode" >&2
exit 2
fi
# Destructive git operations
if echo "$CMD" | grep -qiE '(git\s+reset\s+--hard|git\s+push\s+--force|git\s+push\s+-f|git\s+clean\s+-f)'; then
echo "BLOCKED: Destructive git operation not allowed in autonomous mode" >&2
exit 2
fi
# Database destruction
if echo "$CMD" | grep -qiE '(DROP\s+TABLE|TRUNCATE\s+TABLE|DELETE\s+FROM\s+\w+\s*$)'; then
echo "BLOCKED: Destructive database operation not allowed in autonomous mode" >&2
exit 2
fi
# Production deploys (require human approval)
if echo "$CMD" | grep -qiE '(wrangler\s+deploy|wrangler\s+publish|npm\s+run\s+deploy|kubectl\s+apply|terraform\s+apply)'; then
echo "BLOCKED: Production deploys require human approval. Commit your work and stop." >&2
exit 2
fi
# Secret management
if echo "$CMD" | grep -qiE '(wrangler\s+secret|echo\s+.*API_KEY|echo\s+.*TOKEN|echo\s+.*SECRET)'; then
echo "BLOCKED: Secret management not allowed in autonomous mode" >&2
exit 2
fi
exit 0
#!/usr/bin/env bash
# safety-gate.sh — Blocks destructive commands in unattended sessions
#
# PreToolUse hook for Bash tool: checks command for dangerous patterns.
# Blocks: rm -rf, git push --force, DROP TABLE, deploys, secret access.
#
# Copyright 2026 Stackbilt LLC — Apache 2.0

INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)

if [[ "$TOOL" != "Bash" ]]; then
exit 0
fi

CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)

# Destructive filesystem operations
if echo "$CMD" | grep -qiE '(rm\s+-rf|rm\s+-r\s+/|>\s*/dev/)'; then
echo "BLOCKED: Destructive filesystem operation not allowed in autonomous mode" >&2
exit 2
fi

# Destructive git operations
if echo "$CMD" | grep -qiE '(git\s+reset\s+--hard|git\s+push\s+--force|git\s+push\s+-f|git\s+clean\s+-f)'; then
echo "BLOCKED: Destructive git operation not allowed in autonomous mode" >&2
exit 2
fi

# Database destruction
if echo "$CMD" | grep -qiE '(DROP\s+TABLE|TRUNCATE\s+TABLE|DELETE\s+FROM\s+\w+\s*$)'; then
echo "BLOCKED: Destructive database operation not allowed in autonomous mode" >&2
exit 2
fi

# Production deploys (require human approval)
if echo "$CMD" | grep -qiE '(wrangler\s+deploy|wrangler\s+publish|npm\s+run\s+deploy|kubectl\s+apply|terraform\s+apply)'; then
echo "BLOCKED: Production deploys require human approval. Commit your work and stop." >&2
exit 2
fi

# Secret management
if echo "$CMD" | grep -qiE '(wrangler\s+secret|echo\s+.*API_KEY|echo\s+.*TOKEN|echo\s+.*SECRET)'; then
echo "BLOCKED: Secret management not allowed in autonomous mode" >&2
exit 2
fi

exit 0
Loading