diff --git a/src/defaultSettings.ts b/src/defaultSettings.ts index 9240c211..c38e2b12 100644 --- a/src/defaultSettings.ts +++ b/src/defaultSettings.ts @@ -699,6 +699,7 @@ export const DEFAULT_SETTINGS: Settings = { increaseFileReadLimit: false, suppressLineNumbers: false, suppressRateLimitOptions: false, + suppressRateLimitWarning: false, mcpConnectionNonBlocking: true, mcpServerBatchSize: null, statuslineThrottleMs: null, diff --git a/src/patches/index.ts b/src/patches/index.ts index a1c69861..f77a4181 100644 --- a/src/patches/index.ts +++ b/src/patches/index.ts @@ -58,6 +58,7 @@ import { writeHideStartupClawd } from './hideStartupClawd'; import { writeIncreaseFileReadLimit } from './increaseFileReadLimit'; import { writeSuppressLineNumbers } from './suppressLineNumbers'; import { writeSuppressRateLimitOptions } from './suppressRateLimitOptions'; +import { writeSuppressRateLimitWarning } from './suppressRateLimitWarning'; import { writeSessionMemory } from './sessionMemory'; import { writeRememberSkill } from './rememberSkill'; import { writeThinkingBlockStyling } from './thinkingBlockStyling'; @@ -311,6 +312,13 @@ const PATCH_DEFINITIONS = [ description: "/rate-limit-options won't be injected when limits are reached", }, + { + id: 'suppress-rate-limit-warning', + name: 'Suppress rate limit warning', + group: PatchGroup.MISC_CONFIGURABLE, + description: + 'Rate limit warning banners will be suppressed (errors still shown)', + }, { id: 'token-count-rounding', name: 'Token count rounding', @@ -781,6 +789,10 @@ export const applyCustomization = async ( fn: c => writeSuppressRateLimitOptions(c), condition: !!config.settings.misc?.suppressRateLimitOptions, }, + 'suppress-rate-limit-warning': { + fn: c => writeSuppressRateLimitWarning(c), + condition: !!config.settings.misc?.suppressRateLimitWarning, + }, 'token-count-rounding': { fn: c => writeTokenCountRounding(c, config.settings.misc!.tokenCountRounding!), diff --git a/src/patches/suppressRateLimitWarning.test.ts b/src/patches/suppressRateLimitWarning.test.ts new file mode 100644 index 00000000..ad266e0a --- /dev/null +++ b/src/patches/suppressRateLimitWarning.test.ts @@ -0,0 +1,45 @@ +import { describe, it, expect } from 'vitest'; +import { writeSuppressRateLimitWarning } from './suppressRateLimitWarning'; + +describe('writeSuppressRateLimitWarning', () => { + const makeInput = (delimiter = '}') => + `function Ip8(H,$){let q=d2K(H,$)${delimiter}if(q&&q.severity==="warning")return q.message;return null}`; + + it('should replace warning message return with null', () => { + const input = makeInput(); + const result = writeSuppressRateLimitWarning(input); + expect(result).not.toBeNull(); + expect(result).toContain('if(q&&q.severity==="warning")return null;'); + expect(result).not.toContain('return q.message'); + }); + + it('should return unchanged file when already patched', () => { + const input = makeInput(); + const patched = writeSuppressRateLimitWarning(input)!; + const result = writeSuppressRateLimitWarning(patched); + expect(result).toBe(patched); + }); + + it('should return null when pattern not found', () => { + const result = writeSuppressRateLimitWarning('no matching content here'); + expect(result).toBeNull(); + }); + + it('should preserve error-path message returns', () => { + const input = + 'function Rp8(H,$){let q=d2K(H,$)}if(q&&q.severity==="error")return q.message;return null}' + + 'function Ip8(H,$){let q=d2K(H,$)}if(q&&q.severity==="warning")return q.message;return null}'; + const result = writeSuppressRateLimitWarning(input); + expect(result).not.toBeNull(); + expect(result).toContain('severity==="error")return q.message;'); + expect(result).toContain('severity==="warning")return null;'); + }); + + it('should work with different delimiters', () => { + for (const d of [',', ';', '}', '{']) { + const result = writeSuppressRateLimitWarning(makeInput(d)); + expect(result).not.toBeNull(); + expect(result).toContain('severity==="warning")return null;'); + } + }); +}); diff --git a/src/patches/suppressRateLimitWarning.ts b/src/patches/suppressRateLimitWarning.ts new file mode 100644 index 00000000..19f7c4e9 --- /dev/null +++ b/src/patches/suppressRateLimitWarning.ts @@ -0,0 +1,35 @@ +import { debug } from '../utils'; +import { showDiff } from './index'; + +export const writeSuppressRateLimitWarning = ( + oldFile: string +): string | null => { + const alreadyPatched = + /[,;{}]if\(([$\w]+)&&\1\.severity==="warning"\)return null;/; + if (alreadyPatched.test(oldFile)) return oldFile; + + const pattern = + /[,;{}]if\(([$\w]+)&&\1\.severity==="warning"\)return \1\.message;/; + + const match = oldFile.match(pattern); + + if (!match || match.index === undefined) { + debug( + 'patch: suppressRateLimitWarning: failed to find rate limit warning getter pattern' + ); + return null; + } + + const varName = match[1]; + const original = match[0]; + const delimiter = original[0]; + const replacement = `${delimiter}if(${varName}&&${varName}.severity==="warning")return null;`; + const startIndex = match.index; + const endIndex = startIndex + original.length; + + const newFile = + oldFile.slice(0, startIndex) + replacement + oldFile.slice(endIndex); + + showDiff(oldFile, newFile, replacement, startIndex, endIndex); + return newFile; +}; diff --git a/src/types.ts b/src/types.ts index 0aa23747..06791484 100644 --- a/src/types.ts +++ b/src/types.ts @@ -117,6 +117,7 @@ export interface MiscConfig { increaseFileReadLimit: boolean; suppressLineNumbers: boolean; suppressRateLimitOptions: boolean; + suppressRateLimitWarning: boolean; mcpConnectionNonBlocking: boolean; mcpServerBatchSize: number | null; statuslineThrottleMs: number | null; diff --git a/src/ui/components/MiscView.tsx b/src/ui/components/MiscView.tsx index e0d9e3bf..c80ed109 100644 --- a/src/ui/components/MiscView.tsx +++ b/src/ui/components/MiscView.tsx @@ -65,6 +65,7 @@ export function MiscView({ onSubmit }: MiscViewProps) { increaseFileReadLimit: false, suppressLineNumbers: false, suppressRateLimitOptions: false, + suppressRateLimitWarning: false, mcpConnectionNonBlocking: true, mcpServerBatchSize: null as number | null, statuslineThrottleMs: null as number | null, @@ -324,6 +325,20 @@ export function MiscView({ onSubmit }: MiscViewProps) { }); }, }, + { + id: 'suppressRateLimitWarning', + title: 'Suppress rate limit warning banners', + description: + 'Hides rate limit warning banners in the status bar. Error messages when limits are actually reached are still shown.', + getValue: () => settings.misc?.suppressRateLimitWarning ?? false, + toggle: () => { + updateSettings(settings => { + ensureMisc(); + settings.misc!.suppressRateLimitWarning = + !settings.misc!.suppressRateLimitWarning; + }); + }, + }, { id: 'mcpNonBlocking', title: 'Non-blocking MCP startup',