import esbuild from "esbuild";
import { spawn } from "node:child_process";
import { chmodSync, cpSync, existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
import { builtinModules, createRequire } from "node:module";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const requireFromHere = createRequire(import.meta.url);
export const projectRoot = path.resolve(__dirname, "..");
export const packagesRoot = path.join(projectRoot, "packages");
export const cliRoot = path.join(packagesRoot, "cli");
export const coreRoot = path.join(packagesRoot, "core");
export const electronRoot = path.join(packagesRoot, "electron");
export const uiRoot = path.join(packagesRoot, "ui");
export const cliSourceRoot = path.join(cliRoot, "src");
export const coreSourceRoot = path.join(coreRoot, "src");
export const electronSourceRoot = path.join(electronRoot, "src");
export const uiSourceRoot = path.join(uiRoot, "src");
export const legacyDistDir = path.join(projectRoot, "dist");
export const cliDistDir = path.join(cliRoot, "dist");
export const coreDistDir = path.join(coreRoot, "dist");
export const electronDistDir = path.join(electronRoot, "dist");
export const uiDistDir = path.join(uiRoot, "dist");
export const distDir = electronDistDir;
export const cliMainOutDir = path.join(cliDistDir, "main");
export const coreMainOutDir = path.join(coreDistDir, "main");
export const electronMainOutDir = path.join(electronDistDir, "main");
export const mainOutDir = electronMainOutDir;
export const gatewayPackageRoot = path.dirname(requireFromHere.resolve("@the-next-ai/ai-gateway/package.json"));
export const gatewayRuntimeInput = path.join(gatewayPackageRoot, "bin", "next-ai-gateway.js");
export const electronGatewayRuntimeOutput = path.join(electronMainOutDir, "next-ai-gateway.js");
export const botGatewaySdkPackageRoot = path.dirname(requireFromHere.resolve("@the-next-ai/bot-gateway-sdk/package.json"));
export const botGatewaySdkEntryInput = path.join(botGatewaySdkPackageRoot, "dist", "index.js");
export const botGatewaySdkRunnerInput = path.join(botGatewaySdkPackageRoot, "bin", "bot-gateway-stdio.mjs");
export const electronBotGatewaySdkRootDir = path.join(electronMainOutDir, "bot-gateway-sdk");
export const electronBotGatewaySdkDistDir = path.join(electronBotGatewaySdkRootDir, "dist");
export const electronBotGatewaySdkBinDir = path.join(electronBotGatewaySdkRootDir, "bin");
export const electronBotGatewaySdkPackageOutput = path.join(electronBotGatewaySdkRootDir, "package.json");
export const electronBotGatewaySdkEntryOutput = path.join(electronBotGatewaySdkDistDir, "index.js");
export const electronBotGatewaySdkRunnerOutput = path.join(electronBotGatewaySdkBinDir, "bot-gateway-stdio.mjs");
export const rendererOutDir = path.join(uiDistDir, "renderer");
export const cliRendererOutDir = path.join(cliDistDir, "renderer");
export const coreRendererOutDir = path.join(coreDistDir, "renderer");
export const electronRendererOutDir = path.join(electronDistDir, "renderer");
export const runtimeRendererOutDirs = [cliRendererOutDir, coreRendererOutDir, electronRendererOutDir];
export const appAssetsDir = path.join(electronDistDir, "assets");
export const rendererAssetsDir = path.join(rendererOutDir, "assets");
export const bundledClaudeRuntimePluginIds = ["claude-design", "claude-ship"];
export const bundledClaudeRuntimePluginsInputDir = path.join(electronRoot, "bundled-plugins");
export const electronBundledRuntimePluginsDir = path.join(electronDistDir, "bundled-plugins");
export const appAssetsInput = path.join(electronRoot, "assets");
export const modelCatalogInput = path.join(coreRoot, "models.json");
export const cliModelCatalogOutput = path.join(cliDistDir, "models.json");
export const coreModelCatalogOutput = path.join(coreDistDir, "models.json");
export const electronModelCatalogOutput = path.join(electronDistDir, "models.json");
export const modelCatalogOutput = electronModelCatalogOutput;
export const rendererRoot = uiSourceRoot;
export const rendererHtmlInput = path.join(rendererRoot, "pages", "home", "index.html");
export const rendererHtmlOutput = path.join(rendererOutDir, "pages", "home", "index.html");
export const browserRendererHtmlInput = path.join(rendererRoot, "pages", "browser", "index.html");
export const browserRendererHtmlOutput = path.join(rendererOutDir, "pages", "browser", "index.html");
export const trayRendererHtmlInput = path.join(rendererRoot, "pages", "tray", "index.html");
export const trayRendererHtmlOutput = path.join(rendererOutDir, "pages", "tray", "index.html");
export const cssInput = path.join(rendererRoot, "styles", "globals.css");
export const cssOutput = path.join(rendererAssetsDir, "main.css");
export const webClientBridgeOutput = path.join(rendererAssetsDir, "web-client-bridge.js");
export const requestLogBodyWorkerOutput = path.join(rendererAssetsDir, "log-body.worker.js");
export const requestLogBodyWorkerInput = path.join(rendererRoot, "pages", "home", "shared", "log-body.worker.ts");
export const electronUndiciProxyAgentInput = path.join(coreSourceRoot, "proxy", "undici-proxy-agent.ts");
export const localAgentAuthProviderHookInput = path.join(coreSourceRoot, "gateway", "core-runtime", "local-agent-auth-provider-hook.ts");
export const upstreamHeaderSanitizerInput = path.join(coreSourceRoot, "gateway", "core-runtime", "upstream-header-sanitizer.ts");
const lightweightMcpBundleNames = ["browser-web-search-proxy-mcp.js", "fusion-vision-mcp.js", "fusion-tool-fallback-mcp.js", "media-tools-proxy-mcp.js"];
const lightweightMcpBundleMaxBytes = 128 * 1024;
const forbiddenLightweightMcpInputs = [
{ prefix: "packages/core/src/config/", reason: "config modules can pull in native storage side effects" },
{ prefix: "packages/core/src/storage/", reason: "native SQLite storage is not allowed in lightweight MCP subprocesses" },
{ prefix: "packages/electron/src/", reason: "Electron runtime modules are not allowed in lightweight MCP subprocesses" },
{ prefix: "packages/ui/src/", reason: "UI modules do not belong in stdio MCP subprocesses" },
{ prefix: "node_modules/better-sqlite3/", reason: "native SQLite is not allowed in lightweight MCP subprocesses" },
{ prefix: "node_modules/electron/", reason: "Electron runtime modules are not allowed in lightweight MCP subprocesses" }
];
const forbiddenLightweightMcpExternalImports = new Set(["better-sqlite3", "electron"]);
const nodeExternals = [
"electron",
"better-sqlite3",
...builtinModules,
...builtinModules.map((moduleName) => `node:${moduleName}`)
];
export function cleanDist() {
rmSync(legacyDistDir, { force: true, recursive: true });
rmSync(cliDistDir, { force: true, recursive: true });
rmSync(coreDistDir, { force: true, recursive: true });
rmSync(electronDistDir, { force: true, recursive: true });
rmSync(uiDistDir, { force: true, recursive: true });
ensureDist();
}
export function ensureDist() {
mkdirSync(cliMainOutDir, { recursive: true });
mkdirSync(coreMainOutDir, { recursive: true });
mkdirSync(electronMainOutDir, { recursive: true });
mkdirSync(electronBotGatewaySdkDistDir, { recursive: true });
mkdirSync(electronBotGatewaySdkBinDir, { recursive: true });
mkdirSync(appAssetsDir, { recursive: true });
mkdirSync(electronBundledRuntimePluginsDir, { recursive: true });
mkdirSync(rendererAssetsDir, { recursive: true });
for (const outputDir of runtimeRendererOutDirs) {
mkdirSync(path.join(outputDir, "assets"), { recursive: true });
}
mkdirSync(path.dirname(rendererHtmlOutput), { recursive: true });
mkdirSync(path.dirname(browserRendererHtmlOutput), { recursive: true });
mkdirSync(path.dirname(trayRendererHtmlOutput), { recursive: true });
}
export function copyAppAssets() {
ensureDist();
if (existsSync(appAssetsInput)) {
cpSync(appAssetsInput, appAssetsDir, { recursive: true });
}
}
export function copyModelCatalog() {
ensureDist();
if (existsSync(modelCatalogInput)) {
cpSync(modelCatalogInput, cliModelCatalogOutput);
cpSync(modelCatalogInput, coreModelCatalogOutput);
cpSync(modelCatalogInput, electronModelCatalogOutput);
}
}
export function copyRendererHtml() {
copyRendererPageHtml(rendererHtmlInput, rendererHtmlOutput, "main.js", {
beforeModuleScriptTags: [' ']
});
}
export function copyTrayRendererHtml() {
copyRendererPageHtml(trayRendererHtmlInput, trayRendererHtmlOutput, "tray.js");
}
export function copyBrowserRendererHtml() {
copyRendererPageHtml(browserRendererHtmlInput, browserRendererHtmlOutput, "browser.js");
}
export function copyBundledClaudeRuntimePlugins() {
ensureDist();
for (const pluginId of bundledClaudeRuntimePluginIds) {
copyBundledClaudeRuntimePlugin(pluginId);
}
}
export function syncUiRendererToRuntimeDists() {
ensureDist();
for (const outputDir of runtimeRendererOutDirs) {
rmSync(outputDir, { force: true, recursive: true });
if (existsSync(rendererOutDir)) {
cpSync(rendererOutDir, outputDir, { recursive: true });
}
}
}
function copyRendererPageHtml(input, output, scriptName, options = {}) {
ensureDist();
const source = readFileSync(input, "utf8");
const styleTag = ' ';
const scriptTag = ` `;
let html = source.includes('')
? source.replace(' ', scriptTag)
: source.replace("