helpers.sh

  1#!/bin/bash
  2# Crush Hook Helper Functions
  3# These functions are automatically available in all hooks.
  4# No need to source this file - it's prepended automatically.
  5
  6# Permission helpers
  7
  8# Approve the current tool call.
  9# Usage: crush_approve ["message"]
 10crush_approve() {
 11  export CRUSH_PERMISSION=approve
 12  [ -n "$1" ] && export CRUSH_MESSAGE="$1"
 13}
 14
 15# Deny the current tool call.
 16# Usage: crush_deny ["message"]
 17crush_deny() {
 18  export CRUSH_PERMISSION=deny
 19  export CRUSH_CONTINUE=false
 20  [ -n "$1" ] && export CRUSH_MESSAGE="$1"
 21  exit 2
 22}
 23
 24# Ask user for permission (default behavior).
 25# Usage: crush_ask ["message"]
 26crush_ask() {
 27  export CRUSH_PERMISSION=ask
 28  [ -n "$1" ] && export CRUSH_MESSAGE="$1"
 29}
 30
 31# Context helpers
 32
 33# Add raw text content to LLM context.
 34# Usage: crush_add_context "content"
 35crush_add_context() {
 36  export CRUSH_CONTEXT_CONTENT="$1"
 37}
 38
 39# Add a file to be loaded into LLM context.
 40# Usage: crush_add_context_file "/path/to/file.md"
 41crush_add_context_file() {
 42  if [ -z "$CRUSH_CONTEXT_FILES" ]; then
 43    export CRUSH_CONTEXT_FILES="$1"
 44  else
 45    export CRUSH_CONTEXT_FILES="$CRUSH_CONTEXT_FILES:$1"
 46  fi
 47}
 48
 49# Modification helpers
 50
 51# Modify the user prompt (UserPromptSubmit hooks only).
 52# Usage: crush_modify_prompt "new prompt text"
 53crush_modify_prompt() {
 54  export CRUSH_MODIFIED_PROMPT="$1"
 55}
 56
 57# Modify tool input parameters (PreToolUse hooks only).
 58# Values are parsed as JSON when valid, supporting strings, numbers, booleans, arrays, objects.
 59# Usage: crush_modify_input "param_name" "value"
 60# Examples:
 61#   crush_modify_input "command" "ls -la"
 62#   crush_modify_input "offset" "100"
 63#   crush_modify_input "run_in_background" "true"
 64#   crush_modify_input "ignore" '["*.log","*.tmp"]'
 65crush_modify_input() {
 66  local key="$1"
 67  local value="$2"
 68  if [ -z "$CRUSH_MODIFIED_INPUT" ]; then
 69    export CRUSH_MODIFIED_INPUT="$key=$value"
 70  else
 71    export CRUSH_MODIFIED_INPUT="$CRUSH_MODIFIED_INPUT:$key=$value"
 72  fi
 73}
 74
 75# Modify tool output (PostToolUse hooks only).
 76# Usage: crush_modify_output "field_name" "value"
 77crush_modify_output() {
 78  local key="$1"
 79  local value="$2"
 80  if [ -z "$CRUSH_MODIFIED_OUTPUT" ]; then
 81    export CRUSH_MODIFIED_OUTPUT="$key=$value"
 82  else
 83    export CRUSH_MODIFIED_OUTPUT="$CRUSH_MODIFIED_OUTPUT:$key=$value"
 84  fi
 85}
 86
 87# Stop execution.
 88# Usage: crush_stop ["message"]
 89crush_stop() {
 90  export CRUSH_CONTINUE=false
 91  [ -n "$1" ] && export CRUSH_MESSAGE="$1"
 92  exit 1
 93}
 94
 95# Input parsing helpers
 96# These read from the JSON context saved in _CRUSH_STDIN
 97
 98# Get a field from the hook context.
 99# Usage: VALUE=$(crush_get_input "field_name")
100crush_get_input() {
101  echo "$_CRUSH_STDIN" | jq -r ".$1 // empty"
102}
103
104# Get a tool input parameter.
105# Usage: COMMAND=$(crush_get_tool_input "command")
106crush_get_tool_input() {
107  echo "$_CRUSH_STDIN" | jq -r ".tool_input.$1 // empty"
108}
109
110# Get the user prompt.
111# Usage: PROMPT=$(crush_get_prompt)
112crush_get_prompt() {
113  echo "$_CRUSH_STDIN" | jq -r '.prompt // empty'
114}
115
116# Logging helper.
117# Writes to stderr which is captured by Crush.
118# Usage: crush_log "debug message"
119crush_log() {
120  echo "[CRUSH HOOK] $*" >&2
121}