From 1201b4bb4b0b207d1c170fc3dcf39e79bbc545bd Mon Sep 17 00:00:00 2001 From: kaitranntt Date: Wed, 4 Feb 2026 00:59:10 -0500 Subject: [PATCH] fix(hooks): add network errors to noRetryPatterns, update E2E test - Add ENOTFOUND, ENETUNREACH, EAI_AGAIN to noRetryPatterns to prevent infinite retries on network errors - Update E2E test to expect exit code 2 (block) when CLIProxy unavailable - Fix debug message expectation in test --- lib/hooks/image-analyzer-transformer.cjs | 8 ++++++-- tests/e2e/image-analyzer-hook.e2e.test.ts | 14 +++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/hooks/image-analyzer-transformer.cjs b/lib/hooks/image-analyzer-transformer.cjs index fd1504ec..09362bb6 100755 --- a/lib/hooks/image-analyzer-transformer.cjs +++ b/lib/hooks/image-analyzer-transformer.cjs @@ -215,9 +215,13 @@ async function analyzeWithRetry(base64Data, mediaType, timeoutMs) { lastError = err; const isLastModel = i === models.length - 1; - // Don't retry on certain errors (auth, rate limit, timeout, file access) + // Don't retry on certain errors (auth, rate limit, timeout, file access, network) const errMsg = err.message || ''; - const noRetryPatterns = ['AUTH_ERROR', 'RATE_LIMIT', 'TIMEOUT', 'EACCES', 'EPERM', 'ECONNREFUSED']; + const noRetryPatterns = [ + 'AUTH_ERROR', 'RATE_LIMIT', 'TIMEOUT', + 'EACCES', 'EPERM', 'ECONNREFUSED', + 'ENOTFOUND', 'ENETUNREACH', 'EAI_AGAIN' // Network errors - no point retrying + ]; const shouldNotRetry = noRetryPatterns.some(p => errMsg.includes(p)); if (shouldNotRetry || isLastModel) { diff --git a/tests/e2e/image-analyzer-hook.e2e.test.ts b/tests/e2e/image-analyzer-hook.e2e.test.ts index b3da61dd..de00aa62 100644 --- a/tests/e2e/image-analyzer-hook.e2e.test.ts +++ b/tests/e2e/image-analyzer-hook.e2e.test.ts @@ -468,7 +468,7 @@ describe('Image Analyzer Hook', () => { resetMockState(); }); - it('should pass through when CLIProxy is unavailable', async () => { + it('should block when CLIProxy is unavailable to prevent context overflow', async () => { // Force hook to use a port that's definitely not running const result = invokeHook( { @@ -483,9 +483,13 @@ describe('Image Analyzer Hook', () => { } ); - // Should pass through (exit 0) when CLIProxy not available - expect(result.code).toBe(0); - expect(result.stderr).toContain('CLIProxy not available'); + // Should block (exit 2) when CLIProxy not available to prevent context overflow + expect(result.code).toBe(2); + const output = JSON.parse(result.stdout); + expect(output.decision).toBe('block'); + expect(output.hookSpecificOutput.permissionDecisionReason).toContain( + 'CLIProxy unavailable' + ); }); it('should analyze PNG via mock CLIProxy and return analysis', () => { @@ -634,7 +638,7 @@ describe('Image Analyzer Hook', () => { // Should output debug info to stderr expect(result.stderr).toContain('[CCS Hook]'); - expect(result.stderr).toContain('Analyzing'); + expect(result.stderr).toContain('Starting image analysis'); }); it('should handle API error response gracefully (pass through)', () => {