← Back to PRs

#9126: fix(macOS): prevent recursive menu nesting in status bar

by YuriNachos open 2026-02-04 22:18 View on GitHub →
app: macos stale
## Summary - Guards `menuWillOpen`/`menuDidClose` in `MenuSessionsInjector` to only process the main status item menu, not submenus - Prevents infinite recursive nesting when opening submenus like "Usage cost (30 days)" Fixes #9019 ## Root Cause The `MenuSessionsInjector` class is set as the delegate for the main status item menu. When a submenu opens (e.g., "Usage cost (30 days)"), `menuWillOpen` is called for that submenu as well. Without checking that the menu is the main status item menu, `inject(into: menu)` was called on the submenu, adding another "Usage cost (30 days)" menu item inside it - creating infinite recursion. ## Fix Added guard clauses to `menuWillOpen` and `menuDidClose`: ```swift guard menu === self.statusItem?.menu else { return } ``` This ensures: - Menu injection only happens for the main status item menu - State management (`isMenuOpen`, tasks) only tracks the main menu lifecycle - Submenus are left unchanged ## Test plan - [x] macOS app compiles successfully (`swift build`) - [ ] Manual test: Open menu bar → hover "Usage cost (30 days)" → verify no recursive submenu 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This change updates `MenuSessionsInjector` (the `NSMenuDelegate` for the macOS status item menu) to ignore submenu open/close events by guarding `menuWillOpen(_:)` and `menuDidClose(_:)` with `guard menu === self.statusItem?.menu else { return }`. This prevents the injector from re-running `inject(into:)` on submenus (e.g., the “Usage cost (30 days)” submenu, which also sets `menu.delegate = self`), eliminating the infinite recursive nesting of injected menu items while keeping menu open state/tasks scoped to the main status bar menu lifecycle. <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with minimal risk. - The change is a narrow guard in NSMenuDelegate callbacks that prevents a known infinite-recursion bug by scoping injection/state changes to the main status item menu; it doesn’t alter data formats or external interfaces. - apps/macos/Sources/Clawdbot/MenuSessionsInjector.swift <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs