#!/bin/bash # Budget report: summarize cost events and compare against policy. # Bash 3.2 compatible. Uses python3 for aggregation. # # Usage: ./budget-report.sh # # Placeholders: # {{WORKING_DIR}} - absolute path to project directory WORKING_DIR="{{WORKING_DIR}}" COST_LOG="$WORKING_DIR/budget/cost-events.jsonl" BUDGET_FILE="$WORKING_DIR/BUDGET.md" PAUSED_FLAG="$WORKING_DIR/budget/PAUSED" if [ ! -f "$COST_LOG" ]; then echo "No cost events recorded yet." exit 0 fi COST_LOG="$COST_LOG" BUDGET_FILE="$BUDGET_FILE" PAUSED_FLAG="$PAUSED_FLAG" python3 -c " import json, re, os from collections import defaultdict cost_log = os.environ.get('COST_LOG', '') budget_file = os.environ.get('BUDGET_FILE', '') paused_flag = os.environ.get('PAUSED_FLAG', '') # Read events events = [] with open(cost_log) as f: for line in f: line = line.strip() if line: try: events.append(json.loads(line)) except: pass # Aggregate by_agent = defaultdict(int) by_day = defaultdict(int) by_tool = defaultdict(int) for e in events: agent = e.get('agent', 'unknown') day = e.get('timestamp', '')[:10] tool = e.get('tool_name', 'unknown') by_agent[agent] += 1 by_day[day] += 1 by_tool[tool] += 1 print('BUDGET REPORT') print('=' * 50) print('Total events: ' + str(len(events))) print() # Per-agent breakdown print('By Agent:') for agent, count in sorted(by_agent.items(), key=lambda x: -x[1]): print(' ' + agent + ': ' + str(count) + ' events') print() # Per-day breakdown (last 7 days) print('By Day (last 7):') for day, count in sorted(by_day.items())[-7:]: print(' ' + day + ': ' + str(count) + ' events') print() # Budget comparison if os.path.exists(budget_file): content = open(budget_file).read() limit_m = re.search(r'limit:\s*(\d+)\s*cents', content) if limit_m: limit = int(limit_m.group(1)) est_cents = len(events) # rough proxy pct = (est_cents / limit * 100) if limit > 0 else 0 print('Budget: ~' + str(est_cents) + '/' + str(limit) + ' cents (' + str(round(pct)) + '%)') # Paused status if os.path.exists(paused_flag): print('') print('!! AGENT PAUSED: ' + open(paused_flag).read().strip()) print(' Remove ' + paused_flag + ' to resume') "