diff --git a/package-lock.json b/package-lock.json index 4bdf885..986e122 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1027,7 +1027,6 @@ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", "license": "MIT", - "peer": true, "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", @@ -1611,7 +1610,6 @@ "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -1661,7 +1659,6 @@ "integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.53.1", "@typescript-eslint/types": "8.53.1", @@ -2063,7 +2060,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2560,7 +2556,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3849,7 +3844,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -4002,7 +3996,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -4208,7 +4201,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -4222,7 +4214,6 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", diff --git a/src/core/target-handlers/acp-handler.ts b/src/core/target-handlers/acp-handler.ts index cfa023c..ab55244 100644 --- a/src/core/target-handlers/acp-handler.ts +++ b/src/core/target-handlers/acp-handler.ts @@ -121,8 +121,12 @@ export class ACPTargetHandler implements TargetHandler { try { const msg = JSON.parse(line) as ACPMessage; this.handleMessage(msg); - } catch { - // Ignore parse errors (partial messages) + } catch (err) { + // Log parse errors in debug mode + if (process.env['DEBUG'] || process.env['WORK_DEBUG']) { + console.warn('ACP message parse error:', err instanceof Error ? err.message : String(err)); + console.warn('Problematic line:', line.substring(0, 200)); + } } } } diff --git a/tests/unit/core/target-handlers/acp-handler.test.ts b/tests/unit/core/target-handlers/acp-handler.test.ts index 0c2806b..1bf244a 100644 --- a/tests/unit/core/target-handlers/acp-handler.test.ts +++ b/tests/unit/core/target-handlers/acp-handler.test.ts @@ -26,10 +26,17 @@ describe('ACPTargetHandler', () => { let mockProcess: any; const mockSpawn = spawn as any; + let savedDebug: string | undefined; + let savedWorkDebug: string | undefined; + beforeEach(() => { vi.clearAllMocks(); vi.useFakeTimers(); + // Save environment variables for restoration + savedDebug = process.env['DEBUG']; + savedWorkDebug = process.env['WORK_DEBUG']; + // Create a more realistic mock process mockProcess = { stdin: { @@ -70,6 +77,18 @@ describe('ACPTargetHandler', () => { afterEach(() => { vi.useRealTimers(); + + // Restore environment variables + if (savedDebug !== undefined) { + process.env['DEBUG'] = savedDebug; + } else { + delete process.env['DEBUG']; + } + if (savedWorkDebug !== undefined) { + process.env['WORK_DEBUG'] = savedWorkDebug; + } else { + delete process.env['WORK_DEBUG']; + } }); describe('formatWorkItems', () => { @@ -384,6 +403,92 @@ describe('ACPTargetHandler', () => { // Should not throw expect(true).toBe(true); }); + + it('should not log parse errors when DEBUG is not set', () => { + const consoleWarnSpy = vi.spyOn(console, 'warn'); + delete process.env['DEBUG']; + delete process.env['WORK_DEBUG']; + + (handler as any).ensureProcess(mockConfig); + + // Send invalid JSON + mockProcess.stdout.emit('data', 'invalid json\n'); + + // Should not log anything + expect(consoleWarnSpy).not.toHaveBeenCalled(); + + consoleWarnSpy.mockRestore(); + }); + + it('should log parse errors when DEBUG is set', () => { + const consoleWarnSpy = vi.spyOn(console, 'warn'); + process.env['DEBUG'] = '1'; + + (handler as any).ensureProcess(mockConfig); + + // Send invalid JSON + mockProcess.stdout.emit('data', 'invalid json\n'); + + // Should log error message first, then problematic line + expect(consoleWarnSpy).toHaveBeenCalledTimes(2); + expect(consoleWarnSpy).toHaveBeenNthCalledWith( + 1, + 'ACP message parse error:', + expect.stringContaining('JSON') + ); + expect(consoleWarnSpy).toHaveBeenNthCalledWith( + 2, + 'Problematic line:', + 'invalid json' + ); + + consoleWarnSpy.mockRestore(); + }); + + it('should log parse errors when WORK_DEBUG is set', () => { + const consoleWarnSpy = vi.spyOn(console, 'warn'); + process.env['WORK_DEBUG'] = '1'; + + (handler as any).ensureProcess(mockConfig); + + // Send invalid JSON + mockProcess.stdout.emit('data', 'invalid json\n'); + + // Should log error message first, then problematic line + expect(consoleWarnSpy).toHaveBeenCalledTimes(2); + expect(consoleWarnSpy).toHaveBeenNthCalledWith( + 1, + 'ACP message parse error:', + expect.stringContaining('JSON') + ); + expect(consoleWarnSpy).toHaveBeenNthCalledWith( + 2, + 'Problematic line:', + 'invalid json' + ); + + consoleWarnSpy.mockRestore(); + }); + + it('should truncate long problematic lines to 200 characters', () => { + const consoleWarnSpy = vi.spyOn(console, 'warn'); + process.env['DEBUG'] = '1'; + + (handler as any).ensureProcess(mockConfig); + + // Send invalid JSON that's longer than 200 characters + const longInvalidJson = 'x'.repeat(300) + '\n'; + mockProcess.stdout.emit('data', longInvalidJson); + + // Should log truncated line (200 chars max) + expect(consoleWarnSpy).toHaveBeenNthCalledWith( + 2, + 'Problematic line:', + 'x'.repeat(200) + ); + + consoleWarnSpy.mockRestore(); + }); }); describe('cleanup', () => {