diff --git a/sdk/src/gsd-transport.ts b/sdk/src/gsd-transport.ts index 69be7b680..7b9cefc8b 100644 --- a/sdk/src/gsd-transport.ts +++ b/sdk/src/gsd-transport.ts @@ -32,33 +32,48 @@ export class GSDTransport { ) {} async run(request: TransportRequest, policy: TransportPolicyLike): Promise { - const forceSubprocess = Boolean(request.workstream); - - if (!forceSubprocess && policy.preferNative && this.registry.has(request.registryCommand)) { + if (this.shouldUseNative(request, policy)) { try { const native = await this.adapters.dispatchNative(request); - if (request.mode === 'raw') { - if (this.adapters.formatNativeRaw) { - return this.adapters.formatNativeRaw(request.registryCommand, native.data).trim(); - } - return this.toRaw(native.data); - } - return native.data; + return this.projectNativeOutput(request, native.data); } catch (error) { - if (!policy.allowFallbackToSubprocess) throw error; - // Do not subprocess-fallback after a timed-out native dispatch: - // the timeout does not cancel the native handler, so falling through - // would run the same command twice (double-execution race). - if (toFailureSignal(error).kind === 'timeout') throw error; + if (this.shouldRethrowNativeError(error, policy)) throw error; } } + return this.dispatchSubprocess(request); + } + + private shouldUseNative(request: TransportRequest, policy: TransportPolicyLike): boolean { + const forceSubprocess = Boolean(request.workstream); + return !forceSubprocess && policy.preferNative && this.registry.has(request.registryCommand); + } + + private shouldRethrowNativeError(error: unknown, policy: TransportPolicyLike): boolean { + if (!policy.allowFallbackToSubprocess) return true; + // Do not subprocess-fallback after a timed-out native dispatch: + // the timeout does not cancel the native handler, so falling through + // would run the same command twice (double-execution race). + return toFailureSignal(error).kind === 'timeout'; + } + + private dispatchSubprocess(request: TransportRequest): Promise { if (request.mode === 'raw') { return this.adapters.execSubprocessRaw(request.legacyCommand, request.legacyArgs); } return this.adapters.execSubprocessJson(request.legacyCommand, request.legacyArgs); } + private projectNativeOutput(request: TransportRequest, data: unknown): unknown { + if (request.mode === 'raw') { + if (this.adapters.formatNativeRaw) { + return this.adapters.formatNativeRaw(request.registryCommand, data).trim(); + } + return this.toRaw(data); + } + return data; + } + private toRaw(data: unknown): string { if (typeof data === 'string') return data.trim(); const json = JSON.stringify(data, null, 2);