#!/usr/bin/env bash # Verify any Bash call with command matching a regex fires before any other Bash call # matching a second regex. # # Usage: tool-match-before-tool-match # Example: tool-match-before-tool-match Bash 'pytest' Bash 'git[[:space:]]+commit' # # Semantics: # - If no call matches the "later" regex, PASS (vacuously — the gated event never happened). # - If the "later" call fires but no "earlier" call preceded it, FAIL. set -euo pipefail command -v jq >/dev/null || { echo "jq required"; exit 127; } TOOL_A="$1" REGEX_A="$2" TOOL_B="$3" REGEX_B="$4" FILE="tool_calls.jsonl" if [ ! -s "$FILE" ]; then echo "FAIL: tool_calls.jsonl missing or empty" exit 1 fi IDX_A=$( jq -s --arg tool "$TOOL_A" --arg re "$REGEX_A" \ 'to_entries | map(select(.value.tool == $tool and ((.value.args.command // "") | test($re)))) | first | (.key // -1)' \ "$FILE" ) IDX_B=$( jq -s --arg tool "$TOOL_B" --arg re "$REGEX_B" \ 'to_entries | map(select(.value.tool == $tool and ((.value.args.command // "") | test($re)))) | first | (.key // -1)' \ "$FILE" ) if [ "$IDX_B" -lt 0 ]; then echo "PASS: no $TOOL_B call matched /$REGEX_B/ — assertion is vacuous" exit 0 fi if [ "$IDX_A" -lt 0 ]; then echo "FAIL: $TOOL_B /$REGEX_B/ fired at line $((IDX_B + 1)) but no $TOOL_A /$REGEX_A/ preceded it" exit 1 fi if [ "$IDX_A" -lt "$IDX_B" ]; then echo "PASS: $TOOL_A /$REGEX_A/ at line $((IDX_A + 1)) before $TOOL_B /$REGEX_B/ at line $((IDX_B + 1))" exit 0 else echo "FAIL: $TOOL_A /$REGEX_A/ at line $((IDX_A + 1)) fired after $TOOL_B /$REGEX_B/ at line $((IDX_B + 1))" exit 1 fi