diff --git a/sdk/src/query-execution-policy.test.ts b/sdk/src/query-execution-policy.test.ts index 0b267a2e9..146801a5a 100644 --- a/sdk/src/query-execution-policy.test.ts +++ b/sdk/src/query-execution-policy.test.ts @@ -1,8 +1,12 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, it, expect, vi, afterEach } from 'vitest'; import { QueryExecutionPolicy } from './query-execution-policy.js'; import { setTransportPolicy, clearTransportPolicy } from './gsd-transport-policy.js'; describe('QueryExecutionPolicy', () => { + afterEach(() => { + clearTransportPolicy(); + }); + it('applies transport policy to transport.run', async () => { const run = vi.fn().mockResolvedValue({ ok: true }); const policy = new QueryExecutionPolicy({ run } as never); @@ -23,6 +27,5 @@ describe('QueryExecutionPolicy', () => { const [, policyArg] = run.mock.calls[0]; expect(policyArg).toEqual({ preferNative: true, allowFallbackToSubprocess: false }); - clearTransportPolicy(); }); }); diff --git a/sdk/src/query-raw-output-projection.ts b/sdk/src/query-raw-output-projection.ts index 720f36f7a..51f564435 100644 --- a/sdk/src/query-raw-output-projection.ts +++ b/sdk/src/query-raw-output-projection.ts @@ -10,6 +10,9 @@ export function formatQueryRawOutput(registryCommand: string, data: unknown): st } if (registryCommand === 'commit') { + if (data == null || typeof data !== 'object' || Array.isArray(data)) { + return JSON.stringify(data, null, 2); + } const d = data as Record; if (d.committed === true) { return d.hash != null ? String(d.hash) : 'committed'; @@ -33,6 +36,9 @@ export function formatQueryRawOutput(registryCommand: string, data: unknown): st } if (registryCommand === 'config-set') { + if (data == null || typeof data !== 'object' || Array.isArray(data)) { + return JSON.stringify(data, null, 2); + } const d = data as Record; if ((d.updated === true || d.set === true) && d.key !== undefined) { const v = d.value; @@ -48,6 +54,9 @@ export function formatQueryRawOutput(registryCommand: string, data: unknown): st } if (registryCommand === 'state.begin-phase' || registryCommand === 'state begin-phase') { + if (data == null || typeof data !== 'object' || Array.isArray(data)) { + return JSON.stringify(data, null, 2); + } const d = data as Record; const u = d.updated as string[] | undefined; return Array.isArray(u) && u.length > 0 ? 'true' : 'false'; diff --git a/sdk/src/query-subprocess-adapter.ts b/sdk/src/query-subprocess-adapter.ts index fbea8f7e6..029dbf0f3 100644 --- a/sdk/src/query-subprocess-adapter.ts +++ b/sdk/src/query-subprocess-adapter.ts @@ -103,6 +103,18 @@ export class QuerySubprocessAdapter { (error, stdout, stderr) => { const stderrStr = stderr?.toString() ?? ''; if (error) { + if (error.killed || (error as NodeJS.ErrnoException).code === 'ETIMEDOUT') { + reject( + this.deps.createToolsError( + `gsd-tools timed out after ${this.deps.timeoutMs}ms: ${command} ${args.join(' ')}`, + command, + args, + null, + stderrStr, + ), + ); + return; + } reject( this.deps.createToolsError( `gsd-tools exited with code ${error.code ?? 'unknown'}: ${command} ${args.join(' ')}${stderrStr ? `\n${stderrStr}` : ''}`,