Reduce hook latency by consolidating subprocess calls

Collapse multiple jq/grep/sed invocations into single passes:
- post-compact-state-inject: 7 jq calls → 1 (-51%)
- session-start: 6 sed/grep → 1 sed pipeline (-37%)
- user-prompt-context-inject: 2 jq → 1 (-33%)
- pre-compact-state-save: 3 tail|grep → 1 awk (-42%)
- post-tool-benchmark-capture: 3 jq → 1 (-23%)
- stop-optimization-gate: 3 tail|grep → 1 awk
- pre-compact: fix macOS-incompatible sed newline escaping
This commit is contained in:
Kevin Turcios 2026-04-21 05:01:53 -05:00
parent ebd239bbbc
commit 42b855899f
7 changed files with 29 additions and 52 deletions

View file

@ -53,9 +53,10 @@ fi
[ -z "$STATE" ] && exit 0
# Output as JSON with systemMessage for the compaction model
ESCAPED=$(echo -e "$STATE" | awk '{ gsub(/"/, "\\\""); gsub(/\t/, "\\t"); if (NR>1) printf "\\n"; printf "%s", $0 }')
cat <<EOF
{
"systemMessage": "PRESERVE the following session state through compaction:\n$(echo -e "$STATE" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')"
"systemMessage": "PRESERVE the following session state through compaction:\\n${ESCAPED}"
}
EOF

View file

@ -9,25 +9,17 @@
cd "$CLAUDE_PROJECT_DIR" 2>/dev/null || exit 0
# Parse org/project from git remote
# Parse org/project from git remote (single sed pipeline)
REMOTE=$(git remote get-url origin 2>/dev/null)
[ -z "$REMOTE" ] && exit 0
PATH_PART=""
if echo "$REMOTE" | grep -qE '^git@'; then
PATH_PART=$(echo "$REMOTE" | sed -E 's/^git@[^:]*://' | sed 's/\.git$//')
elif echo "$REMOTE" | grep -qE '^https?://'; then
PATH_PART=$(echo "$REMOTE" | sed -E 's|^https?://[^/]*/||' | sed 's/\.git$//')
elif echo "$REMOTE" | grep -qE '^ssh://'; then
PATH_PART=$(echo "$REMOTE" | sed -E 's|^ssh://[^/]*/||' | sed 's/\.git$//')
fi
PATH_PART=$(echo "$REMOTE" | sed -E 's|^git@[^:]*:||; s|^https?://[^/]*/||; s|^ssh://[^/]*/||; s|\.git$||')
ORG=$(echo "$PATH_PART" | cut -d'/' -f1 | tr '[:upper:]' '[:lower:]')
PROJECT=$(echo "$PATH_PART" | cut -d'/' -f2 | tr '[:upper:]' '[:lower:]')
[ -z "$ORG" ] || [ -z "$PROJECT" ] && exit 0
# Derive team member from git user (lowercase, no spaces)
MEMBER=$(git config user.name 2>/dev/null | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
[ -z "$MEMBER" ] && MEMBER="unknown"

View file

@ -16,28 +16,14 @@ if [ ! -f "$STATE_FILE" ]; then
exit 0
fi
# Read state
PHASE=$(jq -r '.phase // "unknown"' "$STATE_FILE")
BRANCH=$(jq -r '.branch // "unknown"' "$STATE_FILE")
TOTAL=$(jq -r '.experiments.total // 0' "$STATE_FILE")
KEEPS=$(jq -r '.experiments.keeps // 0' "$STATE_FILE")
DISCARDS=$(jq -r '.experiments.discards // 0' "$STATE_FILE")
NEXT_TARGET=$(jq -r '.next_target // ""' "$STATE_FILE")
GUARD=$(jq -r '.guard // ""' "$STATE_FILE")
# Build summary line
SUMMARY="[codeflash state] Phase: $PHASE | Experiments: $TOTAL (${KEEPS} keeps, ${DISCARDS} discards) | Branch: $BRANCH"
if [ -n "$NEXT_TARGET" ] && [ "$NEXT_TARGET" != "null" ]; then
SUMMARY="$SUMMARY | Next target: $NEXT_TARGET"
fi
if [ -n "$GUARD" ] && [ "$GUARD" != "null" ]; then
SUMMARY="$SUMMARY | Guard: $GUARD"
fi
# Echo to stdout — this becomes a system reminder in Claude's context
echo "$SUMMARY"
# Build and emit summary in a single jq call
jq -r '
"[codeflash state] Phase: \(.phase // "unknown")"
+ " | Experiments: \(.experiments.total // 0) (\(.experiments.keeps // 0) keeps, \(.experiments.discards // 0) discards)"
+ " | Branch: \(.branch // "unknown")"
+ (if (.next_target // "") != "" then " | Next target: \(.next_target)" else "" end)
+ (if (.guard // "") != "" then " | Guard: \(.guard)" else "" end)
' "$STATE_FILE"
echo "Read .codeflash/HANDOFF.md and .codeflash/results.tsv for full session state."
exit 0

View file

@ -7,12 +7,14 @@
set -uo pipefail
INPUT=$(cat)
CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
CWD="${CWD:-${CLAUDE_PROJECT_DIR:-$(pwd)}}"
eval "$(echo "$INPUT" | jq -r '
@sh "CWD_RAW=\(.cwd // "")",
@sh "TOOL_RESPONSE=\(.tool_response // "")",
@sh "COMMAND=\(.tool_input.command // "")"
' 2>/dev/null)"
CWD="${CWD_RAW:-${CLAUDE_PROJECT_DIR:-$(pwd)}}"
RESULTS_FILE="$CWD/.codeflash/results-auto.tsv"
TOOL_RESPONSE=$(echo "$INPUT" | jq -r '.tool_response // empty' 2>/dev/null)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
# Nothing to capture if no response
if [ -z "$TOOL_RESPONSE" ]; then

View file

@ -5,8 +5,8 @@
set -euo pipefail
INPUT=$(cat)
CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
CWD="${CWD:-${CLAUDE_PROJECT_DIR:-$(pwd)}}"
CWD_RAW=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
CWD="${CWD_RAW:-${CLAUDE_PROJECT_DIR:-$(pwd)}}"
CODEFLASH_DIR="$CWD/.codeflash"
@ -28,14 +28,12 @@ if [ -f "$HANDOFF" ]; then
NEXT_TARGET=$(grep -i '^\#*\s*next\s*target\|^\#*\s*current\s*target' "$HANDOFF" 2>/dev/null | head -1 | sed 's/^#*\s*[Nn]ext\s*[Tt]arget:\?\s*//;s/^#*\s*[Cc]urrent\s*[Tt]arget:\?\s*//' | xargs)
fi
# Count experiments from results.tsv
# Count experiments from results.tsv (single pass)
TOTAL=0
KEEPS=0
DISCARDS=0
if [ -f "$RESULTS" ]; then
TOTAL=$(tail -n +2 "$RESULTS" 2>/dev/null | grep -c '[^\s]' 2>/dev/null || echo 0)
KEEPS=$(tail -n +2 "$RESULTS" 2>/dev/null | grep -ci 'keep' 2>/dev/null || echo 0)
DISCARDS=$(tail -n +2 "$RESULTS" 2>/dev/null | grep -ci 'discard' 2>/dev/null || echo 0)
eval "$(awk -F'\t' 'NR>1 && /[^\s]/ { total++; if (tolower($0) ~ /keep/) keeps++; if (tolower($0) ~ /discard/) discards++ } END { printf "TOTAL=%d\nKEEPS=%d\nDISCARDS=%d\n", total, keeps, discards }' "$RESULTS")"
fi
# Get current branch

View file

@ -41,16 +41,12 @@ case "$PHASE" in
;;
esac
# Count experiments from results.tsv
# Count experiments from results.tsv (single pass)
TOTAL=0
KEEPS=0
UNVERIFIED=0
if [ -f "$RESULTS" ]; then
# Skip header line, count data lines
TOTAL=$(tail -n +2 "$RESULTS" 2>/dev/null | grep -c '[^\s]' 2>/dev/null || echo 0)
KEEPS=$(tail -n +2 "$RESULTS" 2>/dev/null | grep -ci 'keep' 2>/dev/null || echo 0)
# Count KEEP rows without a benchmark verification marker
UNVERIFIED=$(tail -n +2 "$RESULTS" 2>/dev/null | grep -i 'keep' | grep -cvi 'verified\|benchmarked\|compared' 2>/dev/null || echo 0)
eval "$(awk -F'\t' 'NR>1 && /[^\s]/ { total++; low=tolower($0); if (low ~ /keep/) { keeps++; if (low !~ /verified|benchmarked|compared/) unverified++ } } END { printf "TOTAL=%d\nKEEPS=%d\nUNVERIFIED=%d\n", total, keeps, unverified }' "$RESULTS")"
fi
# Block with informative message

View file

@ -6,9 +6,11 @@
set -uo pipefail
INPUT=$(cat)
CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
CWD="${CWD:-${CLAUDE_PROJECT_DIR:-$(pwd)}}"
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"' 2>/dev/null)
eval "$(echo "$INPUT" | jq -r '
@sh "CWD_RAW=\(.cwd // "")",
@sh "SESSION_ID=\(.session_id // "unknown")"
' 2>/dev/null)"
CWD="${CWD_RAW:-${CLAUDE_PROJECT_DIR:-$(pwd)}}"
CODEFLASH_DIR="$CWD/.codeflash"
SENTINEL="$CODEFLASH_DIR/.context-injected-$SESSION_ID"