#!/bin/bash # Shared functions for claude-code-supervisor hooks and scripts. set -euo pipefail # Find config file: project .claude-code-supervisor.yml → ~/.config/ → defaults ccs_find_config() { local cwd="${1:-.}" if [ -f "$cwd/.claude-code-supervisor.yml" ]; then echo "$cwd/.claude-code-supervisor.yml" elif [ -f "${HOME}/.config/claude-code-supervisor/config.yml" ]; then echo "${HOME}/.config/claude-code-supervisor/config.yml" else echo "" fi } # Read a yaml value (simple key.subkey extraction, no yq dependency). # Falls back to default if not found. ccs_config_get() { local config_file="$1" local key="$2" local default="${3:-}" if [ -z "$config_file" ] || [ ! -f "$config_file" ]; then echo "$default" return fi # Simple grep-based yaml extraction (handles key: value on one line) local value case "$key" in triage.command) value=$(grep -A0 '^\s*command:' "$config_file" | head -1 | sed 's/.*command:\s*["]*//;s/["]*$//' | xargs) ;; triage.model) value=$(awk '/^triage:/,/^[a-z]/' "$config_file" | grep 'model:' | head -1 | sed 's/.*model:\s*["]*//;s/["]*$//' | xargs) ;; triage.max_tokens) value=$(awk '/^triage:/,/^[a-z]/' "$config_file" | grep 'max_tokens:' | head -1 | sed 's/.*max_tokens:\s*//' | xargs) ;; notify.command) value=$(awk '/^notify:/,/^[a-z]/' "$config_file" | grep 'command:' | head -1 | sed 's/.*command:\s*["]*//;s/["]*$//' | xargs) ;; idle.timeout) value=$(awk '/^idle:/,/^[a-z]/' "$config_file" | grep 'timeout_seconds:' | head -1 | sed 's/.*timeout_seconds:\s*//' | xargs) ;; idle.nudge_message) value=$(awk '/^idle:/,/^[a-z]/' "$config_file" | grep 'nudge_message:' | head -1 | sed 's/.*nudge_message:\s*["]*//;s/["]*$//' | xargs) ;; *) value="" ;; esac echo "${value:-$default}" } # Send a notification via the configured notify command. ccs_notify() { local config_file="$1" local message="$2" local notify_cmd notify_cmd=$(ccs_config_get "$config_file" "notify.command" "openclaw gateway call wake --params") # Build JSON payload local payload payload=$(jq -n --arg text "$message" --arg mode "now" '{text: $text, mode: $mode}') $notify_cmd "$payload" 2>/dev/null || true } # Run LLM triage via configured command. # Accepts prompt on stdin, returns verdict on stdout. ccs_triage() { local config_file="$1" local prompt="$2" local triage_cmd model max_tokens triage_cmd=$(ccs_config_get "$config_file" "triage.command" "claude -p --no-session-persistence") model=$(ccs_config_get "$config_file" "triage.model" "claude-haiku-4-20250414") max_tokens=$(ccs_config_get "$config_file" "triage.max_tokens" "150") echo "$prompt" | $triage_cmd --model "$model" --max-tokens "$max_tokens" 2>/dev/null } # Generate a notify wrapper script the agent can call on completion. # Usage: ccs_generate_notify_script "$config_file" ["/tmp/supervisor-notify.sh"] ccs_generate_notify_script() { local config_file="$1" local script_path="${2:-/tmp/supervisor-notify.sh}" local notify_cmd notify_cmd=$(ccs_config_get "$config_file" "notify.command" "openclaw gateway call wake --params") cat > "$script_path" <