




















@@ -54,6 +54,13 @@ export type QaGatewayChildStateMutationContext = {
5454tempRoot: string;
5555};
565657+export type QaGatewayChildCommand = {
58+executablePath: string;
59+argsPrefix?: string[];
60+cwd?: string;
61+usePackagedPlugins?: boolean;
62+};
63+5764async function getFreePort() {
5865return await new Promise<number>((resolve, reject) => {
5966const server = net.createServer();
@@ -435,6 +442,7 @@ export function resolveQaControlUiRoot(params: { repoRoot: string; controlUiEnab
435442436443export async function startQaGatewayChild(params: {
437444repoRoot: string;
445+command?: QaGatewayChildCommand;
438446providerBaseUrl?: string;
439447transport: Pick<QaTransportAdapter, "requiredPluginIds" | "createGatewayConfig">;
440448transportBaseUrl: string;
@@ -455,6 +463,10 @@ export async function startQaGatewayChild(params: {
455463);
456464const runtimeCwd = tempRoot;
457465const distEntryPath = path.join(params.repoRoot, "dist", "index.js");
466+const gatewayCommand = params.command;
467+const gatewayExecutablePath = gatewayCommand?.executablePath;
468+const gatewayArgsPrefix = gatewayCommand?.argsPrefix ?? [];
469+const gatewayCwd = gatewayCommand?.cwd ?? runtimeCwd;
458470const workspaceDir = path.join(tempRoot, "workspace");
459471const stateDir = path.join(tempRoot, "state");
460472const homeDir = path.join(tempRoot, "home");
@@ -558,7 +570,17 @@ export async function startQaGatewayChild(params: {
558570let env: NodeJS.ProcessEnv | null = null;
559571560572try {
561-const nodeExecPath = await resolveQaNodeExecPath();
573+const nodeExecPath = gatewayExecutablePath ?? (await resolveQaNodeExecPath());
574+const buildGatewayArgs = () => [
575+ ...(gatewayExecutablePath ? gatewayArgsPrefix : [distEntryPath, ...gatewayArgsPrefix]),
576+"gateway",
577+"run",
578+"--port",
579+String(gatewayPort),
580+"--bind",
581+"loopback",
582+"--allow-unconfigured",
583+];
562584for (let attempt = 1; attempt <= QA_GATEWAY_CHILD_STARTUP_MAX_ATTEMPTS; attempt += 1) {
563585gatewayPort = await getFreePort();
564586baseUrl = `http://127.0.0.1:${gatewayPort}`;
@@ -574,16 +596,22 @@ export async function startQaGatewayChild(params: {
574596);
575597},
576598);
577-const { bundledPluginsDir, stagedRoot } = await createQaBundledPluginsDir({
578-repoRoot: params.repoRoot,
579- tempRoot,
580- allowedPluginIds,
581-});
582-stagedBundledPluginsRoot = stagedRoot;
583-const runtimeHostVersion = await resolveQaRuntimeHostVersion({
584-repoRoot: params.repoRoot,
585- allowedPluginIds,
586-});
599+const stagedPluginRuntime = gatewayCommand?.usePackagedPlugins
600+ ? { bundledPluginsDir: undefined, runtimeHostVersion: undefined }
601+ : {
602+ ...(await createQaBundledPluginsDir({
603+repoRoot: params.repoRoot,
604+ tempRoot,
605+ allowedPluginIds,
606+})),
607+runtimeHostVersion: await resolveQaRuntimeHostVersion({
608+repoRoot: params.repoRoot,
609+ allowedPluginIds,
610+}),
611+};
612+if ("stagedRoot" in stagedPluginRuntime) {
613+stagedBundledPluginsRoot = stagedPluginRuntime.stagedRoot;
614+}
587615env = buildQaRuntimeEnv({
588616 configPath,
589617 gatewayToken,
@@ -593,8 +621,8 @@ export async function startQaGatewayChild(params: {
593621 xdgConfigHome,
594622 xdgDataHome,
595623 xdgCacheHome,
596- bundledPluginsDir,
597-compatibilityHostVersion: runtimeHostVersion,
624+bundledPluginsDir: stagedPluginRuntime.bundledPluginsDir,
625+compatibilityHostVersion: stagedPluginRuntime.runtimeHostVersion,
598626 providerMode,
599627forwardHostHomeForClaudeCli: liveProviderIds.includes("claude-cli"),
600628claudeCliAuthMode: params.claudeCliAuthMode,
@@ -608,25 +636,12 @@ export async function startQaGatewayChild(params: {
608636throw new Error("qa gateway runtime env not initialized");
609637}
610638611-const attemptChild = spawn(
612-nodeExecPath,
613-[
614-distEntryPath,
615-"gateway",
616-"run",
617-"--port",
618-String(gatewayPort),
619-"--bind",
620-"loopback",
621-"--allow-unconfigured",
622-],
623-{
624-cwd: runtimeCwd,
625- env,
626-detached: process.platform !== "win32",
627-stdio: ["ignore", "pipe", "pipe"],
628-},
629-);
639+const attemptChild = spawn(nodeExecPath, buildGatewayArgs(), {
640+cwd: gatewayCwd,
641+ env,
642+detached: process.platform !== "win32",
643+stdio: ["ignore", "pipe", "pipe"],
644+});
630645attemptChild.stdout.on("data", (chunk) => {
631646const buffer = Buffer.from(chunk);
632647stdout.push(buffer);
@@ -714,25 +729,12 @@ export async function startQaGatewayChild(params: {
714729const runningEnv = env;
715730716731const spawnReplacementGatewayChild = async () => {
717-const nextChild = spawn(
718-nodeExecPath,
719-[
720-distEntryPath,
721-"gateway",
722-"run",
723-"--port",
724-String(gatewayPort),
725-"--bind",
726-"loopback",
727-"--allow-unconfigured",
728-],
729-{
730-cwd: runtimeCwd,
731-env: runningEnv,
732-detached: process.platform !== "win32",
733-stdio: ["ignore", "pipe", "pipe"],
734-},
735-);
732+const nextChild = spawn(nodeExecPath, buildGatewayArgs(), {
733+cwd: gatewayCwd,
734+env: runningEnv,
735+detached: process.platform !== "win32",
736+stdio: ["ignore", "pipe", "pipe"],
737+});
736738nextChild.stdout.on("data", (chunk) => {
737739const buffer = Buffer.from(chunk);
738740stdout.push(buffer);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。