skill-before-tool-match 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. #!/usr/bin/env bash
  2. # Verify a specific Skill was invoked before any Bash call whose command matches a regex.
  3. #
  4. # Usage: skill-before-tool-match <skill-name> <bash-command-regex>
  5. # Example: skill-before-tool-match superpowers:verification-before-completion 'git[[:space:]]+commit'
  6. #
  7. # Semantics:
  8. # - If no Bash call matches the regex, PASS (vacuously — the gated event never occurred).
  9. # - If Bash matches but Skill with that name never appeared earlier, FAIL.
  10. # - If both appeared and Skill came first, PASS.
  11. # - If Skill never appeared but Bash matched, FAIL.
  12. set -euo pipefail
  13. command -v jq >/dev/null || { echo "jq required"; exit 127; }
  14. SKILL_NAME="$1"
  15. BASH_REGEX="$2"
  16. FILE="tool_calls.jsonl"
  17. if [ ! -s "$FILE" ]; then
  18. echo "FAIL: tool_calls.jsonl missing or empty"
  19. exit 1
  20. fi
  21. # First index where Skill(skill=SKILL_NAME) appears (0-based).
  22. SKILL_IDX=$(
  23. jq -s --arg name "$SKILL_NAME" \
  24. 'to_entries | map(select(.value.tool == "Skill" and (.value.args.skill // "") == $name)) | first | (.key // -1)' \
  25. "$FILE"
  26. )
  27. # First index where Bash(command =~ BASH_REGEX) appears.
  28. BASH_IDX=$(
  29. jq -s --arg re "$BASH_REGEX" \
  30. 'to_entries | map(select(.value.tool == "Bash" and ((.value.args.command // "") | test($re)))) | first | (.key // -1)' \
  31. "$FILE"
  32. )
  33. if [ "$BASH_IDX" -lt 0 ]; then
  34. echo "PASS: no Bash call matched /$BASH_REGEX/ — assertion is vacuous"
  35. exit 0
  36. fi
  37. if [ "$SKILL_IDX" -lt 0 ]; then
  38. echo "FAIL: Bash /$BASH_REGEX/ fired at line $((BASH_IDX + 1)) but Skill($SKILL_NAME) never fired"
  39. exit 1
  40. fi
  41. if [ "$SKILL_IDX" -lt "$BASH_IDX" ]; then
  42. echo "PASS: Skill($SKILL_NAME) at line $((SKILL_IDX + 1)) before Bash /$BASH_REGEX/ at line $((BASH_IDX + 1))"
  43. exit 0
  44. else
  45. echo "FAIL: Skill($SKILL_NAME) at line $((SKILL_IDX + 1)) fired after Bash /$BASH_REGEX/ at line $((BASH_IDX + 1))"
  46. exit 1
  47. fi