@kya-os/cli
Version:
CLI for MCP-I setup and management
173 lines • 7.94 kB
JavaScript
import chalk from "chalk";
import { spawn } from "child_process";
import { existsSync, readFileSync } from "fs";
import { join } from "path";
import { showError, showSuccess, showInfo } from "../utils/prompts.js";
/**
* Build the XMCP-I application for production
*/
export async function build() {
console.log(chalk.cyan("\n🔨 Building Application\n"));
// Check if we're in a valid XMCP-I project
const packageJsonPath = join(process.cwd(), "package.json");
if (!existsSync(packageJsonPath)) {
showError("No package.json found. Are you in a valid project directory?");
process.exit(1);
}
// Check for mcpi dependency
try {
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
const hasmcpi = packageJson.dependencies?.mcpi ||
packageJson.devDependencies?.mcpi ||
packageJson.dependencies?.["@kya-os/mcp-i"] ||
packageJson.devDependencies?.["@kya-os/mcp-i"] ||
packageJson.dependencies?.["@kya-os/mcpi"] ||
packageJson.devDependencies?.["@kya-os/mcpi"];
if (!hasmcpi) {
showError("This doesn't appear to be an XMCP-I project. Missing mcpi dependency.");
console.log(`\n${chalk.gray("To create a new XMCP-I project:")}`);
console.log(`${chalk.cyan("npx @kya-os/create-mcpi-app my-agent")}`);
process.exit(1);
}
}
catch (error) {
showError("Failed to read package.json");
process.exit(1);
}
// Check if this is an XMCP project with xmcp.config.ts
const xmcpConfigPath = join(process.cwd(), "xmcp.config.ts");
if (existsSync(xmcpConfigPath)) {
// Use XMCP compiler for XMCP projects
try {
showInfo("Building XMCP project...");
// Import and use the XMCP compiler
let compile;
try {
showInfo("Importing XMCP compiler...");
// Try ESM import first
const mcpiModule = await import("@kya-os/mcp-i");
compile = mcpiModule.compile || mcpiModule.default?.compile;
if (!compile) {
// Log available exports for debugging
console.log("Available exports:", Object.keys(mcpiModule));
throw new Error("compile function not found in ESM exports");
}
}
catch (esmError) {
showInfo("ESM import failed, trying CommonJS...");
// Fallback to CommonJS require
try {
const mcpiModule = require("@kya-os/mcp-i");
compile = mcpiModule.compile;
if (!compile) {
console.log("Available exports:", Object.keys(mcpiModule));
throw new Error("compile function not found in CJS exports");
}
}
catch (cjsError) {
const esmErrorMsg = esmError instanceof Error ? esmError.message : String(esmError);
const cjsErrorMsg = cjsError instanceof Error ? cjsError.message : String(cjsError);
showError("Failed to import XMCP compiler");
console.log("ESM error:", esmErrorMsg);
console.log("CJS error:", cjsErrorMsg);
console.log("\nDebugging info:");
console.log("- Make sure @kya-os/mcp-i is built: pnpm --filter=@kya-os/mcp-i build");
console.log("- Check if dist/index.js exists in packages/mcp-i/");
console.log("- Verify compile function is exported from mcpi");
throw new Error(`Failed to import XMCP compiler. ESM: ${esmErrorMsg}, CJS: ${cjsErrorMsg}`);
}
}
if (typeof compile !== "function") {
showError(`XMCP compiler 'compile' is not a function. Got: ${typeof compile}`);
throw new Error(`XMCP compiler 'compile' is not a function. Got: ${typeof compile}`);
}
showInfo("XMCP compiler imported successfully");
// Set production mode for build
process.env.NODE_ENV = "production";
// Wait for compilation to fully complete
await compile();
// Show success messages after compilation is done
showSuccess("Build completed successfully!");
console.log(`\n${chalk.gray("Next steps:")}`);
console.log(`${chalk.gray("• Deploy to your platform of choice")}`);
console.log(`${chalk.gray("• Set production environment variables")}`);
console.log(`${chalk.gray("• Test with: mcpi start")}`);
// Exit CLI after successful build
// This is necessary because webpack may have lingering handles even after compiler.close()
process.exit(0);
}
catch (error) {
showError(`XMCP build failed: ${error}`);
process.exit(1);
}
}
// Fallback to npm/tsc for non-XMCP projects
let command = "npm";
let args = ["run", "build"];
try {
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
if (!packageJson.scripts?.build) {
// Try alternative build approaches
if (existsSync(join(process.cwd(), "tsconfig.json"))) {
// Use TypeScript compiler directly
command = "npx";
args = ["tsc"];
showInfo("No build script found, using TypeScript compiler directly.");
}
else {
showError("No build script found and no TypeScript configuration detected.");
console.log(`\n${chalk.gray("Expected one of:")}`);
console.log(`${chalk.gray("• xmcp.config.ts for XMCP projects")}`);
console.log(`${chalk.gray("• npm script 'build' in package.json")}`);
console.log(`${chalk.gray("• tsconfig.json for TypeScript compilation")}`);
process.exit(1);
}
}
}
catch (error) {
showError("Failed to parse package.json");
process.exit(1);
}
console.log(`${chalk.gray("Running:")} ${chalk.cyan(`${command} ${args.join(" ")}`)}`);
// Spawn the build process
const child = spawn(command, args, {
stdio: "inherit",
shell: true,
env: {
...process.env,
NODE_ENV: "production",
},
});
// Handle process termination
process.on("SIGINT", () => {
console.log(chalk.yellow("\n\n🛑 Stopping build process..."));
child.kill("SIGINT");
});
process.on("SIGTERM", () => {
child.kill("SIGTERM");
});
child.on("error", (error) => {
showError(`Failed to start build process: ${error.message}`);
process.exit(1);
});
child.on("exit", (code) => {
if (code === 0) {
showSuccess("Build completed successfully!");
// Check for common output directories
const outputDirs = ["dist", "build", "out"];
const foundOutput = outputDirs.find((dir) => existsSync(join(process.cwd(), dir)));
if (foundOutput) {
console.log(`\n${chalk.gray("Output directory:")} ${chalk.cyan(foundOutput)}`);
}
console.log(`\n${chalk.gray("Next steps:")}`);
console.log(`${chalk.gray("• Deploy to your platform of choice")}`);
console.log(`${chalk.gray("• Set production environment variables")}`);
console.log(`${chalk.gray("• Test with:")} ${chalk.cyan("mcpi start")}`);
}
else if (code !== null) {
showError(`Build failed with exit code ${code}`);
process.exit(code);
}
});
}
//# sourceMappingURL=build.js.map