fix: multi-line TUI detection, stale scrollback, and false positives
The rate limit detection was fundamentally broken because Claude Code
renders rate limit messages across multiple lines in its TUI (Ink/React),
but all regex patterns required keywords on a single line.
Key fixes:
- Split detection into LIMIT_PATTERNS + RESET_PATTERNS with a 6-line
sliding window, so multi-line TUI renders are detected correctly
- Capture only last 20 lines instead of 200 to avoid stale scrollback
- Add 30s post-retry cooldown to prevent re-detecting old messages
- Fix max-retries infinite loop (stay in waiting, check clear first)
- Add OSC/DCS sequence stripping for complete ANSI handling
- Parse relative times ("try again in 5 minutes") instead of 5h fallback
- Handle invalid timezones gracefully with fallback
- Fix zombie monitor on pane destruction (exit after 10 consecutive errors)
- Replace setInterval with recursive setTimeout to prevent concurrent ticks
- Restore user shell traps instead of clobbering them
- Remove overly broad /\blimit\b/ pattern that caused false positives
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,21 @@ describe('parseResetTime', () => {
|
||||
it('returns null for unparseable text', () => {
|
||||
assert.equal(parseResetTime('some random text'), null);
|
||||
});
|
||||
it('parses "try again in 5 minutes" as relative time', () => {
|
||||
const r = parseResetTime('try again in 5 minutes');
|
||||
assert.ok(r.relative);
|
||||
assert.equal(r.waitMs, 5 * 60_000);
|
||||
});
|
||||
it('parses "try again in 2 hours" as relative time', () => {
|
||||
const r = parseResetTime('try again in 2 hours');
|
||||
assert.ok(r.relative);
|
||||
assert.equal(r.waitMs, 2 * 3_600_000);
|
||||
});
|
||||
it('parses "wait 30 mins" as relative time', () => {
|
||||
const r = parseResetTime('wait 30 mins');
|
||||
assert.ok(r.relative);
|
||||
assert.equal(r.waitMs, 30 * 60_000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculateWaitMs', () => {
|
||||
@@ -59,4 +74,12 @@ describe('calculateWaitMs', () => {
|
||||
);
|
||||
assert.ok(wait > 0 && wait <= 3 * 3600_000);
|
||||
});
|
||||
it('handles relative time correctly', () => {
|
||||
const wait = calculateWaitMs({ relative: true, waitMs: 300_000 }, 60, 5);
|
||||
assert.ok(Math.abs(wait - 360_000) < 2000); // 5 min + 60s margin
|
||||
});
|
||||
it('falls back on invalid timezone', () => {
|
||||
const wait = calculateWaitMs({ hour: 15, minute: 0, timezone: 'Invalid/Zone' }, 60, 5);
|
||||
assert.ok(Math.abs(wait - (5 * 3600 + 60) * 1000) < 2000); // fallback
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user