diff --git a/sdk/src/gsd-tools-error.ts b/sdk/src/gsd-tools-error.ts index 68a5a1bc6..bc5d79880 100644 --- a/sdk/src/gsd-tools-error.ts +++ b/sdk/src/gsd-tools-error.ts @@ -3,6 +3,14 @@ export interface GSDToolsErrorClassification { timeoutMs?: number; } +export function timeoutClassification(timeoutMs?: number): GSDToolsErrorClassification { + return timeoutMs === undefined ? { kind: 'timeout' } : { kind: 'timeout', timeoutMs }; +} + +export function failureClassification(): GSDToolsErrorClassification { + return { kind: 'failure' }; +} + export class GSDToolsError extends Error { constructor( message: string, diff --git a/sdk/src/query-failure-classification.test.ts b/sdk/src/query-failure-classification.test.ts index 4232304c7..5f3774c74 100644 --- a/sdk/src/query-failure-classification.test.ts +++ b/sdk/src/query-failure-classification.test.ts @@ -1,7 +1,6 @@ import { describe, expect, it } from 'vitest'; import { errorMessage, - isTimeoutLikeError, isTimeoutMessage, parseTimeoutMs, timeoutMessage, @@ -16,13 +15,6 @@ describe('query failure classification', () => { expect(parseTimeoutMs(msg)).toBe(30000); }); - it('classifies timeout-like errors', () => { - expect(isTimeoutLikeError(new Error('gsd-tools timed out after 1000ms: x'))).toBe(true); - const abort = new Error('aborted'); - abort.name = 'AbortError'; - expect(isTimeoutLikeError(abort)).toBe(true); - }); - it('normalizes unknown error values', () => { expect(errorMessage('boom')).toBe('boom'); expect(errorMessage(new Error('x'))).toBe('x'); diff --git a/sdk/src/query-failure-classification.ts b/sdk/src/query-failure-classification.ts index 5fdda719e..e5a4a8aad 100644 --- a/sdk/src/query-failure-classification.ts +++ b/sdk/src/query-failure-classification.ts @@ -21,12 +21,6 @@ export function isTimeoutMessage(message: string): boolean { return /timed out after/i.test(message); } -export function isTimeoutLikeError(error: unknown): boolean { - if (!(error instanceof Error)) return false; - if (error.name === 'TimeoutError' || error.name === 'AbortError') return true; - return isTimeoutMessage(error.message); -} - export function timeoutMessage(command: string, args: string[], timeoutMs: number): string { return `gsd-tools timed out after ${timeoutMs}ms: ${command} ${args.join(' ')}`; } diff --git a/sdk/src/query-gsd-tools-runtime.ts b/sdk/src/query-gsd-tools-runtime.ts index 6ff59c513..3a9f72d92 100644 --- a/sdk/src/query-gsd-tools-runtime.ts +++ b/sdk/src/query-gsd-tools-runtime.ts @@ -7,7 +7,7 @@ import { QuerySubprocessAdapter } from './query-subprocess-adapter.js'; import { QueryNativeDirectAdapter } from './query-native-direct-adapter.js'; import { QueryNativeHotpathAdapter } from './query-native-hotpath-adapter.js'; import { formatQueryRawOutput } from './query-raw-output-projection.js'; -import { GSDToolsError } from './gsd-tools-error.js'; +import { failureClassification, GSDToolsError, timeoutClassification } from './gsd-tools-error.js'; export interface GSDToolsRuntime { registry: ReturnType; @@ -35,7 +35,7 @@ export function createGSDToolsRuntime(opts: { workstream: opts.workstream, createToolsError: (message, command, args, exitCode, stderr, classification) => new GSDToolsError(message, command, args, exitCode, stderr, { - classification: classification ?? { kind: 'failure' }, + classification: classification ?? failureClassification(), }), }); @@ -43,7 +43,7 @@ export function createGSDToolsRuntime(opts: { timeoutMs: opts.timeoutMs, dispatch: (registryCommand, registryArgs) => registry.dispatch(registryCommand, registryArgs, opts.projectDir), createTimeoutError: (message, command, args) => - new GSDToolsError(message, command, args, null, '', { classification: { kind: 'timeout', timeoutMs: opts.timeoutMs } }), + new GSDToolsError(message, command, args, null, '', { classification: timeoutClassification(opts.timeoutMs) }), }); const transport = new GSDTransport(registry, { diff --git a/sdk/src/query-tools-error-mapper.ts b/sdk/src/query-tools-error-mapper.ts index 357af2fe4..ee58ec0a8 100644 --- a/sdk/src/query-tools-error-mapper.ts +++ b/sdk/src/query-tools-error-mapper.ts @@ -1,5 +1,5 @@ import { GSDError, exitCodeFor } from './errors.js'; -import { GSDToolsError } from './gsd-tools-error.js'; +import { failureClassification, GSDToolsError, timeoutClassification } from './gsd-tools-error.js'; import { errorMessage, toFailureSignal } from './query-failure-classification.js'; /** @@ -20,8 +20,8 @@ export function toGSDToolsError(command: string, args: string[], err: unknown): const msg = errorMessage(err); const signal = toFailureSignal(err); const classification = signal.kind === 'timeout' - ? { kind: 'timeout' as const, timeoutMs: signal.timeoutMs } - : { kind: 'failure' as const }; + ? timeoutClassification(signal.timeoutMs) + : failureClassification(); return new GSDToolsError( msg,