create-mastra 0.10.13-alpha.1 → 0.10.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1216,10 +1216,10 @@ var exec = util.promisify(child_process.exec);
1216
1216
  async function cloneTemplate(options) {
1217
1217
  const { template, projectName, targetDir } = options;
1218
1218
  const projectPath = targetDir ? path3.resolve(targetDir, projectName) : path3.resolve(projectName);
1219
- const spinner4 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
1219
+ const spinner5 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
1220
1220
  try {
1221
1221
  if (await directoryExists(projectPath)) {
1222
- spinner4.error(`Directory ${projectName} already exists`);
1222
+ spinner5.error(`Directory ${projectName} already exists`);
1223
1223
  throw new Error(`Directory ${projectName} already exists`);
1224
1224
  }
1225
1225
  await cloneRepositoryWithoutGit(template.githubUrl, projectPath);
@@ -1228,10 +1228,10 @@ async function cloneTemplate(options) {
1228
1228
  if (await fileExists(envExamplePath)) {
1229
1229
  await fs.copyFile(envExamplePath, path3.join(projectPath, ".env"));
1230
1230
  }
1231
- spinner4.success(`Template "${template.title}" cloned successfully to ${projectName}`);
1231
+ spinner5.success(`Template "${template.title}" cloned successfully to ${projectName}`);
1232
1232
  return projectPath;
1233
1233
  } catch (error) {
1234
- spinner4.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
1234
+ spinner5.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
1235
1235
  throw error;
1236
1236
  }
1237
1237
  }
@@ -1286,16 +1286,16 @@ async function updatePackageJson(projectPath, projectName) {
1286
1286
  }
1287
1287
  }
1288
1288
  async function installDependencies(projectPath, packageManager) {
1289
- const spinner4 = yoctoSpinner({ text: "Installing dependencies..." }).start();
1289
+ const spinner5 = yoctoSpinner({ text: "Installing dependencies..." }).start();
1290
1290
  try {
1291
1291
  const pm = packageManager || getPackageManager();
1292
1292
  const installCommand = shellQuote.quote([pm, "install"]);
1293
1293
  await exec(installCommand, {
1294
1294
  cwd: projectPath
1295
1295
  });
1296
- spinner4.success("Dependencies installed successfully");
1296
+ spinner5.success("Dependencies installed successfully");
1297
1297
  } catch (error) {
1298
- spinner4.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
1298
+ spinner5.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
1299
1299
  throw error;
1300
1300
  }
1301
1301
  }
@@ -2474,21 +2474,116 @@ var postCreate = ({ projectName }) => {
2474
2474
  ${color2.cyan(`${packageManager} run dev`)}
2475
2475
  `);
2476
2476
  };
2477
+ function isGitHubUrl(url) {
2478
+ try {
2479
+ const parsedUrl = new URL(url);
2480
+ return parsedUrl.hostname === "github.com" && parsedUrl.pathname.split("/").length >= 3;
2481
+ } catch {
2482
+ return false;
2483
+ }
2484
+ }
2485
+ async function validateGitHubProject(githubUrl) {
2486
+ const errors = [];
2487
+ try {
2488
+ const urlParts = new URL(githubUrl).pathname.split("/").filter(Boolean);
2489
+ const owner = urlParts[0];
2490
+ const repo = urlParts[1]?.replace(".git", "");
2491
+ if (!owner || !repo) {
2492
+ throw new Error("Invalid GitHub URL format");
2493
+ }
2494
+ const branches = ["main", "master"];
2495
+ let packageJsonContent = null;
2496
+ let indexContent = null;
2497
+ for (const branch of branches) {
2498
+ try {
2499
+ const packageJsonUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/package.json`;
2500
+ const packageJsonResponse = await fetch(packageJsonUrl);
2501
+ if (packageJsonResponse.ok) {
2502
+ packageJsonContent = await packageJsonResponse.text();
2503
+ const indexUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/src/mastra/index.ts`;
2504
+ const indexResponse = await fetch(indexUrl);
2505
+ if (indexResponse.ok) {
2506
+ indexContent = await indexResponse.text();
2507
+ }
2508
+ break;
2509
+ }
2510
+ } catch {
2511
+ }
2512
+ }
2513
+ if (!packageJsonContent) {
2514
+ errors.push("Could not fetch package.json from repository");
2515
+ return { isValid: false, errors };
2516
+ }
2517
+ try {
2518
+ const packageJson = JSON.parse(packageJsonContent);
2519
+ const hasMastraCore = packageJson.dependencies?.["@mastra/core"] || packageJson.devDependencies?.["@mastra/core"] || packageJson.peerDependencies?.["@mastra/core"];
2520
+ if (!hasMastraCore) {
2521
+ errors.push("Missing @mastra/core dependency in package.json");
2522
+ }
2523
+ } catch {
2524
+ errors.push("Invalid package.json format");
2525
+ }
2526
+ if (!indexContent) {
2527
+ errors.push("Missing src/mastra/index.ts file");
2528
+ } else {
2529
+ const hasMastraExport = indexContent.includes("export") && (indexContent.includes("new Mastra") || indexContent.includes("Mastra("));
2530
+ if (!hasMastraExport) {
2531
+ errors.push("src/mastra/index.ts does not export a Mastra instance");
2532
+ }
2533
+ }
2534
+ return { isValid: errors.length === 0, errors };
2535
+ } catch (error) {
2536
+ errors.push(`Failed to validate GitHub repository: ${error instanceof Error ? error.message : "Unknown error"}`);
2537
+ return { isValid: false, errors };
2538
+ }
2539
+ }
2540
+ async function createFromGitHubUrl(url) {
2541
+ const urlParts = new URL(url).pathname.split("/").filter(Boolean);
2542
+ const owner = urlParts[0] || "unknown";
2543
+ const repo = urlParts[1] || "unknown";
2544
+ return {
2545
+ githubUrl: url,
2546
+ title: `${owner}/${repo}`,
2547
+ slug: repo,
2548
+ agents: [],
2549
+ mcp: [],
2550
+ tools: [],
2551
+ networks: [],
2552
+ workflows: []
2553
+ };
2554
+ }
2477
2555
  async function createFromTemplate(args2) {
2478
- const templates = await loadTemplates();
2479
2556
  let selectedTemplate;
2480
2557
  if (args2.template === true) {
2481
- selectedTemplate = await selectTemplate(templates);
2482
- if (!selectedTemplate) {
2558
+ const templates = await loadTemplates();
2559
+ const selected = await selectTemplate(templates);
2560
+ if (!selected) {
2483
2561
  M.info("No template selected. Exiting.");
2484
2562
  return;
2485
2563
  }
2486
- } else if (args2.template) {
2487
- selectedTemplate = findTemplateByName(templates, args2.template);
2488
- if (!selectedTemplate) {
2489
- M.error(`Template "${args2.template}" not found. Available templates:`);
2490
- templates.forEach((t) => M.info(` - ${t.title} (use: ${t.slug.replace("template-", "")})`));
2491
- throw new Error(`Template "${args2.template}" not found`);
2564
+ selectedTemplate = selected;
2565
+ } else if (args2.template && typeof args2.template === "string") {
2566
+ if (isGitHubUrl(args2.template)) {
2567
+ const spinner5 = Y();
2568
+ spinner5.start("Validating GitHub repository...");
2569
+ const validation = await validateGitHubProject(args2.template);
2570
+ if (!validation.isValid) {
2571
+ spinner5.stop("Validation failed");
2572
+ M.error("This does not appear to be a valid Mastra project:");
2573
+ validation.errors.forEach((error) => M.error(` - ${error}`));
2574
+ throw new Error("Invalid Mastra project");
2575
+ }
2576
+ spinner5.stop("Valid Mastra project \u2713");
2577
+ selectedTemplate = await createFromGitHubUrl(args2.template);
2578
+ } else {
2579
+ const templates = await loadTemplates();
2580
+ const found = findTemplateByName(templates, args2.template);
2581
+ if (!found) {
2582
+ M.error(`Template "${args2.template}" not found. Available templates:`);
2583
+ templates.forEach((t) => M.info(` - ${t.title} (use: ${t.slug.replace("template-", "")})`));
2584
+ throw new Error(`Template "${args2.template}" not found`);
2585
+ }
2586
+ selectedTemplate = found;
2492
2587
  }
2493
2588
  }
2494
2589
  if (!selectedTemplate) {
@@ -2572,7 +2667,7 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
2572
2667
  "Project name that will be used in package.json and as the project directory name."
2573
2668
  ).option("--default", "Quick start with defaults(src, OpenAI, examples)").option("-c, --components <components>", "Comma-separated list of components (agents, tools, workflows)").option("-l, --llm <model-provider>", "Default model provider (openai, anthropic, groq, google, or cerebras)").option("-k, --llm-api-key <api-key>", "API key for the model provider").option("-e, --example", "Include example code").option("-n, --no-example", "Do not include example code").option("-t, --timeout [timeout]", "Configurable timeout for package installation, defaults to 60000 ms").option("-d, --dir <directory>", "Target directory for Mastra source code (default: src/)").option("-m, --mcp <mcp>", "MCP Server for code editor (cursor, cursor-global, windsurf, vscode)").option(
2574
2669
  "--template [template-name]",
2575
- "Create project from a template (use template name or leave blank to select from list)"
2670
+ "Create project from a template (use template name, public GitHub URL, or leave blank to select from list)"
2576
2671
  ).action(async (projectNameArg, args) => {
2577
2672
  const projectName = projectNameArg || args.projectName;
2578
2673
  const timeout = args?.timeout ? args?.timeout === true ? 6e4 : parseInt(args?.timeout, 10) : void 0;