Skip to content

Fix Cursor hook misattribution and add token usage support#1263

Open
SnowingFox wants to merge 2 commits into
entireio:mainfrom
SnowingFox:feat/cursor-hook-guard-and-tokens
Open

Fix Cursor hook misattribution and add token usage support#1263
SnowingFox wants to merge 2 commits into
entireio:mainfrom
SnowingFox:feat/cursor-hook-guard-and-tokens

Conversation

@SnowingFox
Copy link
Copy Markdown

@SnowingFox SnowingFox commented May 26, 2026

close #1262
close #1264
image

Dispatch — feat/cursor-hook-guard-and-tokens

2026-05-26, 1 commit, 1 checkpoint (2a89e658287e)

Summary

This branch fixes Cursor session misattribution when only Claude Code hooks are installed (#1262), and adds token usage reporting for Cursor sessions by parsing the stop hook payload — the only authoritative source, since Cursor's JSONL transcript contains no usage fields.

Work Items

Bug Fix: Cross-agent hook forwarding guard (#1262)

  • Added shouldSkipForwardedHook() in hook_guard.go — checks if event.SessionRef (transcript path) belongs to a different registered agent via AgentForTranscriptPath
  • Wired the guard into executeAgentHook() in hook_registry.go, before DispatchLifecycleEvent — silently skips with a debug log when a forwarded hook is detected
  • Covers the scenario: user has .claude/settings.json but no .cursor/hooks.json; Cursor IDE fires Claude Code hooks; transcript path proves it's a Cursor session

Feature: Cursor token usage from stop hook

  • Added TokenUsage *TokenUsage field to agent.Event — allows hook parsers to inject authoritative token data that the framework prefers over transcript-based computation
  • Extended stopHookInputRaw in cursor/types.go with input_tokens, output_tokens, cache_read_tokens, cache_write_tokens fields
  • Implemented tokenUsageFromStop() in cursor/lifecycle.go — derives fresh input tokens as max(0, total_input - cache_read - cache_write), matching the story/apps/cli approach
  • Modified handleLifecycleTurnEnd in lifecycle.go to prefer event.TokenUsage over agent.CalculateTokenUsage() fallback

Tests

  • hook_guard_test.go: transcript belongs to other agent (skip), transcript belongs to self (pass through), full executeAgentHook integration test confirming no state file created
  • lifecycle_test.go: TestHandleLifecycleTurnEnd_PrefersEventTokenUsage — verifies hook-provided tokens flow into session state
  • cursor/lifecycle_test.go: token extraction from stop hook, nil when omitted, negative clamp to zero

1. Add transcript-owner guard in executeAgentHook to prevent Cursor
   sessions from being claimed by Claude Code when only
   .claude/settings.json is installed (fixes entireio#1262).

2. Parse token fields (input_tokens, output_tokens, cache_read_tokens,
   cache_write_tokens) from Cursor's stop hook payload into
   Event.TokenUsage so Cursor sessions report non-zero token counts.

3. Prefer hook-provided TokenUsage over transcript-based calculation
   in handleLifecycleTurnEnd, since Cursor's JSONL transcript has no
   usage data.

Co-authored-by: Cursor <cursoragent@cursor.com>
Entire-Checkpoint: 2a89e658287e
@SnowingFox SnowingFox requested a review from a team as a code owner May 26, 2026 07:42
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant