Files
msd-core/sdk/src/query/query-fallback-bridge-adapter.ts
Tom Boucher b6c401dc90 refactor(query): deepen command/dispatch seams and resolve coderabbit findings
* refactor(query): deepen command definition seam and fold fallback mapping cleanup

* refactor(query): add shared dispatch formatting module seam

* fix(query): restore QueryResult type import in dispatch deps

* test/query: align raw-output policy and definition normalization contracts

* refactor(query): deepen diagnosis, invariant report, and error taxonomy seams

* refactor(query): deepen dispatch plan, fallback bridge, policy snapshot, and hints seams

* refactor(query): deepen validation, fallback policy, capability, and result builder seams

* refactor(query): deepen resolution strategy, output classifier, observability, and policy-capability seams

* refactor(query): finalize deep strategy/classifier/observability/capability seams

* test/query: address coderabbit inline and out-of-diff dispatch nits

* fix(query): address remaining coderabbit input-validation and bridge stderr threads

* fix(query): address remaining coderabbit dispatch and strategy/output nits
2026-05-03 15:29:34 -04:00

55 lines
1.8 KiB
TypeScript

import { execFile } from 'node:child_process';
import { classifyFallbackOutput } from './query-fallback-output-classifier.js';
export interface FallbackBridgeRunInput {
projectDir: string;
gsdToolsPath: string;
normCmd: string;
normArgs: string[];
ws?: string;
}
export interface FallbackBridgeOutput {
mode: 'json' | 'text';
output: unknown;
stderr: string;
}
function dottedCommandToCjsArgv(normCmd: string, normArgs: string[]): string[] {
if (normCmd.includes('.')) return [...normCmd.split('.'), ...normArgs];
return [normCmd, ...normArgs];
}
function execBridge(input: FallbackBridgeRunInput): Promise<{ stdout: string; stderr: string }> {
const cjsArgv = dottedCommandToCjsArgv(input.normCmd, input.normArgs);
const wsSuffix = input.ws ? ['--ws', input.ws] : [];
const fullArgv = [input.gsdToolsPath, ...cjsArgv, ...wsSuffix];
return new Promise((resolve, reject) => {
execFile(
process.execPath,
fullArgv,
{ cwd: input.projectDir, maxBuffer: 10 * 1024 * 1024, timeout: 30_000, killSignal: 'SIGKILL', env: { ...process.env } },
(err, stdout, stderr) => {
const stdoutText = stdout?.toString() ?? '';
const stderrText = stderr?.toString() ?? '';
if (err) {
if (stderrText.trim()) {
reject(new Error(`${err.message}\n${stderrText.trimEnd()}`));
return;
}
reject(err);
return;
}
resolve({ stdout: stdoutText, stderr: stderrText });
},
);
});
}
export async function runFallbackBridge(input: FallbackBridgeRunInput): Promise<FallbackBridgeOutput> {
const { stdout, stderr } = await execBridge(input);
const classified = await classifyFallbackOutput(stdout, input.projectDir);
return { ...classified, stderr };
}