UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

1,408 lines 53.6 kB
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
const require_fastkv = require('./fastkv.cjs');
const require_merge = require('./merge.cjs');
const require_network = require('./network.cjs');
const require_types = require('./types.cjs');
const require_config = require('./config.cjs');
const require_contract = require('./contract.cjs');
const require_integrity = require('./integrity.cjs');
const require_process_registry = require('./process-registry.cjs');
const require_app = require('./app.cjs');
const require_shared_deps = require('./shared-deps.cjs');
const require_run = require('./utils/run.cjs');
const require_theme = require('./utils/theme.cjs');
const require_build = require('./build.cjs');
const require_infra = require('./cli/infra.cjs');
const require_save_config = require('./utils/save-config.cjs');
const require_cli_init = require('./cli/init.cjs');
const require_status = require('./cli/status.cjs');
const require_sync = require('./cli/sync.cjs');
const require_upgrade = require('./cli/upgrade.cjs');
const require_code_artifacts = require('./code-artifacts.cjs');
const require_service_descriptor = require('./service-descriptor.cjs');
const require_planner = require('./infra/planner.cjs');
const require_preflight = require('./infra/preflight.cjs');
const require_near_cli = require('./near-cli.cjs');
const require_publish = require('./publish.cjs');
let node_fs = require("node:fs");
let node_path = require("node:path");
let effect = require("effect");
let node_events = require("node:events");
let node_process = require("node:process");
node_process = require_runtime.__toESM(node_process, 1);
let node_readline_promises = require("node:readline/promises");
let every_plugin = require("every-plugin");
let zod = require("zod");

//#region src/plugin.ts
const pluginEvents = new node_events.EventEmitter();
let pendingSession = null;
let pendingStartSummary = null;
function consumeDevSession() {
	const data = pendingSession;
	const summary = pendingStartSummary;
	pendingSession = null;
	pendingStartSummary = null;
	if (!data) return null;
	return summary ? {
		...data,
		summary
	} : data;
}
async function timePhase(timings, name, fn) {
	pluginEvents.emit("progress", {
		phase: name,
		status: "running"
	});
	const startedAt = Date.now();
	try {
		const result = await fn();
		timings.push({
			name,
			durationMs: Date.now() - startedAt
		});
		pluginEvents.emit("progress", {
			phase: name,
			status: "done",
			durationMs: Date.now() - startedAt
		});
		return result;
	} catch (error) {
		pluginEvents.emit("progress", {
			phase: name,
			status: "error",
			durationMs: Date.now() - startedAt
		});
		throw error;
	}
}
const PUBLISH_FUNCTION_NAMES = ["__fastdata_kv"];
function parseSourceMode(value, defaultValue) {
	if (value === "local" || value === "remote") return value;
	return defaultValue;
}
function buildConfigResult(bosConfig, full = false) {
	const packages = bosConfig?.app && typeof bosConfig.app === "object" ? Object.keys(bosConfig.app) : [];
	const remotes = packages.filter((name) => name !== "host");
	return {
		config: bosConfig ?? null,
		packages,
		remotes,
		full
	};
}
function isValidProxyUrl(url) {
	try {
		const parsed = new URL(url);
		return parsed.protocol === "http:" || parsed.protocol === "https:";
	} catch {
		return false;
	}
}
function resolveProxyUrl(bosConfig) {
	if (!bosConfig) return null;
	const apiConfig = bosConfig.app.api;
	if (!apiConfig) return null;
	if (apiConfig.proxy && isValidProxyUrl(apiConfig.proxy)) return apiConfig.proxy;
	if (apiConfig.production && isValidProxyUrl(apiConfig.production)) return apiConfig.production;
	return null;
}
function sanitizePluginKey(value) {
	return value.replace(/[^A-Za-z0-9/_-]/g, "-").replace(/\/+/g, "/").split("/").filter(Boolean).map((segment) => segment.replace(/[^A-Za-z0-9_-]/g, "-")).join("/").replace(/^\/+|\/+$/g, "");
}
function defaultPluginKey(source) {
	const normalized = source.replace(/^local:/, "").replace(/\/$/, "");
	if (source.startsWith("local:")) return sanitizePluginKey((0, node_path.basename)(normalized)) || "plugin";
	try {
		const url = new URL(source);
		return sanitizePluginKey((0, node_path.basename)(url.pathname) || url.hostname) || "plugin";
	} catch {
		return sanitizePluginKey(source) || "plugin";
	}
}
function pluginLocalPath(configDir, attachment) {
	const ref = require_build.getPluginRef(attachment);
	const source = ref?.development ?? ref?.production;
	if (!source?.startsWith("local:")) return null;
	return (0, node_path.join)(configDir, source.slice(6));
}
function listPluginAttachments(config) {
	return Object.entries(config?.plugins ?? {}).map(([key, attachment]) => {
		const ref = require_build.getPluginRef(attachment);
		return {
			key,
			development: ref?.development,
			production: ref?.production,
			localPath: ref?.development?.startsWith("local:") ? ref.development.slice(6) : void 0,
			source: ref?.development?.startsWith("local:") ? "local" : "remote",
			integrity: ref?.integrity,
			version: ref?.version,
			name: ref?.name
		};
	}).sort((a, b) => a.key.localeCompare(b.key));
}
async function resolveRemoteConfigChain(accountId, gatewayId, visited) {
	const selfRef = `bos://${accountId}/${gatewayId}`;
	if (visited.has(selfRef)) throw new Error(`Circular extends detected: ${selfRef}`);
	const nextVisited = new Set(visited);
	nextVisited.add(selfRef);
	const config = await require_fastkv.fetchBosConfigFromFastKv(selfRef);
	const parentRef = config.extends ? require_merge.resolveExtendsRef(config.extends, "production") : void 0;
	let merged;
	if (!parentRef) merged = config;
	else {
		const { accountId: parentAccountId, gatewayId: parentGatewayId } = require_fastkv.parseBosUrl(parentRef);
		merged = require_merge.mergeBosConfigWithExtends(await resolveRemoteConfigChain(parentAccountId, parentGatewayId, nextVisited), config);
	}
	return require_config.resolveConfigComposableEntries(require_types.BosConfigSchema.parse(merged), node_process.default.cwd(), "production");
}
async function fetchPublishedConfig(accountId, gatewayId) {
	try {
		return await resolveRemoteConfigChain(accountId, gatewayId, /* @__PURE__ */ new Set());
	} catch (error) {
		if (error instanceof Error && error.message.startsWith("No config found")) return null;
		throw error;
	}
}
var plugin_default = (0, every_plugin.createPlugin)({
	variables: zod.z.object({ configPath: zod.z.string().optional() }),
	secrets: zod.z.object({}),
	contract: require_contract.bosContract,
	initialize: (config) => effect.Effect.promise(async () => {
		const configResult = await require_config.loadResolvedConfig({ path: config.variables.configPath });
		return {
			bosConfig: configResult?.config ?? null,
			runtimeConfig: configResult?.runtime ?? null,
			configDir: require_config.getProjectRoot()
		};
	}),
	shutdown: () => effect.Effect.void,
	createRouter: (deps, builder) => ({
		config: builder.config.handler(async ({ input }) => {
			if (input.full) return buildConfigResult(deps.bosConfig, true);
			return buildConfigResult((await require_config.loadLocalConfig({ cwd: deps.configDir }))?.config ?? null, false);
		}),
		pluginAdd: builder.pluginAdd.handler(async ({ input }) => {
			if (!deps.bosConfig) return {
				status: "error",
				key: "",
				error: "No bos.config.json found"
			};
			const isBosRef = input.source.startsWith("bos://");
			const isLocal = input.source.startsWith("local:");
			const key = sanitizePluginKey(input.as ?? (isBosRef ? input.source.split("/").pop() ?? "plugin" : defaultPluginKey(input.source)));
			const existing = deps.bosConfig.plugins?.[key];
			const existingEntry = existing && typeof existing === "object" ? existing : {};
			const nextPlugins = { ...deps.bosConfig.plugins ?? {} };
			if (isBosRef) nextPlugins[key] = {
				...existingEntry,
				extends: input.source
			};
			else if (isLocal) nextPlugins[key] = {
				...existingEntry,
				development: input.source,
				...existingEntry.extends ? {} : {}
			};
			else nextPlugins[key] = {
				...existingEntry,
				production: input.production ?? input.source
			};
			deps.bosConfig = {
				...deps.bosConfig,
				plugins: nextPlugins
			};
			await require_save_config.saveBosConfig(deps.configDir, deps.bosConfig);
			await require_code_artifacts.generateCodeArtifacts(deps.configDir, deps.bosConfig);
			const stored = deps.bosConfig.plugins?.[key];
			const storedObj = stored && typeof stored === "object" ? stored : {};
			return {
				status: "added",
				key,
				development: storedObj.development,
				production: storedObj.production,
				integrity: storedObj.integrity,
				version: storedObj.version
			};
		}),
		pluginRemove: builder.pluginRemove.handler(async ({ input }) => {
			if (!deps.bosConfig) return {
				status: "error",
				key: input.key,
				error: "No bos.config.json found"
			};
			if (!deps.bosConfig.plugins?.[input.key]) return {
				status: "error",
				key: input.key,
				error: `Plugin '${input.key}' is not configured`
			};
			const nextPlugins = { ...deps.bosConfig.plugins ?? {} };
			delete nextPlugins[input.key];
			deps.bosConfig = {
				...deps.bosConfig,
				plugins: Object.keys(nextPlugins).length > 0 ? nextPlugins : void 0
			};
			await require_save_config.saveBosConfig(deps.configDir, deps.bosConfig);
			await require_code_artifacts.generateCodeArtifacts(deps.configDir, deps.bosConfig);
			return {
				status: "removed",
				key: input.key
			};
		}),
		pluginList: builder.pluginList.handler(async () => {
			return {
				status: "listed",
				plugins: listPluginAttachments(deps.bosConfig)
			};
		}),
		pluginPublish: builder.pluginPublish.handler(async ({ input }) => {
			if (!deps.bosConfig) return {
				status: "error",
				key: input.key,
				error: "No bos.config.json found"
			};
			const attachment = deps.bosConfig.plugins?.[input.key];
			if (!attachment) return {
				status: "error",
				key: input.key,
				error: `Plugin '${input.key}' is not configured`
			};
			const attachmentRef = require_build.getPluginRef(attachment);
			const localPath = pluginLocalPath(deps.configDir, attachment);
			if (!localPath) return {
				status: "error",
				key: input.key,
				error: `Plugin '${input.key}' does not have a local development path`
			};
			const pkgPath = (0, node_path.join)(localPath, "package.json");
			if (!await require_build.fileExists(pkgPath)) return {
				status: "error",
				key: input.key,
				error: `Missing package.json at ${localPath}`
			};
			const pkgJson = await require_build.readJsonFile(pkgPath);
			const script = pkgJson.scripts?.deploy ? "deploy" : "build";
			const { stdout, stderr, exitCode } = await require_run.run("bun", ["run", script], {
				cwd: localPath,
				capture: true
			});
			if (exitCode !== 0) {
				if (stdout.trim()) node_process.default.stdout.write(stdout);
				if (stderr.trim()) node_process.default.stderr.write(stderr);
				return {
					status: "error",
					key: input.key,
					error: `Publish failed with exit code ${exitCode}`
				};
			}
			if (stdout.trim()) node_process.default.stdout.write(stdout);
			if (stderr.trim()) node_process.default.stderr.write(stderr);
			const output = `${stdout}\n${stderr}`;
			const deployEntry = require_integrity.parseDeployLines(output).find((e) => e.urlField === `plugins.${input.key}.production`);
			let publishedUrl;
			let integrity;
			if (deployEntry) {
				publishedUrl = deployEntry.url;
				integrity = deployEntry.integrity;
			} else {
				publishedUrl = require_publish.extractPublishedUrl(output) ?? void 0;
				integrity = publishedUrl ? await require_integrity.computeSriHashForUrl(publishedUrl) ?? void 0 : void 0;
			}
			let manifest = null;
			if (publishedUrl) manifest = await require_fastkv.fetchRemotePluginManifest(publishedUrl);
			else if (attachmentRef?.production) {
				manifest = await require_fastkv.fetchRemotePluginManifest(attachmentRef.production);
				if (manifest) publishedUrl = attachmentRef.production;
			}
			const version = manifest?.plugin.version ?? pkgJson.version;
			if (publishedUrl) {
				const rootConfigPath = (0, node_path.join)(deps.configDir, "bos.config.json");
				try {
					const rootConfig = JSON.parse((0, node_fs.readFileSync)(rootConfigPath, "utf-8"));
					if (!rootConfig.plugins || typeof rootConfig.plugins !== "object") rootConfig.plugins = {};
					const plugins = rootConfig.plugins;
					if (!plugins[input.key] || typeof plugins[input.key] !== "object") plugins[input.key] = {};
					const entry = plugins[input.key];
					entry.production = publishedUrl;
					if (integrity) entry.integrity = integrity;
					else delete entry.integrity;
					(0, node_fs.writeFileSync)(rootConfigPath, `${JSON.stringify(rootConfig, null, 2)}\n`);
					console.log(`   ✅ Updated bos.config.json: plugins.${input.key}.production`);
				} catch (err) {
					console.error(`   ❌ Failed to update bos.config.json:`, err instanceof Error ? err.message : err);
				}
				await require_code_artifacts.generateCodeArtifacts(deps.configDir, deps.bosConfig);
			}
			return {
				status: "published",
				key: input.key,
				path: localPath,
				script,
				production: publishedUrl ?? attachmentRef?.production,
				integrity: integrity ?? void 0,
				version: version ?? void 0
			};
		}),
		dev: builder.dev.handler(async ({ input }) => {
			const devTimings = [];
			require_infra.ensureEnvFile(deps.configDir);
			require_infra.loadProjectEnv(deps.configDir);
			const localPackages = require_app.detectLocalPackages(deps.bosConfig ?? void 0, deps.runtimeConfig ?? void 0);
			const hostSource = localPackages.includes("host") ? parseSourceMode(input.host, "local") : "remote";
			const uiSource = localPackages.includes("ui") ? parseSourceMode(input.ui, "local") : "remote";
			const apiSource = localPackages.includes("api") ? parseSourceMode(input.api, "local") : "remote";
			const authSource = localPackages.includes("auth") ? parseSourceMode(input.auth, "local") : "remote";
			const ssr = input.ssr ?? false;
			const proxy = input.proxy ?? false;
			const sharedSync = await timePhase(devTimings, "shared deps", () => require_shared_deps.syncResolvedSharedDeps({
				configDir: deps.configDir,
				hostMode: hostSource,
				bosConfig: deps.bosConfig ?? void 0,
				extendsChain: []
			}));
			let configMayHaveChanged = false;
			if (sharedSync.catalogChanged) {
				await timePhase(devTimings, "install", () => require_run.run("bun", ["install"], { cwd: deps.configDir }));
				configMayHaveChanged = true;
			}
			const shouldBuildPlugin = apiSource === "local" && !proxy || localPackages.some((pkg) => pkg.startsWith("plugin:"));
			await timePhase(devTimings, "build", async () => {
				const buildTasks = [require_build.buildEverythingDevQuietly(deps.configDir)];
				if (shouldBuildPlugin) buildTasks.push(require_build.buildEveryPluginQuietly(deps.configDir));
				await Promise.all(buildTasks);
			});
			let devExtendsChain;
			if (configMayHaveChanged || input.remotePlugins !== void 0) {
				const refreshed = await timePhase(devTimings, "resolve config", () => require_config.loadResolvedConfig({
					cwd: deps.configDir,
					remotePlugins: input.remotePlugins
				}));
				deps.bosConfig = refreshed?.config ?? deps.bosConfig;
				deps.runtimeConfig = refreshed?.runtime ?? deps.runtimeConfig;
				devExtendsChain = refreshed?.source.extended;
			}
			if (!deps.bosConfig) return {
				status: "error",
				description: "No bos.config.json found",
				processes: [],
				timings: devTimings
			};
			if (proxy && !resolveProxyUrl(deps.bosConfig)) return {
				status: "error",
				description: "No valid proxy URL configured in bos.config.json",
				processes: [],
				timings: devTimings
			};
			require_config.suppressWarnings();
			const developmentRuntime = await require_app.buildRuntimeConfig(deps.bosConfig, {
				uiSource,
				apiSource,
				authSource,
				hostSource,
				env: "development",
				plugins: deps.runtimeConfig?.plugins
			});
			require_config.drainConfigWarnings();
			require_config.resumeWarnings();
			const plan = await timePhase(devTimings, "ports", () => effect.Effect.runPromise(require_planner.planInfra({
				configDir: deps.configDir,
				bosConfig: developmentRuntime,
				cli: {
					port: input.port,
					apiPort: input.apiPort,
					authPort: input.authPort,
					uiPort: input.uiPort,
					pluginPortStart: input.pluginPortStart,
					ssr,
					proxy,
					hostSource,
					uiSource,
					apiSource,
					authSource,
					interactive: input.interactive
				}
			}).pipe(effect.Effect.provide(require_app.PortAllocatorLive))));
			const mergedEnv = { ...plan.envGenerated };
			for (const [k, v] of Object.entries(node_process.default.env)) if (v != null && !(k in plan.envGenerated)) mergedEnv[k] = v;
			const preflightFailures = await effect.Effect.runPromise(require_preflight.preflightLocalInfra(plan.envGenerated, mergedEnv));
			if (preflightFailures.length > 0) return {
				status: "error",
				description: `Infra preflight failed: ${preflightFailures.map((f) => f.error).join("; ")}`,
				processes: [],
				timings: devTimings
			};
			const services = require_service_descriptor.buildServiceDescriptorMapFromPlan(plan, {
				ssr,
				proxy
			});
			require_infra.writeGeneratedInfra(deps.configDir, plan.runtimeConfig);
			require_infra.ensureEnvFile(deps.configDir);
			require_infra.loadProjectEnv(deps.configDir);
			const packages = [...plan.serviceDescriptors.keys()];
			if (node_process.default.env.DEBUG === "true" || node_process.default.env.DEBUG === "1") console.error("[DEBUG dev] services keys:", packages.join(", "));
			if (services.get("api")?.proxy) {
				const proxyUrl = resolveProxyUrl(deps.bosConfig);
				if (proxyUrl) plan.orchestrator.env.API_PROXY = proxyUrl;
			}
			pendingSession = {
				orchestrator: plan.orchestrator,
				services,
				runtimeConfig: plan.runtimeConfig
			};
			await timePhase(devTimings, "generate artifacts", () => require_code_artifacts.generateCodeArtifacts(deps.configDir, deps.bosConfig, {
				env: "development",
				extendsChain: devExtendsChain,
				runtimeConfig: plan.runtimeConfig
			}));
			return {
				status: "started",
				description: require_service_descriptor.buildDescription(services) || plan.description,
				processes: packages,
				timings: devTimings
			};
		}),
		start: builder.start.handler(async ({ input }) => {
			require_infra.ensureEnvFile(deps.configDir);
			require_infra.loadProjectEnv(deps.configDir);
			pluginEvents.emit("progress", {
				phase: "config",
				status: "running"
			});
			const bosEnv = input.env ?? (node_process.default.env.BOS_ENV === "staging" ? "staging" : "production");
			const account = input.account ?? node_process.default.env.BOS_ACCOUNT;
			const domain = input.domain ?? node_process.default.env.BOS_GATEWAY;
			let config = null;
			let remoteConfig = null;
			if (account && domain) try {
				remoteConfig = await fetchPublishedConfig(account, domain);
				if (remoteConfig) config = remoteConfig;
				else return {
					status: "error",
					url: "",
					error: `No config found at bos://${account}/${domain}. Verify the account and gateway are correct and the config has been published.\nExpected URL: ${require_fastkv.buildRegistryConfigUrl(account, domain)}`
				};
			} catch (error) {
				return {
					status: "error",
					url: "",
					error: `Failed to fetch config for bos://${account}/${domain}: ${error instanceof Error ? error.message : "Unknown error"}\nExpected URL: ${require_fastkv.buildRegistryConfigUrl(account, domain)}`
				};
			}
			else config = deps.bosConfig;
			if (!config) return {
				status: "error",
				url: "",
				error: "No configuration found. Provide --account and --gateway flags, or create a local bos.config.json."
			};
			if (account) config = {
				...config,
				account
			};
			if (domain) config = {
				...config,
				domain
			};
			const port = input.port ?? require_config.getHostDevelopmentPort(config.app.host.development);
			const isStaging = bosEnv === "staging";
			const runtimePlugins = await require_config.buildRuntimePluginsForConfig(config, deps.configDir, "production");
			require_config.suppressWarnings();
			const runtimeConfig = await require_app.buildRuntimeConfig(config, {
				uiSource: "remote",
				apiSource: "remote",
				authSource: "remote",
				hostSource: "remote",
				env: "production",
				plugins: runtimePlugins
			});
			require_config.drainConfigWarnings();
			require_config.resumeWarnings();
			if (isStaging && config.staging?.domain) runtimeConfig.domain = config.staging.domain;
			if (isStaging) runtimeConfig.env = "staging";
			require_infra.syncGeneratedInfra(deps.configDir, runtimeConfig);
			require_infra.ensureEnvFile(deps.configDir);
			require_infra.loadProjectEnv(deps.configDir);
			pluginEvents.emit("progress", {
				phase: "generate artifacts",
				status: "running"
			});
			await require_code_artifacts.generateCodeArtifacts(deps.configDir, config, {
				env: "production",
				runtimeConfig
			});
			pluginEvents.emit("progress", {
				phase: "generate artifacts",
				status: "done"
			});
			const productionEnv = {};
			const warnings = [];
			if (!node_process.default.env.CORS_ORIGIN && config.domain) {
				const defaultOrigin = `https://${isStaging ? config.staging?.domain ?? config.domain : config.domain}`;
				productionEnv.CORS_ORIGIN = defaultOrigin;
				warnings.push(`CORS_ORIGIN defaulting to ${defaultOrigin}`);
			}
			const requiredSecrets = /* @__PURE__ */ new Set();
			const missingSecrets = [];
			if (runtimeConfig.host.secrets) for (const s of runtimeConfig.host.secrets) requiredSecrets.add(s);
			if (runtimeConfig.auth?.secrets) for (const s of runtimeConfig.auth.secrets) requiredSecrets.add(s);
			if (runtimeConfig.api?.secrets) for (const s of runtimeConfig.api.secrets) requiredSecrets.add(s);
			for (const plugin of Object.values(runtimeConfig.plugins ?? {})) if (plugin.secrets) for (const s of plugin.secrets) requiredSecrets.add(s);
			for (const secret of requiredSecrets) {
				const value = node_process.default.env[secret];
				if (!value || value.length === 0) missingSecrets.push(secret);
			}
			if (missingSecrets.length > 0) warnings.push(`Missing ${missingSecrets.length} secret(s): ${missingSecrets.join(", ")}`);
			const stagingEnvVars = isStaging ? { BOS_GATEWAY: config.staging?.domain ?? config.domain ?? "" } : {};
			const plan = await effect.Effect.runPromise(require_planner.planInfra({
				configDir: deps.configDir,
				bosConfig: runtimeConfig,
				cli: {
					port: input.port,
					ssr: false,
					proxy: false,
					hostSource: "remote",
					uiSource: "remote",
					apiSource: "remote",
					authSource: "remote",
					interactive: input.interactive
				}
			}).pipe(effect.Effect.provide(require_app.PortAllocatorLive)));
			const services = require_service_descriptor.buildServiceDescriptorMap(plan.runtimeConfig);
			const summary = {
				configSource: remoteConfig ? `bos://${account}/${domain}` : require_config.findConfigPath() ?? "bos.config.json",
				configSourceHttp: remoteConfig && account && domain ? require_fastkv.buildRegistryConfigUrl(account, domain) : void 0,
				account: config.account,
				domain: config.domain ?? void 0,
				modules: {
					host: plan.runtimeConfig.host.remoteUrl ?? plan.runtimeConfig.host.url ?? "local",
					ui: plan.runtimeConfig.ui.url ?? "local",
					api: plan.runtimeConfig.api.url ?? "local",
					auth: plan.runtimeConfig.auth?.url ?? void 0
				},
				warnings
			};
			pendingSession = {
				orchestrator: {
					packages: ["host"],
					env: {
						NODE_ENV: "production",
						...productionEnv,
						...stagingEnvVars,
						...plan.launch.env
					},
					description: `${isStaging ? "Staging" : "Production"} Mode (${config.account})`,
					port: plan.resolvedPorts.host ?? port,
					interactive: input.interactive,
					noLogs: true
				},
				services,
				runtimeConfig: plan.runtimeConfig
			};
			pendingStartSummary = summary;
			pluginEvents.emit("progress", {
				phase: "config",
				status: "done"
			});
			return {
				status: "running",
				url: plan.launch.hostUrl ?? `http://localhost:${plan.resolvedPorts.host ?? port}`
			};
		}),
		build: builder.build.handler(async ({ input }) => {
			if (!deps.bosConfig) return {
				status: "error",
				built: [],
				skipped: []
			};
			const buildEnv = input.deploy ? "production" : "development";
			const targets = require_build.selectWorkspaceTargets(input.packages, deps.bosConfig);
			if (targets.length === 0) return {
				status: "error",
				built: [],
				skipped: []
			};
			require_config.suppressWarnings();
			const runtimeConfig = await require_app.buildRuntimeConfig(deps.bosConfig, {
				uiSource: deps.bosConfig.app.ui?.development ? "local" : "remote",
				apiSource: deps.bosConfig.app.api?.development ? "local" : "remote",
				authSource: deps.bosConfig.app.auth?.development ? "local" : "remote",
				hostSource: deps.bosConfig.app.host?.development ? "local" : "remote",
				env: buildEnv,
				plugins: deps.runtimeConfig?.plugins
			});
			require_config.drainConfigWarnings();
			require_config.resumeWarnings();
			await require_code_artifacts.generateCodeArtifacts(deps.configDir, deps.bosConfig, {
				env: buildEnv,
				runtimeConfig
			});
			const { built, skipped } = await require_build.buildWorkspaceTargets({
				configDir: deps.configDir,
				bosConfig: deps.bosConfig,
				runtimeConfig,
				targets,
				deploy: input.deploy
			});
			if (built.length === 0) return {
				status: "error",
				built: [],
				skipped
			};
			return {
				status: "success",
				built,
				skipped,
				deployed: input.deploy
			};
		}),
		publish: builder.publish.handler(async ({ input }) => {
			if (!deps.bosConfig) return {
				status: "error",
				registryUrl: "",
				error: "No bos.config.json found"
			};
			const result = await require_publish.publishToFastKv({
				bosConfig: deps.bosConfig,
				runtimeConfig: deps.runtimeConfig,
				configDir: deps.configDir,
				env: input.env,
				build: input.deploy,
				dryRun: input.dryRun,
				verbose: input.verbose,
				packages: input.packages,
				network: input.network,
				privateKey: input.privateKey
			});
			if (result.publishConfig) {
				const refreshed = await require_config.loadResolvedConfig({ cwd: deps.configDir });
				if (refreshed?.config) {
					deps.bosConfig = refreshed.config;
					deps.runtimeConfig = refreshed.runtime;
				}
			}
			return {
				status: result.status,
				registryUrl: result.registryUrl,
				txHash: result.txHash,
				error: result.error,
				built: result.built,
				skipped: result.skipped,
				deployResults: result.deployResults
			};
		}),
		deploy: builder.deploy.handler(async ({ input }) => {
			if (!deps.bosConfig) return {
				status: "error",
				registryUrl: "",
				redeployed: false,
				error: "No bos.config.json found"
			};
			const result = await require_publish.publishToFastKv({
				bosConfig: deps.bosConfig,
				runtimeConfig: deps.runtimeConfig,
				configDir: deps.configDir,
				env: input.env,
				build: input.build,
				dryRun: input.dryRun,
				verbose: input.verbose,
				packages: input.packages,
				network: input.network,
				privateKey: input.privateKey
			});
			if (result.status === "error") return {
				status: "error",
				registryUrl: result.registryUrl,
				txHash: result.txHash,
				built: result.built,
				skipped: result.skipped,
				redeployed: false,
				error: result.error,
				deployResults: result.deployResults
			};
			if (result.status === "dry-run") return {
				status: "dry-run",
				registryUrl: result.registryUrl,
				built: result.built,
				skipped: result.skipped,
				redeployed: false
			};
			if (result.publishConfig) {
				const refreshed = await require_config.loadResolvedConfig({ cwd: deps.configDir });
				if (refreshed?.config) {
					deps.bosConfig = refreshed.config;
					deps.runtimeConfig = refreshed.runtime;
				}
			}
			let redeployed = false;
			let service;
			if (node_process.default.env.RAILWAY_TOKEN) {
				const railwayService = input.service ?? deps.bosConfig.ci?.railway?.service;
				if (!railwayService) {
					console.log();
					console.log(require_theme.colors.yellow("  Railway redeploy skipped: ci.railway.service is not configured in bos.config.json"));
					return {
						status: "published",
						registryUrl: result.registryUrl,
						txHash: result.txHash,
						built: result.built,
						skipped: result.skipped,
						redeployed: false,
						deployResults: result.deployResults,
						error: "Config published but Railway redeploy failed: ci.railway.service is not configured in bos.config.json"
					};
				}
				service = railwayService;
				console.log();
				console.log(`  Redeploying Railway service ${require_theme.colors.cyan(railwayService)}...`);
				try {
					const railResult = await require_run.run("railway", [
						"redeploy",
						"--service",
						railwayService,
						"--yes"
					], { capture: true });
					if (railResult?.stdout) {
						for (const line of railResult.stdout.split("\n")) if (line.trim()) console.log(`  ${require_theme.colors.dim(line.trim())}`);
					}
					redeployed = true;
					console.log(require_theme.colors.green(`  Railway redeploy complete`));
				} catch (error) {
					const message = error instanceof Error ? error.message : String(error);
					const railError = message.includes("not found") || message.includes("ENOENT") ? "Railway CLI not found. Install it: npm i -g @railway/cli" : `Railway redeploy failed: ${message}`;
					console.log(require_theme.colors.yellow(`  ${railError}`));
					return {
						status: "published",
						registryUrl: result.registryUrl,
						txHash: result.txHash,
						built: result.built,
						skipped: result.skipped,
						redeployed: false,
						service,
						deployResults: result.deployResults,
						error: `Config published but ${railError}`
					};
				}
			} else {
				console.log();
				console.log(require_theme.colors.yellow("  Railway redeploy skipped (RAILWAY_TOKEN not set)"));
			}
			return {
				status: "deployed",
				registryUrl: result.registryUrl,
				txHash: result.txHash,
				built: result.built,
				skipped: result.skipped,
				redeployed,
				service,
				deployResults: result.deployResults
			};
		}),
		keyPublish: builder.keyPublish.handler(async ({ input }) => {
			if (!deps.bosConfig) return {
				status: "error",
				account: "",
				network: "mainnet",
				contract: "",
				allowance: input.allowance,
				functionNames: PUBLISH_FUNCTION_NAMES,
				error: "No bos.config.json found"
			};
			const account = deps.bosConfig.account;
			const network = require_network.getNetworkIdForAccount(account);
			const contract = require_fastkv.getRegistryNamespaceForAccount(account);
			try {
				await effect.Effect.runPromise(require_near_cli.ensureNearCli);
				const oldKeys = await require_near_cli.listPublishKeys({
					account,
					contract,
					network
				});
				const keyPair = await require_near_cli.addFunctionCallAccessKey({
					account,
					contract,
					allowance: input.allowance,
					functionNames: PUBLISH_FUNCTION_NAMES,
					network
				});
				if (oldKeys.length > 0) {
					console.log();
					console.log(`  Found ${oldKeys.length} existing publish key${oldKeys.length > 1 ? "s" : ""}:`);
					for (const k of oldKeys) console.log(`    ${require_theme.colors.dim(k)}`);
					const rl = (0, node_readline_promises.createInterface)({
						input: node_process.default.stdin,
						output: node_process.default.stdout
					});
					const answer = await rl.question("  Remove old key(s)? [Y/n] ");
					rl.close();
					if (answer.toLowerCase() !== "n" && answer.toLowerCase() !== "no") try {
						await require_near_cli.deleteAccessKeys(account, oldKeys, network);
						console.log(`  ${require_theme.colors.green("✓")} Removed ${oldKeys.length} old key${oldKeys.length > 1 ? "s" : ""}`);
					} catch {
						console.log(`  ${require_theme.colors.yellow("⚠")} Failed to remove old key${oldKeys.length > 1 ? "s" : ""} (new key still active)`);
					}
					else console.log(`  ${require_theme.colors.dim("Old key(s) retained.")}`);
				}
				return {
					status: "published",
					account,
					network,
					contract,
					allowance: input.allowance,
					functionNames: PUBLISH_FUNCTION_NAMES,
					publicKey: keyPair.publicKey,
					privateKey: keyPair.privateKey
				};
			} catch (error) {
				return {
					status: "error",
					account,
					network,
					contract,
					allowance: input.allowance,
					functionNames: PUBLISH_FUNCTION_NAMES,
					error: error instanceof Error ? error.message : "Unknown error"
				};
			}
		}),
		init: builder.init.handler(async ({ input }) => {
			try {
				const timings = [];
				let extendsAccount = "";
				let extendsGateway = "";
				let directory = input.directory;
				const account = input.account;
				const domain = input.domain;
				let overrides = input.overrides;
				let plugins = input.plugins;
				if (input.extends) {
					const match = (input.extends.startsWith("bos://") ? input.extends : `bos://${input.extends}`).match(/^bos:\/\/([^/]+)\/(.+)$/);
					if (match) {
						extendsAccount = match[1];
						extendsGateway = match[2];
					}
				}
				extendsAccount = extendsAccount || "dev.everything.near";
				extendsGateway = extendsGateway || "everything.dev";
				let parentPluginKeys = [];
				let parentConfig = null;
				try {
					parentConfig = await timePhase(timings, "parent config", () => require_cli_init.fetchParentConfig(extendsAccount, extendsGateway));
					if (parentConfig?.plugins && typeof parentConfig.plugins === "object") parentPluginKeys = Object.keys(parentConfig.plugins);
				} catch (e) {
					console.warn(`[init] Failed to fetch parent config from ${extendsAccount}/${extendsGateway}: ${e instanceof Error ? e.message : e}`);
				}
				overrides = overrides?.length ? overrides : ["ui", "api"];
				if (overrides.includes("plugins") && plugins === void 0) plugins = parentPluginKeys;
				plugins = plugins ?? [];
				const pluginDirMap = {};
				if (parentConfig?.plugins) for (const plugin of plugins) {
					const entry = parentConfig.plugins?.[plugin];
					if (entry && typeof entry === "object") {
						const dev = entry.development;
						if (typeof dev === "string") {
							const match = dev.match(/^local:plugins\/(.+)$/);
							if (match?.[1] && match[1] !== plugin) pluginDirMap[plugin] = match[1];
						}
					}
				}
				directory = directory || domain || extendsGateway;
				const targetDir = (0, node_path.resolve)(directory);
				const extendsRef = `bos://${extendsAccount}/${extendsGateway}`;
				const repository = await require_cli_init.detectGitRemoteUrl(node_process.default.cwd()).catch(() => void 0) ?? parentConfig?.repository;
				if (!parentConfig) try {
					parentConfig = await timePhase(timings, "parent config", () => require_cli_init.fetchParentConfig(extendsAccount, extendsGateway));
				} catch {
					return {
						status: "error",
						directory,
						extendsRef,
						account,
						domain,
						extends: extendsRef,
						plugins,
						overrides,
						filesCopied: 0,
						timings,
						error: `No config found at ${extendsRef} — are you sure this is the right parent?`
					};
				}
				const { sourceDir, parentConfig: resolvedParentConfig, cleanup } = await timePhase(timings, "template source", () => require_cli_init.resolveSourceDir({
					extendsAccount,
					extendsGateway,
					source: input.source
				}));
				parentConfig = resolvedParentConfig;
				const isMinimalScaffold = sourceDir === "";
				try {
					let filesCopied;
					if (isMinimalScaffold) {
						filesCopied = await timePhase(timings, "scaffold project", () => require_cli_init.scaffoldMinimalProject(targetDir, parentConfig, {
							extendsAccount,
							extendsGateway,
							account: account || extendsAccount,
							domain,
							plugins,
							overrides,
							repository,
							title: parentConfig?.title,
							description: parentConfig?.description
						}));
						await timePhase(timings, "personalize config", () => require_cli_init.personalizeConfig(targetDir, {
							extendsAccount,
							extendsGateway,
							account: account || extendsAccount,
							domain: domain || extendsGateway,
							plugins,
							overrides,
							mode: "init",
							repository,
							title: parentConfig?.title,
							description: parentConfig?.description,
							testnet: parentConfig?.testnet,
							staging: parentConfig?.staging
						}));
					} else {
						const patterns = require_cli_init.buildInitPatterns(overrides, plugins, pluginDirMap);
						const routeExclusions = overrides.includes("ui") ? require_cli_init.buildPluginRouteExclusions(parentConfig, plugins) : [];
						filesCopied = await timePhase(timings, "copy files", () => require_cli_init.copyFilteredFiles(sourceDir, targetDir, patterns, {
							overrides,
							plugins,
							ignore: routeExclusions
						}));
						await timePhase(timings, "personalize config", () => require_cli_init.personalizeConfig(targetDir, {
							extendsAccount,
							extendsGateway,
							account: account || extendsAccount,
							domain: domain || extendsGateway,
							plugins,
							overrides,
							workspaceOpts: { sourceDir },
							repository,
							title: parentConfig?.title,
							description: parentConfig?.description,
							testnet: parentConfig?.testnet,
							staging: parentConfig?.staging
						}));
						await timePhase(timings, "write snapshot", () => require_cli_init.writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, {
							overrides,
							plugins,
							ignore: routeExclusions
						}));
						await timePhase(timings, "personalize agents", () => require_cli_init.personalizeAgentsMd(targetDir, {
							overrides,
							plugins
						}));
					}
					await timePhase(timings, "sync shared deps", () => require_shared_deps.syncResolvedSharedDeps({
						configDir: targetDir,
						hostMode: "local"
					}));
					const lockfilePath = (0, node_path.join)(targetDir, "bun.lock");
					require_cli_init.stripOrphanedWorkspacesFromLockfile(lockfilePath, computeAllowedWorkspaces(overrides, plugins));
					require_cli_init.removeInitLockfile(lockfilePath);
					const initConfig = await timePhase(timings, "resolve config", () => require_config.loadResolvedConfig({ cwd: targetDir }));
					if (initConfig?.runtime) await timePhase(timings, "generate env/docker", async () => {
						require_infra.writeGeneratedInfra(targetDir, initConfig.runtime);
					});
					await timePhase(timings, "create env file", async () => {
						require_infra.ensureEnvFile(targetDir);
					});
					if (!input.noInstall) {
						await timePhase(timings, "install dependencies", () => require_cli_init.runBunInstall(targetDir));
						await timePhase(timings, "generate types", () => require_cli_init.runTypesGen(targetDir));
						await timePhase(timings, "generate migrations", () => require_cli_init.generateDatabaseMigrations(targetDir));
					}
					if (input.noInstall && initConfig?.config) await timePhase(timings, "generate code artifacts", () => require_code_artifacts.generateCodeArtifacts(targetDir, initConfig.config));
					return {
						status: "initialized",
						directory,
						extendsRef,
						account,
						domain,
						extends: extendsRef,
						plugins,
						overrides,
						filesCopied,
						timings,
						targetDir
					};
				} finally {
					await cleanup();
				}
			} catch (error) {
				const extendsRef = input.extends ? input.extends.startsWith("bos://") ? input.extends : `bos://${input.extends}` : "bos://dev.everything.near/everything.dev";
				return {
					status: "error",
					directory: input.directory ?? "",
					extendsRef,
					account: input.account,
					domain: input.domain,
					extends: extendsRef,
					plugins: input.plugins ?? [],
					overrides: input.overrides,
					filesCopied: 0,
					timings: [],
					error: error instanceof Error ? error.message : "Unknown error"
				};
			}
		}),
		sync: builder.sync.handler(async ({ input }) => {
			try {
				const configPath = require_config.findConfigPath();
				if (!configPath) return {
					status: "error",
					updated: [],
					skipped: [],
					added: [],
					error: "No bos.config.json found in current directory"
				};
				const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath));
				const result = await require_sync.syncTemplate(projectDir, input);
				if (result.status === "synced" || result.status === "dry-run") {
					const syncedConfig = await require_config.loadResolvedConfig({ cwd: projectDir });
					if (syncedConfig?.config) await require_code_artifacts.generateCodeArtifacts(projectDir, syncedConfig.config);
				}
				return result;
			} catch (error) {
				return {
					status: "error",
					updated: [],
					skipped: [],
					added: [],
					error: error instanceof Error ? error.message : "Unknown error"
				};
			}
		}),
		upgrade: builder.upgrade.handler(async ({ input }) => {
			try {
				const configPath = require_config.findConfigPath();
				if (!configPath) return {
					status: "error",
					packages: [],
					error: "No bos.config.json found in current directory"
				};
				return await require_upgrade.upgradeTemplate((0, node_path.resolve)((0, node_path.dirname)(configPath)), input);
			} catch (error) {
				return {
					status: "error",
					packages: [],
					error: error instanceof Error ? error.message : "Unknown error"
				};
			}
		}),
		typesGen: builder.typesGen.handler(async ({ input }) => {
			try {
				const configPath = require_config.findConfigPath();
				if (!configPath) return {
					status: "error",
					generated: [],
					fetched: [],
					skipped: [],
					failed: [],
					error: "No bos.config.json found in current directory"
				};
				const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath));
				const refreshed = await require_config.loadResolvedConfig({
					cwd: projectDir,
					env: input.env ?? (node_process.default.env.NODE_ENV === "production" ? "production" : "development"),
					remotePlugins: input.remotePlugins
				});
				if (!refreshed) return {
					status: "error",
					generated: [],
					fetched: [],
					skipped: [],
					failed: [],
					error: "Failed to load bos.config.json"
				};
				if (input.dryRun) {
					const pluginEntries = Object.entries(refreshed.runtime.plugins ?? {});
					const fetched = [];
					const skipped = [];
					const hasLocalApiWorkspace = (0, node_fs.existsSync)((0, node_path.join)(projectDir, "api", "src"));
					if (refreshed.runtime.api.source !== "local") fetched.push(`api remote (${refreshed.runtime.api.url})`);
					else {
						const path = refreshed.runtime.api.localPath ? ` (${(0, node_path.relative)(projectDir, refreshed.runtime.api.localPath)})` : "";
						skipped.push(`api local${path}`);
					}
					if (refreshed.runtime.auth) if (refreshed.runtime.auth.source !== "local") fetched.push(`auth remote (${refreshed.runtime.auth.url})`);
					else {
						const path = refreshed.runtime.auth.localPath ? ` (${(0, node_path.relative)(projectDir, refreshed.runtime.auth.localPath)})` : "";
						skipped.push(`auth local${path}`);
					}
					for (const [key, plugin] of pluginEntries) if (plugin.url && plugin.source !== "local") fetched.push(`${key} remote (${plugin.url})`);
					else if (plugin.localPath) skipped.push(`${key} local (${(0, node_path.relative)(projectDir, plugin.localPath)})`);
					else skipped.push(`${key} no URL resolved`);
					const generated = ["ui/src/lib/api-types.gen.ts", "ui/src/lib/auth-types.gen.ts"];
					if (hasLocalApiWorkspace) generated.push("api/src/lib/plugins-types.gen.ts", "api/src/lib/auth-types.gen.ts");
					if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, "host", "src"))) generated.push("host/src/lib/auth-types.gen.ts");
					for (const [key, _plugin] of pluginEntries) if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, "plugins", key, "src", "lib", "plugins-client.gen.ts"))) generated.push(`plugins/${key}/src/lib/plugins-client.gen.ts`);
					return {
						status: "success",
						generated,
						fetched,
						skipped,
						failed: []
					};
				}
				const artifacts = await require_code_artifacts.generateCodeArtifacts(projectDir, refreshed.config, { runtimeConfig: refreshed.runtime });
				const hasLocalApiWorkspace = (0, node_fs.existsSync)((0, node_path.join)(projectDir, "api", "src"));
				const generated = ["ui/src/lib/api-types.gen.ts"];
				if (hasLocalApiWorkspace) generated.push("api/src/lib/plugins-types.gen.ts", "api/src/lib/auth-types.gen.ts");
				if (refreshed.runtime.auth && (refreshed.runtime.auth.source !== "local" || refreshed.runtime.auth.localPath)) generated.push("ui/src/lib/auth-types.gen.ts");
				if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, "host", "src"))) generated.push("host/src/lib/auth-types.gen.ts");
				for (const [key, _plugin] of Object.entries(refreshed.runtime.plugins ?? {})) if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, "plugins", key, "src", "lib", "plugins-client.gen.ts"))) generated.push(`plugins/${key}/src/lib/plugins-client.gen.ts`);
				const contractStatus = artifacts?.contractStatus ?? [];
				const fetched = [];
				const skipped = [];
				const failed = [];
				for (const entry of contractStatus) if (entry.source === "remote") fetched.push(entry.url ? `${entry.key} remote (${entry.url})` : entry.key);
				else if (entry.source === "local") {
					const path = entry.localPath ? ` (${(0, node_path.relative)(projectDir, entry.localPath)})` : "";
					skipped.push(`${entry.key} local${path}`);
				} else if (entry.source === "skipped") skipped.push(`${entry.key} no URL resolved`);
				else if (entry.source === "failed") {
					const detail = entry.error ? `: ${entry.error}` : "";
					failed.push(`${entry.key}${detail}`);
				}
				return {
					status: "success",
					generated,
					fetched,
					skipped,
					failed
				};
			} catch (error) {
				return {
					status: "error",
					generated: [],
					fetched: [],
					skipped: [],
					failed: [],
					error: error instanceof Error ? error.message : "Unknown error"
				};
			}
		}),
		dbStudio: builder.dbStudio.handler(async ({ input }) => {
			try {
				const configPath = require_config.findConfigPath();
				if (!configPath) return {
					status: "error",
					plugin: input.plugin,
					source: "remote",
					section: "",
					error: "No bos.config.json found in current directory"
				};
				const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath));
				require_infra.loadProjectEnv(projectDir);
				const refreshed = await require_config.loadResolvedConfig({ cwd: projectDir });
				if (!refreshed) return {
					status: "error",
					plugin: input.plugin,
					source: "remote",
					section: "",
					error: "Failed to load bos.config.json"
				};
				const { resolvePluginDbInfo } = await Promise.resolve().then(() => require("./cli/db-studio.cjs"));
				const info = resolvePluginDbInfo(input.plugin, refreshed.runtime, projectDir);
				return {
					status: "success",
					plugin: info.key,
					source: info.source,
					section: info.section,
					databaseSecret: info.databaseSecret,
					databaseUrl: info.databaseUrl,
					workspaceDir: info.workspaceDir
				};
			} catch (error) {
				return {
					status: "error",
					plugin: input.plugin,
					source: "remote",
					section: "",
					error: error instanceof Error ? error.message : "Unknown error"
				};
			}
		}),
		dbDoctor: builder.dbDoctor.handler(async ({ input }) => {
			try {
				const configPath = require_config.findConfigPath();
				if (!configPath) return {
					status: "error",
					plugin: input.plugin,
					slug: "",
					journalTable: "",
					journalSchema: "",
					diagnosis: "error",
					localMigrationCount: 0,
					appliedHashCount: 0,
					expectedTables: [],
					missingTables: [],
					error: "No bos.config.json"
				};
				const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath));
				require_infra.loadProjectEnv(projectDir);
				const refreshed = await require_config.loadResolvedConfig({ cwd: projectDir });
				if (!refreshed) return {
					status: "error",
					plugin: input.plugin,
					slug: "",
					journalTable: "",
					journalSchema: "",
					diagnosis: "error",
					localMigrationCount: 0,
					appliedHashCount: 0,
					expectedTables: [],
					missingTables: [],
					error: "Failed to load config"
				};
				const { resolvePluginDbInfo } = await Promise.resolve().then(() => require("./cli/db-studio.cjs"));
				const info = resolvePluginDbInfo(input.plugin, refreshed.runtime, projectDir);
				const { diagnosePlugin } = await Promise.resolve().then(() => require("./cli/db-doctor.cjs"));
				return {
					status: "success",
					...await diagnosePlugin(info)
				};
			} catch (error) {
				return {
					status: "error",
					plugin: input.plugin,
					slug: "",
					journalTable: "",
					journalSchema: "",
					diagnosis: "error",
					localMigrationCount: 0,
					appliedHashCount: 0,
					expectedTables: [],
					missingTables: [],
					error: error instanceof Error ? error.message : "Unknown error"
				};
			}
		}),
		dbRepair: builder.dbRepair.handler(async ({ input }) => {
			try {
				const configPath = require_config.findConfigPath();
				if (!configPath) return {
					status: "error",
					message: "No bos.config.json found",
					diagnosis: null,
					error: "No config"
				};
				const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath));
				require_infra.loadProjectEnv(projectDir);
				const refreshed = await require_config.loadResolvedConfig({ cwd: projectDir });
				if (!refreshed) return {
					status: "error",
					message: "Failed to load config",
					diagnosis: null,
					error: "Config load failed"
				};
				const { resolvePluginDbInfo } = await Promise.resolve().then(() => require("./cli/db-studio.cjs"));
				const info = resolvePluginDbInfo(input.plugin, refreshed.runtime, projectDir);
				const { repairPlugin } = await Promise.resolve().then(() => require("./cli/db-repair.cjs"));
				const result = await repairPlugin(info, input.mode ?? "history-reset");
				return {
					...result,
					error: result.status === "error" ? result.message : void 0
				};
			} catch (error) {
				return {
					status: "error",
					message: error instanceof Error ? error.message : "Unknown error",
					diagnosis: null,
					error: error instanceof Error ? error.message : "Unknown error"
				};
			}
		}),
		status: builder.status.handler(async () => {
			try {
				const configPath = require_config.findConfigPath();
				if (!configPath) return {
					status: "error",
					packages: [],
					envFile: "missing",
					error: "No bos.config.json found in current directory"
				};
				return await require_status.getStatus((0, node_path.resolve)((0, node_path.dirname)(configPath)));
			} catch (error) {
				return {
					status: "error",
					packages: [],
					envFile: "missing",
					error: error instanceof Error ? error.message : "Unknown error"
				};
			}
		}),
		ps: builder.ps.handler(async () => {
			try {
				return {
					status: "ok",
					entries: await effect.Effect.runPromise(require_process_registry.pruneDeadEffect(require_process_registry.readRegistry()))
				};
			} catch (error) {
				return {
					status: "error",
					entries: [],
					error: error instanceof Error ? error.message : "Unknown error"
				};
			}
		}),
		kill: builder.kill.handler(async ({ input }) => {
			try {
				const entries = await effect.Effect.runPromise(require_process_registry.pruneDeadEffect(require_process_registry.readRegistry()));
				const configPath = require_config.findConfigPath();
				const targetConfigDir = input.all ? void 0 : input.configDir ?? (configPath ? (0, node_path.resolve)((0, node_path.dirname)(configPath)) : void 0);
				const targets = targetConfigDir ? entries.filter((entry) => entry.configDir === targetConfigDir) : entries;
				const killed = [];
				const skipped = [];
				for (const entry of targets) try {
					node_process.default.kill(entry.pid, input.signal === "SIGKILL" ? "SIGKILL" : "SIGTERM");
					killed.push({
						pid: entry.pid,
						configDir: entry.configDir
					});
					require_process_registry.unregisterPid(entry.pid);
				} catch (err) {
					if (err.code === "ESRCH") {
						skipped.push({
							pid: entry.pid,
							reason: "process already exited"
						});
						require_process_registry.unregisterPid(entry.pid);
					} else skipped.push({
						pid: entry.pid,
						reason: err.message ?? "kill failed"
					});
				}
				return {
					status: "killed",
					killed,
					skipped
				};
			} catch (error) {
				return {
					status: "error",
					killed: [],
					skipped: [],
					error: error instanceof Error ? error.message : "Unknown error"
				};
			}
		})
	})
});
function computeAllowedWorkspaces(overrides, plugins) {
	const workspaces = [];
	for (const section of overrides) {
		if (section === "host") workspaces.push("host");
		if (section === "ui") workspaces.push("ui");
		if (section === "api") workspaces.push("api");
	}
	if (plugins && plugins.length > 0) workspaces.push("plugins/*");
	return workspaces;
}

//#endregion
exports.consumeDevSession = consumeDevSession;
exports.default = plugin_default;
exports.pluginEvents = pluginEvents;
exports.resolveRemoteConfigChain = resolveRemoteConfigChain;
//# sourceMappingURL=plugin.cjs.map