UNPKG

mastra

Version:
1,325 lines (1,300 loc) • 45.7 kB
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