@kya-os/cli
Version:
CLI for MCP-I setup and management
320 lines ⢠13 kB
JavaScript
import chalk from "chalk";
import { exec } from "child_process";
import { promisify } from "util";
import { EnvManager } from "../utils/env-manager.js";
import { detectPlatform } from "../utils/platform-detector.js";
import { showSuccess, showError } from "../utils/prompts.js";
import { cliEffects } from "../effects/cli-integration.js";
const execAsync = promisify(exec);
export async function env(subcommand) {
const envManager = new EnvManager();
switch (subcommand) {
case "show":
await showEnv(envManager);
break;
case "copy":
await copyEnv(envManager);
break;
case "verify":
await verifyEnv(envManager);
break;
case "print":
await printPlatformEnvVars();
break;
}
}
async function showEnv(envManager) {
console.log(chalk.cyan("\nš XMCP-I Environment Variables\n"));
// Try to get from multiple sources
let vars = envManager.getFromProcess();
if (!vars.AGENT_DID) {
// Try reading from files
const files = [".env.local", ".env", ".env.production"];
for (const file of files) {
const fileVars = envManager.readEnvFile(file);
if (fileVars.AGENT_DID) {
vars = fileVars;
console.log(chalk.gray(`(from ${file})\n`));
break;
}
}
}
else {
console.log(chalk.gray("(from process.env)\n"));
}
if (!vars.AGENT_DID) {
showError("No XMCP-I environment variables found");
console.log("Run the following to initialize:");
console.log(chalk.cyan(" mcpi init"));
return;
}
// Display variables with binary matrix effect
const varsDisplay = envManager.formatForDisplay(vars, true);
await cliEffects.showCustomEffect("binarypath", varsDisplay, {
config: {
duration: 3000,
streamCount: 8,
binaryColors: ["008800", "00ff00"],
revealColor: "00ff00",
streamDelay: 50,
},
});
// Platform-specific instructions
const platform = detectPlatform();
console.log(chalk.bold("\nš Platform-specific usage:\n"));
if (platform.platform === "vercel" || platform.platform === "nextjs") {
console.log("For Vercel deployment:");
console.log("1. Copy these variables: " + chalk.cyan("mcpi env copy"));
console.log("2. Go to Vercel Dashboard ā Settings ā Environment Variables");
console.log("3. Add each variable for Production/Preview/Development as needed");
}
else if (platform.platform === "lambda") {
console.log("For AWS Lambda:");
console.log("1. Add to your Lambda function configuration");
console.log("2. Or use AWS Systems Manager Parameter Store");
console.log("3. Or add to your serverless.yml/SAM template");
}
else if (platform.platform === "docker") {
console.log("For Docker:");
console.log("1. Add to docker-compose.yml under environment:");
console.log("2. Or use --env-file with docker run");
console.log("3. Or build args in Dockerfile");
}
else {
console.log("Add these to your deployment platform's environment configuration.");
}
}
async function copyEnv(envManager) {
console.log(chalk.cyan("\nš Copying XMCP-I Environment Variables\n"));
// Get variables
let vars = envManager.getFromProcess();
if (!vars.AGENT_DID) {
const files = [".env.local", ".env"];
for (const file of files) {
const fileVars = envManager.readEnvFile(file);
if (fileVars.AGENT_DID) {
vars = fileVars;
break;
}
}
}
if (!vars.AGENT_DID) {
showError("No XMCP-I environment variables found");
return;
}
// Format for clipboard (no masking)
const formatted = envManager.formatForClipboard(vars);
// Try to copy to clipboard
try {
// Detect OS and use appropriate command
const platform = process.platform;
let command;
if (platform === "darwin") {
command = "pbcopy";
}
else if (platform === "win32") {
command = "clip";
}
else {
// Linux - try xclip first, then xsel
try {
await execAsync("which xclip");
command = "xclip -selection clipboard";
}
catch {
try {
await execAsync("which xsel");
command = "xsel --clipboard --input";
}
catch {
throw new Error("No clipboard utility found. Install xclip or xsel.");
}
}
}
// Copy to clipboard
const proc = exec(command);
if (proc.stdin) {
proc.stdin.write(formatted);
proc.stdin.end();
}
await new Promise((resolve, reject) => {
proc.on("exit", (code) => {
if (code === 0)
resolve(null);
else
reject(new Error(`Clipboard command failed with code ${code}`));
});
proc.on("error", reject);
});
showSuccess("Environment variables copied to clipboard!");
console.log("\nNext steps:");
console.log("1. Paste into your deployment platform's environment configuration");
console.log("2. Make sure to save/apply the changes");
console.log("\n" +
chalk.yellow("ā ļø Keep these values secure - they contain your private key!"));
}
catch (error) {
showError(`Failed to copy to clipboard: ${error.message}`);
console.log("\nManual copy:\n");
console.log(chalk.gray("ā".repeat(60)));
console.log(formatted);
console.log(chalk.gray("ā".repeat(60)));
}
}
async function verifyEnv(envManager) {
console.log(chalk.cyan("\nā
Verifying XMCP-I Environment\n"));
// Check process.env
const processVars = envManager.getFromProcess();
const { valid: processValid, missing: processMissing } = envManager.validateVariables(processVars);
console.log(chalk.bold("Process Environment:"));
if (processValid) {
console.log(` ā ${chalk.green("All variables present in process.env")}`);
}
else {
console.log(` ā ${chalk.red("Missing from process.env:")} ${processMissing.join(", ")}`);
}
// Check files
console.log(chalk.bold("\nEnvironment Files:"));
const files = [".env", ".env.local", ".env.production"];
let foundValidFile = false;
for (const file of files) {
const fileVars = envManager.readEnvFile(file);
if (fileVars.AGENT_DID) {
const { valid, missing } = envManager.validateVariables(fileVars);
if (valid) {
console.log(` ā ${chalk.green(file)} - All variables present`);
foundValidFile = true;
}
else {
console.log(` ā ļø ${chalk.yellow(file)} - Missing: ${missing.join(", ")}`);
}
}
}
if (!foundValidFile && !processValid) {
console.log(` ā ${chalk.red("No valid environment configuration found")}`);
}
// Platform-specific checks
const platform = detectPlatform();
console.log(chalk.bold("\nPlatform-Specific:"));
if (platform.platform === "vercel" || platform.platform === "nextjs") {
if (process.env.VERCEL) {
console.log(` ā ${chalk.green("Running on Vercel")}`);
if (processValid) {
console.log(` ā ${chalk.green("Environment variables configured in Vercel")}`);
}
else {
console.log(` ā ${chalk.red("Environment variables not found - add to Vercel Dashboard")}`);
}
}
else {
console.log(` ā¹ļø ${chalk.blue("Local development - using .env.local")}`);
}
}
// Summary
console.log(chalk.bold("\nSummary:"));
if (processValid || foundValidFile) {
showSuccess("Environment configuration is valid!");
}
else {
showError("Environment configuration issues found");
console.log("\nTo fix:");
console.log("1. Run: " + chalk.cyan("mcpi init"));
console.log("2. Or manually create .env file with required variables");
}
}
/**
* Print platform-specific environment variable names
* This implements Requirement 10.5 - making the Platform Environment Variables Table
* the single source of truth enforced by the CLI
*/
async function printPlatformEnvVars() {
console.log(chalk.cyan("\nš Platform Environment Variables\n"));
// Platform Environment Variables Table (single source of truth)
const platformVars = {
Vercel: {
AGENT_PRIVATE_KEY: "AGENT_PRIVATE_KEY",
AGENT_KEY_ID: "AGENT_KEY_ID",
AGENT_DID: "AGENT_DID",
KYA_VOUCHED_API_KEY: "KYA_VOUCHED_API_KEY",
},
"Cloudflare Workers": {
AGENT_PRIVATE_KEY: "AGENT_PRIVATE_KEY",
AGENT_KEY_ID: "AGENT_KEY_ID",
AGENT_DID: "AGENT_DID",
KYA_VOUCHED_API_KEY: "KYA_VOUCHED_API_KEY",
},
"AWS Lambda": {
AGENT_PRIVATE_KEY: "AGENT_PRIVATE_KEY",
AGENT_KEY_ID: "AGENT_KEY_ID",
AGENT_DID: "AGENT_DID",
KYA_VOUCHED_API_KEY: "KYA_VOUCHED_API_KEY",
},
};
// Display table
console.log(chalk.bold("Platform Environment Variables Table:"));
console.log();
// Table header
const headers = [
"Platform",
"AGENT_PRIVATE_KEY",
"AGENT_KEY_ID",
"AGENT_DID",
"KYA_VOUCHED_API_KEY",
];
const colWidths = [18, 17, 12, 9, 19];
// Print header
let headerRow = "";
headers.forEach((header, i) => {
headerRow += header.padEnd(colWidths[i]) + " | ";
});
console.log(chalk.bold(headerRow));
// Print separator
let separator = "";
colWidths.forEach((width) => {
separator += "-".repeat(width) + " | ";
});
console.log(separator);
// Print rows
Object.entries(platformVars).forEach(([platform, vars]) => {
let row = platform.padEnd(colWidths[0]) + " | ";
row += vars.AGENT_PRIVATE_KEY.padEnd(colWidths[1]) + " | ";
row += vars.AGENT_KEY_ID.padEnd(colWidths[2]) + " | ";
row += vars.AGENT_DID.padEnd(colWidths[3]) + " | ";
row += vars.KYA_VOUCHED_API_KEY.padEnd(colWidths[4]) + " | ";
console.log(row);
});
console.log();
console.log(chalk.gray("Note: All platforms currently use the same variable names."));
console.log(chalk.gray("This table serves as the single source of truth for environment variable naming."));
// Detect current platform and provide specific guidance
const platform = detectPlatform();
console.log(chalk.bold("\nš Current Platform Guidance:"));
if (platform.platform === "vercel" || platform.platform === "nextjs") {
console.log(chalk.cyan("Vercel Deployment:"));
console.log("1. Go to Vercel Dashboard ā Settings ā Environment Variables");
console.log("2. Add each variable for Production/Preview/Development as needed");
console.log("3. Use the exact names shown in the table above");
}
else if (platform.platform === "lambda") {
console.log(chalk.cyan("AWS Lambda Deployment:"));
console.log("1. Add to your Lambda function configuration");
console.log("2. Or use AWS Systems Manager Parameter Store");
console.log("3. Or add to your serverless.yml/SAM template");
}
else {
console.log(chalk.cyan("General Deployment:"));
console.log("1. Set environment variables using the names from the table");
console.log("2. Ensure variables are available to your application at runtime");
console.log("3. Keep private keys secure and never commit them to version control");
}
console.log(chalk.bold("\nš Required Variables:"));
console.log(`${chalk.cyan("AGENT_PRIVATE_KEY")} - Base64-encoded Ed25519 private key`);
console.log(`${chalk.cyan("AGENT_KEY_ID")} - Key identifier (e.g., key-1)`);
console.log(`${chalk.cyan("AGENT_DID")} - Decentralized identifier (e.g., did:web:example.com)`);
console.log(`${chalk.cyan("KYA_VOUCHED_API_KEY")} - Know-That-AI API key for registration`);
console.log(chalk.bold("\nš” Usage:"));
console.log(`${chalk.gray("⢠Copy variable names:")} ${chalk.cyan("mcpi env copy")}`);
console.log(`${chalk.gray("⢠Verify configuration:")} ${chalk.cyan("mcpi env verify")}`);
console.log(`${chalk.gray("⢠Show current values:")} ${chalk.cyan("mcpi env show")}`);
}
//# sourceMappingURL=env.js.map