4 Commits

  • fix(hooks): cost-tracker reads usage from transcript instead of stdin
    The Stop hook's stdin payload does not include `usage` or `model` —
    those fields exist only in the session transcript JSONL (per-assistant-turn
    `message.usage` blocks). The previous implementation looked for
    `input.usage.input_tokens` on stdin and silently produced zero-filled rows
    (observed: 2,340 rows captured with 0.0% non-zero token rate over 52 days).
    
    Fix: read `transcript_path` from Stop stdin, scan the JSONL, sum usage
    across all assistant turns. Use `message.model` to pick a rate tier
    (haiku/sonnet/opus). Track cache tokens separately (cache_creation and
    cache_read have distinct billing rates).
    
    Behavior note: Stop fires per assistant response, so each row in
    costs.jsonl represents the cumulative session total at that point.
    To get per-session cost: take the last row per session_id.
    
    Verified by reading a real Stop hook payload from
    .claude/projects/*/<uuid>.jsonl — payload contains
    {session_id, transcript_path, cwd, hook_event_name, ...} only,
    matching the published Claude Code hook spec.
  • feat: add ECC statusline observability hooks
    Salvages the useful statusline/context monitor work from stale PR #1504 while preserving the current continuous-learning hook runner wiring.
    
    Adds the metrics bridge, context monitor, statusline script, shared cost/session bridge utilities, and tests. Fixes the reviewed false loop-detection hash collision for non-file tools, avoids default-session cost inflation, sanitizes statusline task lookup, and records hook payload session IDs in cost-tracker.