mastra
Version:
cli for mastra
1,325 lines (1,300 loc) • 45.7 kB
JavaScript
import { createMastraDir, writeIndexFile, createComponentsDir, writeAPIKey, writeCodeSample, DepsService, getAPIKey, installMastraDocsMCPServer, writeAgentsMarkdown, writeClaudeMarkdown, gitInit, readPackageName, writeObservabilityEnv, getAnalytics, getPackageManager, LLM_PROVIDERS, isGitInitialized, interactivePrompt, getPackageManagerAddCommand, getModelIdentifier } from './chunk-5FWKBO5J.js';
import { fetchOrgs } from './chunk-4Z57PBTZ.js';
import { getCurrentOrgId, setCurrentOrgId, getToken } from './chunk-EXG3XKBK.js';
import { MASTRA_PLATFORM_API_URL, platformFetch, authHeaders } from './chunk-L2SGSIJI.js';
import fsSync from 'fs';
import fs from 'fs/promises';
import * as p6 from '@clack/prompts';
import color from 'picocolors';
import child_process from 'child_process';
import path from 'path';
import util from 'util';
import shellQuote from 'shell-quote';
import yoctoSpinner from 'yocto-spinner';
import { PinoLogger } from '@mastra/loggers';
import { execa } from 'execa';
// package.json
var package_default = {
name: "mastra",
version: "1.10.0",
license: "Apache-2.0",
description: "cli for mastra",
type: "module",
main: "dist/index.js",
types: "dist/index.d.ts",
bin: {
mastra: "./dist/index.js"
},
exports: {
".": "./dist/index.js",
"./package.json": "./package.json",
"./telemetry-loader": "./dist/commands/dev/telemetry-loader.js",
"./dist/*": [
"./dist/*",
"./dist/*.js"
]
},
files: [
"dist",
"CHANGELOG.md"
],
scripts: {
"generate:api-manifest": "pnpm --filter @mastra/server generate:api-cli-route-metadata",
"build:lib": "tsup --silent --config tsup.config.ts",
prepack: "pnpx tsx ../../scripts/generate-package-docs.ts",
test: "vitest run",
"test:watch": "vitest watch",
clean: "rm -rf dist && rm -rf node_modules",
typecheck: "tsc --noEmit --incremental",
lint: "eslint ."
},
keywords: [
"mastra",
"cli",
"ai",
"llm",
"llms",
"agent",
"agents",
"dev",
"development",
"deploy",
"deployment",
"build",
"workflow",
"typescript",
"command-line",
"devtools"
],
dependencies: {
"@babel/parser": "^7.29.3",
"@babel/types": "^7.29.0",
"@clack/prompts": "^1.1.0",
"@expo/devcert": "^1.2.1",
"@mastra/deployer": "workspace:^",
"@mastra/loggers": "workspace:^",
archiver: "^7.0.1",
commander: "^14.0.3",
dotenv: "^17.3.1",
execa: "^9.6.1",
"fs-extra": "^11.3.4",
"get-port": "^7.1.0",
"local-pkg": "^1.1.2",
"openapi-fetch": "^0.17.0",
picocolors: "^1.1.1",
"posthog-node": "^5.30.6",
semver: "^7.7.4",
serve: "^14.2.6",
"serve-handler": "^6.1.7",
"shell-quote": "^1.8.3",
"strip-json-comments": "^5.0.3",
tinyglobby: "^0.2.16",
"yocto-spinner": "^1.1.0"
},
devDependencies: {
"@commander-js/extra-typings": "^14.0.0",
"@internal/lint": "workspace:*",
"@internal/playground": "workspace:*",
"@internal/types-builder": "workspace:*",
"@mastra/core": "workspace:*",
"@types/archiver": "^7.0.0",
"@types/fs-extra": "^11.0.4",
"@types/node": "22.19.15",
"@types/semver": "^7.7.1",
"@types/serve-handler": "^6.1.4",
"@types/shell-quote": "^1.7.5",
"@vitest/coverage-v8": "catalog:",
"@vitest/ui": "catalog:",
eslint: "^10.2.1",
memfs: "^4.56.11",
rollup: "^4.59.0",
tsup: "^8.5.1",
"type-fest": "^5.4.4",
typescript: "catalog:",
vitest: "catalog:"
},
peerDependencies: {
"@mastra/core": ">=1.34.0-0 <2.0.0-0",
zod: "^3.25.0 || ^4.0.0"
},
homepage: "https://mastra.ai",
repository: {
type: "git",
url: "git+https://github.com/mastra-ai/mastra.git",
directory: "packages/cli"
},
bugs: {
url: "https://github.com/mastra-ai/mastra/issues"
},
engines: {
node: ">=22.13.0"
}
};
var logger = createLogger(false);
function createLogger(debug = false) {
return new PinoLogger({
name: "Mastra CLI",
level: debug ? "debug" : "info"
});
}
// src/utils/clone-template.ts
var exec = util.promisify(child_process.exec);
async function cloneTemplate(options) {
const { template, projectName, targetDir, branch, llmProvider } = options;
const projectPath = targetDir ? path.resolve(targetDir, projectName) : path.resolve(projectName);
const spinner4 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
try {
if (await directoryExists(projectPath)) {
spinner4.error(`Directory ${projectName} already exists`);
throw new Error(`Directory ${projectName} already exists`);
}
await cloneRepositoryWithoutGit(template.githubUrl, projectPath, branch);
await updatePackageJson(projectPath, projectName);
const envExamplePath = path.join(projectPath, ".env.example");
if (await fileExists(envExamplePath)) {
const envPath = path.join(projectPath, ".env");
await fs.copyFile(envExamplePath, envPath);
if (llmProvider) {
await updateEnvFile(envPath, llmProvider);
}
}
spinner4.success(`Template "${template.title}" cloned successfully to ${projectName}`);
return projectPath;
} catch (error) {
spinner4.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
async function directoryExists(dirPath) {
try {
const stat = await fs.stat(dirPath);
return stat.isDirectory();
} catch {
return false;
}
}
async function fileExists(filePath) {
try {
const stat = await fs.stat(filePath);
return stat.isFile();
} catch {
return false;
}
}
async function cloneRepositoryWithoutGit(repoUrl, targetPath, branch) {
await fs.mkdir(targetPath, { recursive: true });
try {
const degitRepo = repoUrl.replace("https://github.com/", "");
const degitRepoWithBranch = branch ? `${degitRepo}#${branch}` : degitRepo;
const degitCommand = shellQuote.quote(["npx", "degit", degitRepoWithBranch, targetPath]);
await exec(degitCommand, {
cwd: process.cwd()
});
} catch {
try {
const gitArgs = ["git", "clone"];
if (branch) {
gitArgs.push("--branch", branch);
}
gitArgs.push(repoUrl, targetPath);
const gitCommand = shellQuote.quote(gitArgs);
await exec(gitCommand, {
cwd: process.cwd()
});
const gitDir = path.join(targetPath, ".git");
if (await directoryExists(gitDir)) {
await fs.rm(gitDir, { recursive: true, force: true });
}
} catch (gitError) {
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
}
}
}
async function updatePackageJson(projectPath, projectName) {
const packageJsonPath = path.join(projectPath, "package.json");
try {
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
const packageJson = JSON.parse(packageJsonContent);
packageJson.name = projectName;
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
} catch (error) {
logger.warn("Could not update package.json", { error: error instanceof Error ? error.message : "Unknown error" });
}
}
async function updateEnvFile(envPath, llmProvider) {
try {
const envContent = await fs.readFile(envPath, "utf-8");
const modelString = getModelIdentifier(llmProvider);
if (!modelString) {
logger.warn("Could not get model identifier for provider", { provider: llmProvider });
return;
}
const modelValue = modelString.replace(/'/g, "");
const updatedContent = envContent.replace(/^MODEL=.*/m, `MODEL=${modelValue}`);
await fs.writeFile(envPath, updatedContent, "utf-8");
logger.info("Updated MODEL in .env", { model: modelValue });
} catch (error) {
logger.warn("Could not update .env file", { error: error instanceof Error ? error.message : "Unknown error" });
}
}
async function installDependencies(projectPath, packageManager) {
const spinner4 = yoctoSpinner({ text: "Installing dependencies..." }).start();
try {
const pm = packageManager || getPackageManager();
const installCommand = shellQuote.quote([pm, "install"]);
await exec(installCommand, {
cwd: projectPath
});
spinner4.success("Dependencies installed successfully");
} catch (error) {
spinner4.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
async function loadTemplates() {
try {
const response = await fetch(TEMPLATES_API_URL);
if (!response.ok) {
throw new Error(`Failed to fetch templates: ${response.statusText}`);
}
const templates = await response.json();
return templates;
} catch (error) {
console.error("Error loading templates:", error);
throw new Error("Failed to load templates. Please check your internet connection and try again.");
}
}
function pluralize(count, singular, plural) {
return count === 1 ? singular : plural || `${singular}s`;
}
async function selectTemplate(templates) {
const choices = templates.map((template) => {
const parts = [];
if (template.agents?.length) {
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
}
if (template.tools?.length) {
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
}
if (template.workflows?.length) {
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
}
if (template.mcp?.length) {
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
}
if (template.networks?.length) {
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
}
return {
value: template,
label: template.title,
hint: parts.join(", ") || "Template components"
};
});
const selected = await p6.select({
message: "Select a template:",
options: choices
});
if (p6.isCancel(selected)) {
return null;
}
return selected;
}
function findTemplateByName(templates, templateName) {
let template = templates.find((t) => t.slug === templateName);
if (template) return template;
const slugWithPrefix = `template-${templateName}`;
template = templates.find((t) => t.slug === slugWithPrefix);
if (template) return template;
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
if (template) return template;
return null;
}
function getDefaultProjectName(template) {
return template.slug.replace(/^template-/, "");
}
async function resolveCurrentOrg(token, opts = {}) {
const orgs = await fetchOrgs(token);
if (orgs.length === 0) {
throw new Error("No organizations found.");
}
if (orgs.length === 1) {
return { orgId: orgs[0].id, orgName: orgs[0].name };
}
const envOrgId = process.env.MASTRA_ORG_ID;
if (envOrgId) {
const match = orgs.find((o) => o.id === envOrgId);
if (match) return { orgId: match.id, orgName: match.name };
}
const currentOrgId = await getCurrentOrgId();
if (!opts.forcePrompt && currentOrgId) {
const match = orgs.find((o) => o.id === currentOrgId);
if (match) return { orgId: match.id, orgName: match.name };
}
const selected = await p6.select({
message: "Select an organization",
initialValue: currentOrgId ?? void 0,
options: orgs.map((o) => ({
value: o.id,
label: `${o.name}${o.id === currentOrgId ? " (current)" : ""}`,
hint: o.id
}))
});
if (p6.isCancel(selected)) {
p6.cancel("Cancelled.");
process.exit(0);
}
const org = orgs.find((o) => o.id === selected);
if (org.id !== currentOrgId) {
await setCurrentOrgId(org.id);
}
return { orgId: org.id, orgName: org.name };
}
async function listOrgsAction() {
const token = await getToken();
const currentOrgId = await getCurrentOrgId();
const orgs = await fetchOrgs(token);
if (orgs.length === 0) {
console.info("\nNo organizations found.\n");
return;
}
console.info("\nOrganizations:\n");
for (const org of orgs) {
const marker = org.id === currentOrgId ? " (current)" : "";
const role = org.role ? ` [${org.role}]` : "";
console.info(` ${org.name}${role}${marker}`);
console.info(` ID: ${org.id}`);
}
console.info("");
}
async function switchOrgAction() {
if (process.env.MASTRA_API_TOKEN) {
console.error("\nCannot switch org when using MASTRA_API_TOKEN. Unset it and log in with: mastra auth login\n");
process.exit(1);
}
if (process.env.MASTRA_ORG_ID) {
console.error("\nCannot switch org when MASTRA_ORG_ID is set. Unset it to use persistent org selection.\n");
process.exit(1);
}
const token = await getToken();
const currentOrgId = await getCurrentOrgId();
const orgs = await fetchOrgs(token);
if (orgs.length === 0) {
console.info("\nNo organizations found.\n");
return;
}
if (orgs.length === 1) {
console.info(`
You only have one organization: ${orgs[0].name}
`);
return;
}
const selected = await p6.select({
message: "Switch to organization",
options: orgs.map((o) => ({
value: o.id,
label: `${o.name}${o.id === currentOrgId ? " (current)" : ""}`
}))
});
if (p6.isCancel(selected)) {
p6.cancel("Cancelled.");
process.exit(0);
}
await setCurrentOrgId(selected);
const org = orgs.find((o) => o.id === selected);
console.info(`
Switched to ${org.name} (${org.id})
`);
}
// src/commands/init/observability-provision.ts
var DEFAULT_PLATFORM_API_URL = "https://platform.mastra.ai";
async function provisionObservabilityProject({
defaultProjectName,
observabilityProject,
mode = "pick",
token: providedToken
} = {}) {
const token = providedToken ?? await getToken();
const { orgId, orgName } = mode === "create" ? await resolveCurrentOrg(token) : await resolveCurrentOrg(token, { forcePrompt: true });
let project;
if (observabilityProject) {
const projects = await listProjects(token, orgId);
const match = projects.find((proj) => proj.name === observabilityProject || proj.slug === observabilityProject);
if (match) {
project = match;
} else {
project = await createProjectByName({ token, orgId, name: observabilityProject });
}
} else if (mode === "create") {
if (!defaultProjectName) {
throw new Error('defaultProjectName is required when mode is "create"');
}
project = await createProjectByName({ token, orgId, name: defaultProjectName });
} else {
const projects = await listProjects(token, orgId);
if (projects.length === 0) {
project = await createProject({ token, orgId, defaultName: defaultProjectName, orgName });
} else {
const choice = await p6.select({
message: `Select a project (in ${orgName})`,
options: [
...projects.map((proj) => ({ value: proj.id, label: proj.name, hint: proj.slug })),
{ value: "__new__", label: "+ Create new project" }
]
});
if (p6.isCancel(choice)) {
throw new Error("Cancelled");
}
if (choice === "__new__") {
project = await createProject({ token, orgId, defaultName: defaultProjectName, orgName });
} else {
project = projects.find((proj) => proj.id === choice);
}
}
}
const secret = await mintOrgToken({
token,
orgId,
keyName: `mastra observability \u2013 ${project.name}`
});
const result = {
token: secret,
projectId: project.id,
projectSlug: project.slug,
projectName: project.name,
orgName
};
if (MASTRA_PLATFORM_API_URL !== DEFAULT_PLATFORM_API_URL) {
result.tracesEndpoint = deriveTracesEndpoint(MASTRA_PLATFORM_API_URL, project.id);
}
return result;
}
async function listProjects(token, orgId) {
const res = await platformFetch(`${MASTRA_PLATFORM_API_URL}/v1/studio/projects`, {
headers: authHeaders(token, orgId)
});
if (!res.ok) {
throw new Error(`Failed to list projects (${res.status})`);
}
const body = await res.json();
return body.projects;
}
async function createProject({
token,
orgId,
defaultName,
orgName
}) {
const name = await p6.text({
message: `New project name (in ${orgName})`,
placeholder: defaultName ?? "my-mastra-app",
defaultValue: defaultName,
validate: (v) => !v || v.trim().length === 0 ? "Name is required" : void 0
});
if (p6.isCancel(name)) {
throw new Error("Cancelled");
}
return createProjectByName({ token, orgId, name });
}
async function createProjectByName({
token,
orgId,
name
}) {
const res = await platformFetch(`${MASTRA_PLATFORM_API_URL}/v1/studio/projects`, {
method: "POST",
headers: { ...authHeaders(token, orgId), "Content-Type": "application/json" },
body: JSON.stringify({ name, studioEnabled: false, serverEnabled: false })
});
if (!res.ok) {
throw new Error(`Failed to create project (${res.status})`);
}
const body = await res.json();
return body.project;
}
async function mintOrgToken({
token,
orgId,
keyName
}) {
const res = await platformFetch(`${MASTRA_PLATFORM_API_URL}/v1/auth/tokens`, {
method: "POST",
headers: { ...authHeaders(token, orgId), "Content-Type": "application/json" },
body: JSON.stringify({ name: keyName })
});
if (!res.ok) {
throw new Error(`Failed to create access token (${res.status})`);
}
const body = await res.json();
return body.secret;
}
function deriveTracesEndpoint(platformUrl, projectId) {
const url = new URL(platformUrl);
return `${url.origin}/projects/${projectId}/ai/spans/publish`;
}
async function installMastraSkills({
directory,
agents
}) {
try {
const args = ["skills", "add", "mastra-ai/skills", "--agent", ...agents, "-y"];
await execa("npx", args, {
cwd: directory,
stdio: "pipe"
// Hide verbose output
});
return { success: true, agents };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
agents
};
}
}
// src/commands/init/init.ts
var s = p6.spinner();
var init = async ({
directory = "src/",
components,
llmProvider = "openai",
llmApiKey,
addExample = false,
skills,
mcpServer,
versionTag,
initGit = false,
observability,
observabilityProject,
observabilityMode = "pick",
observabilityToken
}) => {
s.start("Initializing Mastra");
const packageVersionTag = versionTag ? `@${versionTag}` : "";
try {
const result = await createMastraDir(directory);
if (!result.ok) {
s.stop(color.inverse(" Mastra already initialized "));
return { success: false };
}
const dirPath = result.dirPath;
await Promise.all([
writeIndexFile({
dirPath,
addExample,
addWorkflow: components.includes("workflows"),
addAgent: components.includes("agents"),
addScorers: components.includes("scorers")
}),
...components.map((component) => createComponentsDir(dirPath, component)),
writeAPIKey({ provider: llmProvider, apiKey: llmApiKey })
]);
if (addExample) {
await Promise.all([
...components.map(
(component) => writeCodeSample(dirPath, component, llmProvider, components)
)
]);
const depService = new DepsService();
const needsLibsql = await depService.checkDependencies(["@mastra/libsql"]) !== `ok`;
if (needsLibsql) {
await depService.installPackages([`@mastra/libsql${packageVersionTag}`]);
}
const needsDuckDB = await depService.checkDependencies(["@mastra/duckdb"]) !== `ok`;
if (needsDuckDB) {
await depService.installPackages([`@mastra/duckdb${packageVersionTag}`]);
}
const needsMemory = components.includes(`agents`) && await depService.checkDependencies(["@mastra/memory"]) !== `ok`;
if (needsMemory) {
await depService.installPackages([`@mastra/memory${packageVersionTag}`]);
}
const needsLoggers = await depService.checkDependencies(["@mastra/loggers"]) !== `ok`;
if (needsLoggers) {
await depService.installPackages([`@mastra/loggers${packageVersionTag}`]);
}
const needsObservability = await depService.checkDependencies(["@mastra/observability"]) !== `ok`;
if (needsObservability) {
await depService.installPackages([`@mastra/observability${packageVersionTag}`]);
}
const needsEvals = components.includes(`scorers`) && await depService.checkDependencies(["@mastra/evals"]) !== `ok`;
if (needsEvals) {
await depService.installPackages([`@mastra/evals${packageVersionTag}`]);
}
}
const key = await getAPIKey(llmProvider || "openai");
s.stop("Mastra initialized");
if (skills && skills.length > 0) {
try {
s.start("Installing Mastra agent skills");
const skillsResult = await installMastraSkills({
directory: process.cwd(),
agents: skills
});
if (skillsResult.success) {
const agentNames = skillsResult.agents.map((agent) => {
return agent.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
}).join(", ");
s.stop(`Mastra agent skills installed (in ${agentNames})`);
} else {
s.stop("Skills installation failed");
console.warn(color.yellow(`
Warning: ${skillsResult.error}`));
}
} catch (error) {
s.stop("Skills installation failed");
console.warn(color.yellow(`
Warning: ${error instanceof Error ? error.message : "Unknown error"}`));
}
}
if (mcpServer) {
await installMastraDocsMCPServer({
editor: mcpServer,
directory: process.cwd(),
versionTag
});
}
if (skills && skills.length > 0 || mcpServer) {
try {
await writeAgentsMarkdown({ skills, mcpServer });
const shouldWriteClaudeMd = skills?.includes("claude-code");
if (shouldWriteClaudeMd) {
await writeClaudeMarkdown();
}
} catch (error) {
console.warn(
color.yellow(
`
Warning: Failed to create agent guide files: ${error instanceof Error ? error.message : "Unknown error"}`
)
);
}
}
if (initGit) {
s.start("Initializing git repository");
try {
await gitInit({ cwd: process.cwd() });
s.stop("Git repository initialized");
} catch {
s.stop();
}
}
if (observability) {
try {
const defaultProjectName = await readPackageName();
const result2 = await provisionObservabilityProject({
defaultProjectName,
observabilityProject,
mode: observabilityMode,
token: observabilityToken
});
await writeObservabilityEnv({
token: result2.token,
projectId: result2.projectId,
endpoint: result2.tracesEndpoint
});
p6.note(
`${color.green("Mastra Observability enabled.")}
Project: ${color.cyan(result2.projectName)} (${result2.orgName})
Wrote ${color.cyan("MASTRA_PLATFORM_ACCESS_TOKEN")} and ${color.cyan("MASTRA_PROJECT_ID")} to ${color.cyan(".env")}.`
);
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown error";
try {
await writeObservabilityEnv();
} catch {
}
p6.note(
`${color.yellow("Could not connect this project to Mastra Observability automatically:")} ${message}
Empty ${color.cyan("MASTRA_PLATFORM_ACCESS_TOKEN")} and ${color.cyan("MASTRA_PROJECT_ID")} placeholders were added to your ${color.cyan(".env")} file.
1. Visit ${color.cyan("https://projects.mastra.ai")} to create a project and an access token.
2. Paste the token into ${color.cyan("MASTRA_PLATFORM_ACCESS_TOKEN")} and the project id into ${color.cyan("MASTRA_PROJECT_ID")}.`
);
}
}
if (!llmApiKey) {
p6.note(`
${color.green("Mastra initialized successfully!")}
Rename ${color.cyan(".env.example")} to ${color.cyan(".env")}
and add your ${color.cyan(key)}
`);
} else {
p6.note(`
${color.green("Mastra initialized successfully!")}
`);
}
return { success: true };
} catch (err) {
s.stop(color.inverse("An error occurred while initializing Mastra"));
console.error(err);
return { success: false };
}
};
var exec2 = util.promisify(child_process.exec);
var execWithTimeout = async (command, timeoutMs) => {
try {
const promise = exec2(command, { killSignal: "SIGTERM" });
if (!timeoutMs) {
return await promise;
}
let timeoutId;
const timeout = new Promise((_, reject) => {
timeoutId = setTimeout(() => reject(new Error("Command timed out")), timeoutMs);
});
try {
const result = await Promise.race([promise, timeout]);
clearTimeout(timeoutId);
return result;
} catch (error) {
clearTimeout(timeoutId);
if (error instanceof Error && error.message === "Command timed out") {
throw new Error("Something went wrong during installation, please try again.");
}
throw error;
}
} catch (error) {
throw error;
}
};
async function getInitCommand(pm) {
switch (pm) {
case "npm":
return "npm init -y";
case "pnpm":
return "pnpm init";
case "yarn":
return "yarn init -y";
case "bun":
return "bun init -y";
default:
return "npm init -y";
}
}
async function initializePackageJson(pm) {
const initCommand = await getInitCommand(pm);
await exec2(initCommand);
const packageJsonPath = path.join(process.cwd(), "package.json");
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
packageJson.type = "module";
packageJson.engines = {
...packageJson.engines,
node: ">=22.13.0"
};
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
}
var writeReadmeFile = async ({ dirPath, projectName }) => {
const packageManager = getPackageManager();
const readmePath = path.join(dirPath, "README.md");
const content = `# ${projectName}
Welcome to your new [Mastra](https://mastra.ai/) project! We're excited to see what you'll build.
## Getting Started
Start the development server:
\`\`\`shell
${packageManager} run dev
\`\`\`
Open [http://localhost:4111](http://localhost:4111) in your browser to access [Mastra Studio](https://mastra.ai/docs/studio/overview). It provides an interactive UI for building and testing your agents, along with a REST API that exposes your Mastra application as a local service. This lets you start building without worrying about integration right away.
You can start editing files inside the \`src/mastra\` directory. The development server will automatically reload whenever you make changes.
## Learn more
To learn more about Mastra, visit our [documentation](https://mastra.ai/docs/). Your bootstrapped project includes example code for [agents](https://mastra.ai/docs/agents/overview), [tools](https://mastra.ai/docs/agents/using-tools), [workflows](https://mastra.ai/docs/workflows/overview), [scorers](https://mastra.ai/docs/evals/overview), and [observability](https://mastra.ai/docs/observability/overview).
If you're new to AI agents, check out our [course](https://mastra.ai/learn) and [YouTube videos](https://youtube.com/@mastra-ai). You can also join our [Discord](https://discord.gg/BTYqqHKUrf) community to get help and share your projects.
## Deploy to the Mastra platform
The [Mastra platform](https://projects.mastra.ai) provides two products for deploying and managing AI applications built with the Mastra framework:
- **Studio**: A hosted visual environment for testing agents, running workflows, and inspecting traces
- **Server**: A production deployment target that runs your Mastra application as an API server
Learn more in the [Mastra platform documentation](https://mastra.ai/docs/mastra-platform/overview).`;
await fs.writeFile(readmePath, content);
};
async function installMastraDependencies(pm, dependencies, versionTag, isDev, timeout) {
let installCommand = getPackageManagerAddCommand(pm);
if (isDev) {
installCommand = `${installCommand} -D`;
}
const dependenciesWithVersion = dependencies.map((dependency) => `${dependency}${versionTag}`).join(" ");
try {
await execWithTimeout(`${pm} ${installCommand} ${dependenciesWithVersion}`, timeout);
} catch (err) {
if (versionTag === "@latest") {
throw new Error(
`Failed to install ${dependenciesWithVersion}: ${err instanceof Error ? err.message : "Unknown error"}`
);
}
const latestDependencies = dependencies.map((dependency) => `${dependency}@latest`).join(" ");
try {
await execWithTimeout(`${pm} ${installCommand} ${latestDependencies}`, timeout);
} catch (fallbackErr) {
throw new Error(
`Failed to install ${dependencies.join(", ")} (tried ${versionTag} and @latest): ${fallbackErr instanceof Error ? fallbackErr.message : "Unknown error"}`
);
}
}
}
var createMastraProject = async ({
projectName: name,
createVersionTag,
timeout,
llmProvider,
llmApiKey,
skills,
mcpServer,
observability,
needsInteractive,
onObservabilitySelected
}) => {
p6.intro(color.inverse(" Mastra Create "));
const projectName = name ?? await p6.text({
message: "What do you want to name your project?",
placeholder: "my-mastra-app",
validate: (value) => {
if (!value || value.length === 0) return "Project name cannot be empty";
if (fsSync.existsSync(value)) {
return `A directory named "${value}" already exists. Please choose a different name.`;
}
}
});
if (p6.isCancel(projectName)) {
p6.cancel("Operation cancelled");
process.exit(0);
}
let result = void 0;
if (needsInteractive) {
const skipGitInit = await isGitInitialized({ cwd: process.cwd() });
result = await interactivePrompt({
options: { command: "create", showBanner: false, onObservabilitySelected },
skip: {
llmProvider: llmProvider !== void 0,
llmApiKey: llmApiKey !== void 0,
skills: skills !== void 0 && skills.length > 0,
mcpServer: mcpServer !== void 0,
observability: observability !== void 0,
directory: true,
gitInit: skipGitInit
}
});
}
const s2 = p6.spinner();
const originalCwd = process.cwd();
let projectPath = null;
try {
s2.start("Creating project");
try {
await fs.mkdir(projectName);
projectPath = path.resolve(originalCwd, projectName);
} catch (error) {
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
s2.stop(`A directory named "${projectName}" already exists. Please choose a different name.`);
process.exit(1);
}
throw new Error(
`Failed to create project directory: ${error instanceof Error ? error.message : "Unknown error"}`
);
}
process.chdir(projectName);
const pm = getPackageManager();
const installCommand = getPackageManagerAddCommand(pm);
s2.message("Initializing project structure");
try {
await initializePackageJson(pm);
const depsService = new DepsService();
await depsService.addScriptsToPackageJson({
dev: "mastra dev",
build: "mastra build",
start: "mastra start"
});
await writeReadmeFile({ dirPath: process.cwd(), projectName });
} catch (error) {
throw new Error(
`Failed to initialize project structure: ${error instanceof Error ? error.message : "Unknown error"}`
);
}
s2.stop("Project structure created");
s2.start(`Installing ${pm} dependencies`);
try {
await exec2(`${pm} ${installCommand} zod@^4`);
await exec2(`${pm} ${installCommand} -D typescript @types/node`);
await exec2(`echo '{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "bundler",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"noEmit": true,
"outDir": "dist"
},
"include": [
"src/**/*"
]
}' > tsconfig.json`);
} catch (error) {
throw new Error(
`Failed to install basic dependencies: ${error instanceof Error ? error.message : "Unknown error"}`
);
}
s2.stop(`${pm} dependencies installed`);
s2.start("Installing Mastra CLI");
const versionTag = createVersionTag ? `@${createVersionTag}` : "@latest";
try {
await installMastraDependencies(pm, ["mastra"], versionTag, true, timeout);
} catch (error) {
throw new Error(`Failed to install Mastra CLI: ${error instanceof Error ? error.message : "Unknown error"}`);
}
s2.stop("Mastra CLI installed");
s2.start("Installing Mastra dependencies");
try {
await installMastraDependencies(
pm,
["@mastra/core", "@mastra/libsql", "@mastra/memory"],
versionTag,
false,
timeout
);
} catch (error) {
throw new Error(
`Failed to install Mastra dependencies: ${error instanceof Error ? error.message : "Unknown error"}`
);
}
s2.stop("Mastra dependencies installed");
s2.start("Adding .gitignore");
try {
await exec2(`echo output.txt >> .gitignore`);
await exec2(`echo node_modules >> .gitignore`);
await exec2(`echo dist >> .gitignore`);
await exec2(`echo .mastra >> .gitignore`);
await exec2(`echo .env.development >> .gitignore`);
await exec2(`echo .env >> .gitignore`);
await exec2(`echo *.db >> .gitignore`);
await exec2(`echo *.db-* >> .gitignore`);
await exec2(`echo .netlify >> .gitignore`);
await exec2(`echo .vercel >> .gitignore`);
} catch (error) {
throw new Error(`Failed to create .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`);
}
s2.stop(".gitignore added");
p6.outro("Project created successfully");
console.info("");
return { projectName, result };
} catch (error) {
s2.stop();
const errorMessage = error instanceof Error ? error.message : "An unexpected error occurred";
p6.cancel(`Project creation failed: ${errorMessage}`);
if (projectPath && fsSync.existsSync(projectPath)) {
try {
process.chdir(originalCwd);
await fs.rm(projectPath, { recursive: true, force: true });
} catch (cleanupError) {
console.error(
`Warning: Failed to clean up project directory: ${cleanupError instanceof Error ? cleanupError.message : "Unknown error"}`
);
}
}
process.exit(1);
}
};
// src/commands/create/create.ts
var version = package_default.version;
var create = async (args) => {
if (args.template !== void 0) {
await createFromTemplate({
projectName: args.projectName,
template: args.template,
timeout: args.timeout,
injectedAnalytics: args.analytics,
llmProvider: args.llmProvider
});
return;
}
const needsInteractive = args.components === void 0 || args.llmProvider === void 0 || args.addExample === void 0;
const directory = args.directory || "src/";
const { projectName, result } = await createMastraProject({
projectName: args?.projectName,
createVersionTag: args?.createVersionTag,
timeout: args?.timeout,
llmProvider: args?.llmProvider,
llmApiKey: args?.llmApiKey,
skills: args?.skills,
mcpServer: args?.mcpServer,
observability: args?.observability,
needsInteractive,
onObservabilitySelected: (event) => getAnalytics()?.trackEvent("cli_observability_selected", event)
});
if (needsInteractive && result) {
const analytics = getAnalytics();
if (analytics && result?.llmProvider) {
analytics.trackEvent("cli_model_provider_selected", {
provider: result.llmProvider,
selection_method: "interactive"
});
}
const interactiveComponents = ["agents", "tools", "workflows", "scorers"];
if (analytics) {
analytics.trackEvent("cli_components_selected", {
components: interactiveComponents,
selection_method: "interactive"
});
}
await init({
...result,
llmApiKey: result?.llmApiKey,
components: interactiveComponents,
addExample: true,
skills: result?.skills || args.skills,
mcpServer: result?.mcpServer || args.mcpServer,
versionTag: args.createVersionTag,
observability: args.observability ?? result?.observability,
observabilityProject: args.observabilityProject,
observabilityMode: "create",
observabilityToken: result?.observabilityToken
});
postCreate({ projectName });
return;
}
const { components = [], llmProvider = "openai", addExample = false, llmApiKey } = args;
const cliAnalytics = getAnalytics();
if (cliAnalytics) {
cliAnalytics.trackEvent("cli_model_provider_selected", {
provider: llmProvider,
selection_method: "cli_args"
});
cliAnalytics.trackEvent("cli_components_selected", {
components,
has_agents: components.includes("agents"),
has_tools: components.includes("tools"),
has_workflows: components.includes("workflows"),
has_scorers: components.includes("scorers"),
selection_method: "cli_args"
});
}
await init({
directory,
components,
llmProvider,
addExample,
llmApiKey,
skills: args.skills,
mcpServer: args.mcpServer,
versionTag: args.createVersionTag,
observability: args.observability,
observabilityProject: args.observabilityProject,
observabilityMode: "create"
});
postCreate({ projectName });
};
var postCreate = ({ projectName }) => {
const packageManager = getPackageManager();
p6.outro(`
${color.green("To start your project:")}
${color.cyan("cd")} ${projectName}
${color.cyan(`${packageManager} run dev`)}
`);
};
function isGitHubUrl(url) {
try {
const parsedUrl = new URL(url);
return parsedUrl.hostname === "github.com" && parsedUrl.pathname.split("/").length >= 3;
} catch {
return false;
}
}
async function validateGitHubProject(githubUrl) {
const errors = [];
try {
const urlParts = new URL(githubUrl).pathname.split("/").filter(Boolean);
const owner = urlParts[0];
const repo = urlParts[1]?.replace(".git", "");
if (!owner || !repo) {
throw new Error("Invalid GitHub URL format");
}
const branches = ["main", "master"];
let packageJsonContent = null;
let indexContent = null;
for (const branch of branches) {
try {
const packageJsonUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/package.json`;
const packageJsonResponse = await fetch(packageJsonUrl);
if (packageJsonResponse.ok) {
packageJsonContent = await packageJsonResponse.text();
const indexUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/src/mastra/index.ts`;
const indexResponse = await fetch(indexUrl);
if (indexResponse.ok) {
indexContent = await indexResponse.text();
}
break;
}
} catch {
}
}
if (!packageJsonContent) {
errors.push("Could not fetch package.json from repository");
return { isValid: false, errors };
}
try {
const packageJson = JSON.parse(packageJsonContent);
const hasMastraCore = packageJson.dependencies?.["@mastra/core"] || packageJson.devDependencies?.["@mastra/core"] || packageJson.peerDependencies?.["@mastra/core"];
if (!hasMastraCore) {
errors.push("Missing @mastra/core dependency in package.json");
}
} catch {
errors.push("Invalid package.json format");
}
if (!indexContent) {
errors.push("Missing src/mastra/index.ts file");
} else {
const hasMastraExport = indexContent.includes("export") && (indexContent.includes("new Mastra") || indexContent.includes("Mastra("));
if (!hasMastraExport) {
errors.push("src/mastra/index.ts does not export a Mastra instance");
}
}
return { isValid: errors.length === 0, errors };
} catch (error) {
errors.push(`Failed to validate GitHub repository: ${error instanceof Error ? error.message : "Unknown error"}`);
return { isValid: false, errors };
}
}
async function createFromGitHubUrl(url) {
const urlParts = new URL(url).pathname.split("/").filter(Boolean);
const owner = urlParts[0] || "unknown";
const repo = urlParts[1] || "unknown";
return {
githubUrl: url,
title: `${owner}/${repo}`,
slug: repo,
agents: [],
mcp: [],
tools: [],
networks: [],
workflows: []
};
}
async function createFromTemplate(args) {
let selectedTemplate;
if (args.template === true) {
const templates = await loadTemplates();
const selected = await selectTemplate(templates);
if (!selected) {
p6.log.info("No template selected. Exiting.");
return;
}
selectedTemplate = selected;
} else if (args.template && typeof args.template === "string") {
if (isGitHubUrl(args.template)) {
const spinner4 = p6.spinner();
spinner4.start("Validating GitHub repository...");
const validation = await validateGitHubProject(args.template);
if (!validation.isValid) {
spinner4.stop("Validation failed");
p6.log.error("This does not appear to be a valid Mastra project:");
validation.errors.forEach((error) => p6.log.error(` - ${error}`));
throw new Error("Invalid Mastra project");
}
spinner4.stop("Valid Mastra project \u2713");
selectedTemplate = await createFromGitHubUrl(args.template);
} else {
const templates = await loadTemplates();
const found = findTemplateByName(templates, args.template);
if (!found) {
p6.log.error(`Template "${args.template}" not found. Available templates:`);
templates.forEach((t) => p6.log.info(` - ${t.title} (use: ${t.slug.replace("template-", "")})`));
throw new Error(`Template "${args.template}" not found`);
}
selectedTemplate = found;
}
}
if (!selectedTemplate) {
throw new Error("No template selected");
}
let projectName = args.projectName;
if (!projectName) {
const defaultName = getDefaultProjectName(selectedTemplate);
const response = await p6.text({
message: "What is your project name?",
defaultValue: defaultName,
placeholder: defaultName
});
if (p6.isCancel(response)) {
p6.log.info("Project creation cancelled.");
return;
}
projectName = response;
}
let llmProvider = args.llmProvider;
if (!llmProvider) {
const providerResponse = await p6.select({
message: "Select a default provider:",
options: LLM_PROVIDERS
});
if (p6.isCancel(providerResponse)) {
p6.log.info("Project creation cancelled.");
return;
}
llmProvider = providerResponse;
}
let initGit = false;
const gitConfirmResult = await p6.confirm({
message: "Initialize a new git repository?",
initialValue: true
});
if (!p6.isCancel(gitConfirmResult)) {
initGit = gitConfirmResult;
}
let projectPath = null;
try {
const analytics = args.injectedAnalytics || getAnalytics();
if (analytics) {
analytics.trackEvent("cli_template_used", {
template_slug: selectedTemplate.slug,
template_title: selectedTemplate.title
});
if (llmProvider) {
analytics.trackEvent("cli_model_provider_selected", {
provider: llmProvider,
selection_method: args.llmProvider ? "cli_args" : "interactive"
});
}
}
const isBeta = version?.includes("beta") ?? false;
const isMastraTemplate = selectedTemplate.githubUrl.includes("github.com/mastra-ai/");
const branch = isBeta && isMastraTemplate ? "beta" : void 0;
projectPath = await cloneTemplate({
template: selectedTemplate,
projectName,
branch,
llmProvider
});
await installDependencies(projectPath);
if (initGit) {
const s2 = p6.spinner();
try {
s2.start("Initializing git repository");
await gitInit({ cwd: projectPath });
s2.stop("Git repository initialized");
} catch {
s2.stop();
}
}
p6.note(`
${color.green("Mastra template installed!")}
Add the necessary environment
variables in your ${color.cyan(".env")} file
`);
postCreate({ projectName });
} catch (error) {
if (projectPath) {
try {
if (fsSync.existsSync(projectPath)) {
await fs.rm(projectPath, { recursive: true, force: true });
}
} catch (cleanupError) {
console.error(
`Warning: Failed to clean up project directory: ${cleanupError instanceof Error ? cleanupError.message : "Unknown error"}`
);
}
}
p6.log.error(`Failed to create project from template: ${error instanceof Error ? error.message : "Unknown error"}`);
throw error;
}
}
export { create, createLogger, init, listOrgsAction, logger, package_default, resolveCurrentOrg, switchOrgAction };
//# sourceMappingURL=chunk-BXHVOPMR.js.map
//# sourceMappingURL=chunk-BXHVOPMR.js.map