claude-print/scripts/check-billing.sh
jedarden 7a8945ae00 feat(bf-1n6): add scripts/check-billing.sh for AS-4 billing conformance
- Implement check-billing.sh script that verifies the most recent
  transcript has entrypoint 'cli' (subscription pool) not 'sdk-cli'
- Script finds newest *.jsonl under ~/.claude/projects/ and scans
  for entrypoint field, exiting 0 iff it equals 'cli'
- Handle no-transcripts and no-directory cases with distinct errors
- Update README with Troubleshooting and Release checklist sections
  referencing the script as the pre-release gate

Acceptance criteria:
- bash -n passes (syntax valid)
- Executable mode 755
- README updated with troubleshooting/release checklist references

Bead-Id: bf-1n6
2026-07-02 14:42:48 -04:00

79 lines
2.4 KiB
Bash
Executable file

#!/bin/bash
# check-billing.sh - AS-4 billing conformance script
# Inspects the most recent transcript JSONL under ~/.claude/projects/ and asserts
# the session has entrypoint 'cli' (subscription pool), not 'sdk-cli'.
# This is the AS-4 pre-release gate - run before every release.
set -eu
# ANSI color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1" >&2
}
# Find the newest JSONL file under ~/.claude/projects/
TRANSCRIPTS_DIR="$HOME/.claude/projects"
if [ ! -d "$TRANSCRIPTS_DIR" ]; then
log_error "Claude projects directory not found: $TRANSCRIPTS_DIR"
log_error "Has claude or claude-print been run on this machine?"
exit 1
fi
# Find the most recently modified .jsonl file (recursive)
NEWEST_JSONL=$(find "$TRANSCRIPTS_DIR" -type f -name "*.jsonl" -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-)
if [ -z "$NEWEST_JSONL" ]; then
log_error "No transcript JSONL files found under: $TRANSCRIPTS_DIR"
log_error "Run claude or claude-print first to generate a transcript."
exit 1
fi
log_info "Inspecting most recent transcript: $NEWEST_JSONL"
# Scan for the entrypoint field in the JSONL
# We use jq if available, fallback to grep+sed
ENTRYPOINT=
if command -v jq >/dev/null 2>&1; then
# Use jq for robust JSON parsing
ENTRYPOINT=$(grep -m1 '"entrypoint"' "$NEWEST_JSONL" | jq -r '.entrypoint // empty' 2>/dev/null || echo "")
else
# Fallback: extract with grep and sed
# Matches: "entrypoint": "cli" or "entrypoint":"cli"
ENTRYPOINT=$(grep -m1 '"entrypoint"' "$NEWEST_JSONL" | sed -n 's/.*"entrypoint"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' 2>/dev/null || echo "")
fi
if [ -z "$ENTRYPOINT" ]; then
log_error "No entrypoint field found in transcript: $NEWEST_JSONL"
log_error "The transcript may be from an incompatible Claude Code version."
exit 1
fi
# Print the entrypoint value
echo "entrypoint: $ENTRYPOINT"
# Assert it equals 'cli'
if [ "$ENTRYPOINT" = "cli" ]; then
log_info "Billing classification: SUBSCRIPTION (cli) - PASS"
exit 0
else
log_error "Billing classification: AGENT SDK CREDIT POOL ($ENTRYPOINT) - FAIL"
log_error "Expected: cli (subscription pool)"
log_error "Actual: $ENTRYPOINT"
log_error "File inspected: $NEWEST_JSONL"
exit 1
fi