refactor: centralize query tools error construction in factory
This commit is contained in:
@@ -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 { failureToolsError, timeoutToolsError } from './query-tools-error-factory.js';
|
||||
|
||||
export interface GSDToolsRuntime {
|
||||
registry: ReturnType<typeof createRegistry>;
|
||||
@@ -34,18 +34,18 @@ export function createGSDToolsRuntime(opts: {
|
||||
timeoutMs: opts.timeoutMs,
|
||||
workstream: opts.workstream,
|
||||
createTimeoutError: (message, command, args, stderr, timeoutMs) =>
|
||||
GSDToolsError.timeout(message, command, args, stderr, timeoutMs),
|
||||
timeoutToolsError(message, command, args, stderr, timeoutMs),
|
||||
createFailureError: (message, command, args, exitCode, stderr) =>
|
||||
GSDToolsError.failure(message, command, args, exitCode, stderr),
|
||||
failureToolsError(message, command, args, exitCode, stderr),
|
||||
});
|
||||
|
||||
const nativeDirectAdapter = new QueryNativeDirectAdapter({
|
||||
timeoutMs: opts.timeoutMs,
|
||||
dispatch: (registryCommand, registryArgs) => registry.dispatch(registryCommand, registryArgs, opts.projectDir),
|
||||
createTimeoutError: (message, command, args) =>
|
||||
GSDToolsError.timeout(message, command, args, '', opts.timeoutMs),
|
||||
timeoutToolsError(message, command, args, '', opts.timeoutMs),
|
||||
createFailureError: (message, command, args, cause) =>
|
||||
GSDToolsError.failure(message, command, args, 1, '', { cause }),
|
||||
failureToolsError(message, command, args, 1, '', cause),
|
||||
});
|
||||
|
||||
const transport = new GSDTransport(registry, {
|
||||
|
||||
25
sdk/src/query-tools-error-factory.test.ts
Normal file
25
sdk/src/query-tools-error-factory.test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { ErrorClassification, GSDError } from './errors.js';
|
||||
import {
|
||||
failureToolsError,
|
||||
timeoutToolsError,
|
||||
toToolsErrorFromUnknown,
|
||||
} from './query-tools-error-factory.js';
|
||||
|
||||
describe('query tools error factory', () => {
|
||||
it('builds timeout and failure tools errors', () => {
|
||||
expect(timeoutToolsError('t', 'state', ['load'], '', 10).classification).toEqual({ kind: 'timeout', timeoutMs: 10 });
|
||||
expect(failureToolsError('f', 'state', ['load'], 1).classification).toEqual({ kind: 'failure' });
|
||||
});
|
||||
|
||||
it('maps GSDError to failure with semantic exit code', () => {
|
||||
const err = toToolsErrorFromUnknown('state', ['load'], new GSDError('bad', ErrorClassification.Validation));
|
||||
expect(err.exitCode).toBe(10);
|
||||
expect(err.classification).toEqual({ kind: 'failure' });
|
||||
});
|
||||
|
||||
it('maps timeout-like unknown errors to timeout classification', () => {
|
||||
const err = toToolsErrorFromUnknown('state', ['load'], new Error('gsd-tools timed out after 50ms: state load'));
|
||||
expect(err.classification).toEqual({ kind: 'timeout', timeoutMs: 50 });
|
||||
});
|
||||
});
|
||||
31
sdk/src/query-tools-error-factory.ts
Normal file
31
sdk/src/query-tools-error-factory.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { GSDError, exitCodeFor } from './errors.js';
|
||||
import { GSDToolsError } from './gsd-tools-error.js';
|
||||
import { errorMessage, toFailureSignal } from './query-failure-classification.js';
|
||||
|
||||
export function timeoutToolsError(message: string, command: string, args: string[], stderr = '', timeoutMs?: number): GSDToolsError {
|
||||
return GSDToolsError.timeout(message, command, args, stderr, timeoutMs);
|
||||
}
|
||||
|
||||
export function failureToolsError(
|
||||
message: string,
|
||||
command: string,
|
||||
args: string[],
|
||||
exitCode: number | null,
|
||||
stderr = '',
|
||||
cause?: unknown,
|
||||
): GSDToolsError {
|
||||
return GSDToolsError.failure(message, command, args, exitCode, stderr, cause === undefined ? undefined : { cause });
|
||||
}
|
||||
|
||||
export function toToolsErrorFromUnknown(command: string, args: string[], err: unknown): GSDToolsError {
|
||||
if (err instanceof GSDError) {
|
||||
return failureToolsError(err.message, command, args, exitCodeFor(err.classification), '', err);
|
||||
}
|
||||
|
||||
const msg = errorMessage(err);
|
||||
const signal = toFailureSignal(err);
|
||||
if (signal.kind === 'timeout') {
|
||||
return timeoutToolsError(msg, command, args, '', signal.timeoutMs);
|
||||
}
|
||||
return failureToolsError(msg, command, args, 1, '', err instanceof Error ? err : undefined);
|
||||
}
|
||||
@@ -1,27 +1,9 @@
|
||||
import { GSDError, exitCodeFor } from './errors.js';
|
||||
import { GSDToolsError } from './gsd-tools-error.js';
|
||||
import { errorMessage, toFailureSignal } from './query-failure-classification.js';
|
||||
import { toToolsErrorFromUnknown } from './query-tools-error-factory.js';
|
||||
import type { GSDToolsError } from './gsd-tools-error.js';
|
||||
|
||||
/**
|
||||
* Module owning projection of internal errors to GSDToolsError contract.
|
||||
*/
|
||||
export function toGSDToolsError(command: string, args: string[], err: unknown): GSDToolsError {
|
||||
if (err instanceof GSDError) {
|
||||
return GSDToolsError.failure(
|
||||
err.message,
|
||||
command,
|
||||
args,
|
||||
exitCodeFor(err.classification),
|
||||
'',
|
||||
{ cause: err },
|
||||
);
|
||||
}
|
||||
|
||||
const msg = errorMessage(err);
|
||||
const signal = toFailureSignal(err);
|
||||
if (signal.kind === 'timeout') {
|
||||
return GSDToolsError.timeout(msg, command, args, '', signal.timeoutMs, err instanceof Error ? { cause: err } : undefined);
|
||||
}
|
||||
|
||||
return GSDToolsError.failure(msg, command, args, 1, '', err instanceof Error ? { cause: err } : undefined);
|
||||
return toToolsErrorFromUnknown(command, args, err);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user