fix(desktop-windows): wire chat quota gate into main-window send path (#10240)
Merged
FO
2mo ago+75+75+01234567890123456789-83-83-01234567890123456789
Summary
Closes #10240.
The main-window send path had no pre-send quota check — it fired the request, received the server's canned "You've reached your limit" reply as a chat message, and then UsageLimitTriggerHost polled the quota endpoint post-hoc to show the upgrade popup. This is now replaced with a proper pre-send gate matching Mac's AgentBridge.quotaExceeded parity and the bar's existing FloatingBarUsageLimiter parity:
useChat.send()callsmainChatQuotaGate.check()before the request fires. If blocked:showUsageLimit('chat')is raised immediately and the send returns — no request sent, no history entry, no canned server reply.UsageLimitTriggerHostnow callschatQuotaGate.sync()on the busy→idle edge to refresh the snapshot for the next send's check, instead of pollingmaybeTriggerChatQuotaPopup.maybeTriggerChatQuotaPopupremoved fromusageLimit.ts(no remaining callers).
Test plan
node_modules/.bin/vitest run src/renderer/src/lib/usageLimit.test.ts src/renderer/src/lib/chatQuotaGate.test.ts src/renderer/src/hooks/useChat.test.tsx— 68/68 pass- New
describe('useChat — chat quota gate')covers: blocked send (popup shown, no fetch, no history entry) and allowed send (proceeds,recordQuerycalled)
Product invariants affected
- INV-CHAT-1 (one shared transcript across surfaces): this change adds a pre-send quota gate to the main-window send path, maintaining the same chat flow invariant as Mac and the bar.
Failure-Class: none
🤖 Generated with Claude Code