create-eliza
Version:
Initialize an Eliza project
575 lines (568 loc) • 19.1 kB
JavaScript
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
import {
handleError
} from "./chunk-WDKH5BMD.js";
import {
AgentServer,
checkEnvVarsForPlugin,
jsonToCharacter,
loadCharacterTryPath,
promptForEnvVars,
promptForServices
} from "./chunk-7WYPZOGF.js";
import {
character
} from "./chunk-34HYEHJA.js";
import {
require_main
} from "./chunk-ZMJ3QLUC.js";
import {
source_default
} from "./chunk-BY3DNMXE.js";
import {
AgentRuntime,
logger,
settings,
stringToUuid
} from "./chunk-UIEY2LL5.js";
import {
Command
} from "./chunk-CKY7YPIS.js";
import {
__toESM
} from "./chunk-WCMDOJQK.js";
// src/commands/start.ts
import fs2 from "node:fs";
import net from "node:net";
import os2 from "node:os";
import path2 from "node:path";
import { fileURLToPath } from "node:url";
var dotenv = __toESM(require_main(), 1);
// src/utils/character-generator.ts
var PLUGIN_MAP = {
openai: "@elizaos/plugin-openai",
anthropic: "@elizaos/plugin-anthropic",
discord: "@elizaos/plugin-discord",
twitter: "@elizaos/plugin-twitter",
telegram: "@elizaos/plugin-telegram",
sql: "@elizaos/plugin-sql"
};
function generateCustomCharacter(services = [], aiModels = []) {
const plugins = ["sql"];
plugins.push(...aiModels);
plugins.push(...services);
const uniquePlugins = [...new Set(plugins)];
const packageNames = uniquePlugins.map((plugin) => PLUGIN_MAP[plugin]);
const customCharacter = {
...JSON.parse(JSON.stringify(character)),
plugins: packageNames
};
return customCharacter;
}
// src/utils/config-manager.ts
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
function getConfigFilePath() {
const homeDir = os.homedir();
const elizaDir = path.join(homeDir, ".eliza");
return path.join(elizaDir, "config.json");
}
function loadConfig() {
try {
const configPath = getConfigFilePath();
if (!fs.existsSync(configPath)) {
return {
services: [],
aiModels: ["openai"],
// Default to OpenAI
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
isDefault: true
// Mark as default config
};
}
const content = fs.readFileSync(configPath, "utf8");
return JSON.parse(content);
} catch (error) {
logger.warn(`Error loading configuration: ${error}`);
return {
services: [],
aiModels: ["openai"],
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
isDefault: true
// Mark as default config
};
}
}
function saveConfig(config2) {
try {
const configPath = getConfigFilePath();
const elizaDir = path.dirname(configPath);
if (!fs.existsSync(elizaDir)) {
fs.mkdirSync(elizaDir, { recursive: true });
}
config2.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
fs.writeFileSync(configPath, JSON.stringify(config2, null, 2), "utf8");
logger.info(`Configuration saved to ${configPath}`);
} catch (error) {
logger.error(`Error saving configuration: ${error}`);
}
}
function getPluginStatus() {
const allPlugins = [
"openai",
"anthropic",
"discord",
"twitter",
"telegram",
"pglite"
];
const status = {};
for (const plugin of allPlugins) {
status[plugin] = checkEnvVarsForPlugin(plugin);
}
return status;
}
function displayConfigStatus() {
const config2 = loadConfig();
const pluginStatus = getPluginStatus();
logger.info("\n=== Current Configuration ===");
if (config2.isDefault) {
logger.info(
source_default.yellow(
"Using default configuration - you will be prompted to customize your setup."
)
);
}
logger.info("Services:");
if (config2.services.length) {
for (const service of config2.services) {
const status = pluginStatus[service] ? source_default.green("\u2713 configured") : source_default.yellow("\u26A0 missing environment variables");
logger.info(` ${source_default.cyan(service)}: ${status}`);
}
} else {
logger.info(` ${source_default.gray("No services configured")}`);
}
logger.info("AI Models:");
if (config2.aiModels.length) {
for (const model of config2.aiModels) {
const status = pluginStatus[model] ? source_default.green("\u2713 configured") : source_default.yellow("\u26A0 missing environment variables");
logger.info(` ${source_default.cyan(model)}: ${status}`);
}
} else {
logger.info(` ${source_default.gray("No AI models configured")}`);
}
if (config2.lastUpdated && !config2.isDefault) {
logger.info(
`Last updated: ${source_default.gray(new Date(config2.lastUpdated).toLocaleString())}`
);
}
if (!config2.isDefault) {
logger.info(
"\nTo change this configuration, run with the --configure flag"
);
}
logger.info("");
}
// src/commands/start.ts
var __filename = fileURLToPath(import.meta.url);
var __dirname = path2.dirname(__filename);
var wait = (minTime = 1e3, maxTime = 3e3) => {
const waitTime = Math.floor(Math.random() * (maxTime - minTime + 1)) + minTime;
return new Promise((resolve) => setTimeout(resolve, waitTime));
};
async function promptForProjectPlugins(project, pluginToLoad) {
const pluginsToPrompt = /* @__PURE__ */ new Set();
if (pluginToLoad?.name) {
pluginsToPrompt.add(pluginToLoad.name.toLowerCase());
}
if (project) {
const agents = Array.isArray(project.agents) ? project.agents : project.agent ? [project.agent] : [];
for (const agent of agents) {
if (agent.plugins?.length) {
for (const plugin of agent.plugins) {
const pluginName = typeof plugin === "string" ? plugin : plugin.name;
if (pluginName) {
const simpleName = pluginName.split("/").pop()?.replace("plugin-", "") || pluginName;
pluginsToPrompt.add(simpleName.toLowerCase());
}
}
}
}
}
pluginsToPrompt.add("pglite");
for (const pluginName of pluginsToPrompt) {
try {
await promptForEnvVars(pluginName);
} catch (error) {
logger.warn(
`Failed to prompt for ${pluginName} environment variables: ${error}`
);
}
}
}
async function startAgent(character2, server, init, plugins = [], options = {}) {
character2.id ??= stringToUuid(character2.name);
const runtime = new AgentRuntime({
character: character2,
plugins
});
if (init) {
await init(runtime);
}
await runtime.initialize();
server.registerAgent(runtime);
logger.debug(`Started ${runtime.character.name} as ${runtime.agentId}`);
return runtime;
}
async function stopAgent(runtime, server) {
await runtime.close();
server.unregisterAgent(runtime.agentId);
}
var checkPortAvailable = (port) => {
return new Promise((resolve) => {
const server = net.createServer();
server.once("error", (err) => {
if (err.code === "EADDRINUSE") {
resolve(false);
}
});
server.once("listening", () => {
server.close();
resolve(true);
});
server.listen(port);
});
};
var startAgents = async (options) => {
const homeDir = os2.homedir();
const elizaDir = path2.join(homeDir, ".eliza");
const elizaDbDir = path2.join(elizaDir, "db");
const envFilePath = path2.join(elizaDir, ".env");
if (!fs2.existsSync(elizaDir)) {
fs2.mkdirSync(elizaDir, { recursive: true });
logger.info(`Created directory: ${elizaDir}`);
}
if (!fs2.existsSync(elizaDbDir)) {
fs2.mkdirSync(elizaDbDir, { recursive: true });
logger.info(`Created database directory: ${elizaDbDir}`);
}
process.env.PGLITE_DATA_DIR = elizaDbDir;
logger.info(`Using database directory: ${elizaDbDir}`);
if (fs2.existsSync(envFilePath)) {
dotenv.config({ path: envFilePath });
}
try {
await promptForEnvVars("pglite");
} catch (error) {
logger.warn(`Error configuring database: ${error}`);
}
const existingConfig = loadConfig();
const pluginStatus = getPluginStatus();
let selectedServices = [];
let selectedAiModels = [];
console.log("*** existingConfig", existingConfig);
const shouldConfigure = options.configure || existingConfig.isDefault;
if (shouldConfigure) {
displayConfigStatus();
if (existingConfig.isDefault) {
logger.info("First time setup. Let's configure your Eliza agent.");
} else {
logger.info("Reconfiguration requested.");
}
await new Promise((resolve) => setTimeout(resolve, 100));
const userSelections = await promptForServices();
selectedServices = userSelections.services;
selectedAiModels = userSelections.aiModels;
saveConfig({
services: selectedServices,
aiModels: selectedAiModels,
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
// isDefault is not included to indicate this is now a user-configured setup
});
} else {
selectedServices = existingConfig.services;
selectedAiModels = existingConfig.aiModels;
}
const pluginsToPrompt = [
"pglite",
...selectedServices,
...selectedAiModels
].filter((plugin, index, self) => self.indexOf(plugin) === index);
const missingEnvVars = pluginsToPrompt.filter(
(plugin) => !pluginStatus[plugin]
);
if (missingEnvVars.length > 0) {
logger.info(
`${missingEnvVars.length} plugins need configuration. Let's set them up.`
);
for (const plugin of missingEnvVars) {
logger.info(`Configuring ${plugin}...`);
await promptForEnvVars(plugin);
}
logger.info("All required plugin configurations complete!");
}
const customCharacter = generateCustomCharacter(
selectedServices,
selectedAiModels
);
const postgresUrl = process.env.POSTGRES_URL;
const server = new AgentServer({
dataDir: elizaDbDir,
postgresUrl
});
server.startAgent = async (character2) => {
logger.info(`Starting agent for character ${character2.name}`);
return startAgent(character2, server);
};
server.stopAgent = (runtime) => {
stopAgent(runtime, server);
};
server.loadCharacterTryPath = loadCharacterTryPath;
server.jsonToCharacter = jsonToCharacter;
let serverPort = options.port || Number.parseInt(settings.SERVER_PORT || "3000");
let isProject = false;
let isPlugin = false;
let pluginModule = null;
let projectModule = null;
logger.info("Checking for project or plugin in current directory...");
const currentDir = process.cwd();
logger.info(`Current directory: ${currentDir}`);
try {
const packageJsonPath = path2.join(process.cwd(), "package.json");
if (fs2.existsSync(packageJsonPath)) {
const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
if (packageJson.eliza?.type && packageJson.eliza.type === "plugin") {
isPlugin = true;
logger.info("Found Eliza plugin in current directory");
}
if (packageJson.eliza?.type && packageJson.eliza.type === "project") {
isProject = true;
logger.info("Found Eliza project in current directory");
}
if (!isProject && !isPlugin) {
if (packageJson.description?.toLowerCase().includes("project")) {
isProject = true;
logger.info("Found project by description in package.json");
}
}
const mainEntry = packageJson.main;
if (mainEntry) {
const mainPath = path2.resolve(process.cwd(), mainEntry);
if (fs2.existsSync(mainPath)) {
try {
const importedModule = await import(mainPath);
if (isPlugin || importedModule.default && typeof importedModule.default === "object" && importedModule.default.name && typeof importedModule.default.init === "function") {
isPlugin = true;
pluginModule = importedModule.default;
logger.info(`Loaded plugin: ${pluginModule?.name || "unnamed"}`);
if (!pluginModule) {
logger.warn(
"Plugin loaded but no default export found, looking for other exports"
);
for (const key in importedModule) {
if (importedModule[key] && typeof importedModule[key] === "object" && importedModule[key].name && typeof importedModule[key].init === "function") {
pluginModule = importedModule[key];
logger.info(`Found plugin export under key: ${key}`);
break;
}
}
}
} else if (isProject || importedModule.default && typeof importedModule.default === "object" && importedModule.default.agents) {
isProject = true;
projectModule = importedModule;
logger.info(
`Loaded project with ${projectModule.default?.agents?.length || 0} agents`
);
}
} catch (importError) {
logger.error(`Error importing module: ${importError}`);
}
} else {
logger.error(`Main entry point ${mainPath} does not exist`);
}
}
} else {
const projectFiles = ["project.json", "eliza.json", "agents.json"];
for (const file of projectFiles) {
const filePath = path2.join(process.cwd(), file);
if (fs2.existsSync(filePath)) {
try {
const fileContent = fs2.readFileSync(filePath, "utf-8");
const projectData = JSON.parse(fileContent);
if (projectData.agents || projectData.agent) {
isProject = true;
projectModule = { default: projectData };
logger.info(`Found project in ${file}`);
break;
}
} catch (error) {
logger.warn(
`Error reading possible project file ${file}: ${error}`
);
}
}
}
if (!isProject && !isPlugin) {
logger.info(
"No package.json or project files found, using custom character"
);
}
}
} catch (error) {
logger.error(`Error checking for project/plugin: ${error}`);
}
if (isProject) {
logger.info("Found project configuration");
if (projectModule?.default) {
const project = projectModule.default;
const agents = Array.isArray(project.agents) ? project.agents : project.agent ? [project.agent] : [];
logger.info(`Project contains ${agents.length} agent(s)`);
if (agents.length > 0) {
logger.info(
`Agents: ${agents.map((a) => a.character?.name || "unnamed").join(", ")}`
);
}
} else {
logger.warn("Project module doesn't contain a valid default export");
}
} else if (isPlugin) {
logger.info(`Found plugin: ${pluginModule?.name || "unnamed"}`);
} else {
logger.info("No project or plugin found, will use custom character");
}
if (isProject && projectModule?.default) {
const project = projectModule.default;
const agents = Array.isArray(project.agents) ? project.agents : project.agent ? [project.agent] : [];
if (agents.length > 0) {
logger.info(`Found ${agents.length} agents in project`);
try {
await promptForProjectPlugins(project);
} catch (error) {
logger.warn(
`Failed to prompt for project environment variables: ${error}`
);
}
const startedAgents = [];
for (const agent of agents) {
try {
logger.info(`Starting agent: ${agent.character.name}`);
const runtime = await startAgent(
agent.character,
server,
agent.init,
agent.plugins || []
);
startedAgents.push(runtime);
await new Promise((resolve) => setTimeout(resolve, 500));
} catch (agentError) {
logger.error(
`Error starting agent ${agent.character.name}: ${agentError}`
);
}
}
if (startedAgents.length === 0) {
logger.warn(
"Failed to start any agents from project, falling back to custom character"
);
await startAgent(customCharacter, server);
} else {
logger.info(
`Successfully started ${startedAgents.length} agents from project`
);
}
} else {
logger.warn(
"Project found but no agents defined, falling back to custom character"
);
await startAgent(customCharacter, server);
}
} else if (isPlugin && pluginModule) {
if (pluginModule.name) {
try {
await promptForEnvVars(pluginModule.name);
} catch (error) {
logger.warn(
`Failed to prompt for plugin environment variables: ${error}`
);
}
}
logger.info(
`Starting custom character with plugin: ${pluginModule.name || "unnamed plugin"}`
);
const pluginsToLoad = [pluginModule];
await startAgent(customCharacter, server, void 0, pluginsToLoad);
logger.info("Character started with plugin successfully");
} else {
logger.info("Starting with custom character");
await startAgent(customCharacter, server);
}
while (!await checkPortAvailable(serverPort)) {
logger.warn(`Port ${serverPort} is in use, trying ${serverPort + 1}`);
serverPort++;
}
server.start(serverPort);
if (serverPort !== Number.parseInt(settings.SERVER_PORT || "3000")) {
logger.log(`Server started on alternate port ${serverPort}`);
}
let clientPath = path2.join(__dirname, "../../client");
if (!fs2.existsSync(clientPath)) {
clientPath = path2.join(__dirname, "../../../../..", "packages/client/dist");
}
if (fs2.existsSync(clientPath)) {
logger.success(
`Client UI is available at http://localhost:${serverPort}/client`
);
} else {
const clientSrcPath = path2.join(
__dirname,
"../../../..",
"packages/client"
);
if (fs2.existsSync(clientSrcPath)) {
logger.info(
"Client build not found. You can build it with: cd packages/client && npm run build"
);
}
}
};
var start = new Command().name("start").description("Start the Eliza agent with configurable plugins and services").option(
"-p, --port <port>",
"Port to listen on",
(val) => Number.parseInt(val)
).option(
"-c, --configure",
"Reconfigure services and AI models (skips using saved configuration)"
).option("--dev", "Start with development settings").option(
"--character <character>",
"Path or URL to character file to use instead of default"
).action(async (options) => {
try {
const characterPath = options.character;
if (characterPath) {
logger.info(`Loading character from ${characterPath}`);
try {
const characterData = await loadCharacterTryPath(characterPath);
await startAgents(options);
} catch (error) {
logger.error(`Failed to load character: ${error}`);
process.exit(1);
}
} else {
await startAgents(options);
}
} catch (error) {
handleError(error);
}
});
function registerCommand(cli) {
return cli.addCommand(start);
}
export {
wait,
promptForProjectPlugins,
start,
registerCommand
};
//# sourceMappingURL=chunk-JJFTJBPT.js.map