create-mastra 0.0.0-working-memory-per-user-20250620163010 → 0.0.0-zod-v4-compat-part-2-20250820135355
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/LICENSE.md +11 -42
- package/dist/index.js +501 -174
- package/dist/index.js.map +1 -1
- package/dist/starter-files/config.d.ts +26 -0
- package/dist/starter-files/config.d.ts.map +1 -0
- package/dist/starter-files/tools.d.ts +79 -0
- package/dist/starter-files/tools.d.ts.map +1 -0
- package/dist/templates/dev.entry.d.ts +2 -0
- package/dist/templates/dev.entry.d.ts.map +1 -0
- package/dist/templates/dev.entry.js +7 -2
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import * as
|
|
5
|
-
import
|
|
4
|
+
import * as fs4__default from 'node:fs';
|
|
5
|
+
import fs4__default__default, { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
6
|
import os from 'node:os';
|
|
7
|
-
import
|
|
7
|
+
import path3, { dirname } from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { PostHog } from 'posthog-node';
|
|
10
10
|
import util, { stripVTControlCharacters } from 'node:util';
|
|
@@ -12,18 +12,22 @@ import y$1, { stdout, stdin } from 'node:process';
|
|
|
12
12
|
import * as g from 'node:readline';
|
|
13
13
|
import g__default from 'node:readline';
|
|
14
14
|
import { Writable } from 'node:stream';
|
|
15
|
+
import fs from 'node:fs/promises';
|
|
15
16
|
import child_process from 'node:child_process';
|
|
16
|
-
import fs4 from 'node:fs/promises';
|
|
17
|
-
import { execa } from 'execa';
|
|
18
|
-
import fsExtra3, { readJSON, ensureFile, writeJSON } from 'fs-extra/esm';
|
|
19
|
-
import prettier from 'prettier';
|
|
20
17
|
import tty from 'node:tty';
|
|
21
18
|
import pino from 'pino';
|
|
22
19
|
import pretty from 'pino-pretty';
|
|
20
|
+
import { execa } from 'execa';
|
|
21
|
+
import fsExtra3, { readJSON, ensureFile, writeJSON } from 'fs-extra/esm';
|
|
22
|
+
import prettier from 'prettier';
|
|
23
23
|
import fsExtra from 'fs-extra';
|
|
24
24
|
|
|
25
25
|
var __filename = fileURLToPath(import.meta.url);
|
|
26
|
-
var __dirname =
|
|
26
|
+
var __dirname = path3.dirname(__filename);
|
|
27
|
+
var analyticsInstance = null;
|
|
28
|
+
function getAnalytics() {
|
|
29
|
+
return analyticsInstance;
|
|
30
|
+
}
|
|
27
31
|
var PosthogAnalytics = class {
|
|
28
32
|
sessionId;
|
|
29
33
|
client;
|
|
@@ -35,7 +39,7 @@ var PosthogAnalytics = class {
|
|
|
35
39
|
host = "https://app.posthog.com"
|
|
36
40
|
}) {
|
|
37
41
|
this.version = version;
|
|
38
|
-
const cliConfigPath =
|
|
42
|
+
const cliConfigPath = path3.join(__dirname, "mastra-cli.json");
|
|
39
43
|
if (existsSync(cliConfigPath)) {
|
|
40
44
|
try {
|
|
41
45
|
const { distinctId, sessionId } = JSON.parse(readFileSync(cliConfigPath, "utf-8"));
|
|
@@ -63,7 +67,7 @@ var PosthogAnalytics = class {
|
|
|
63
67
|
}
|
|
64
68
|
writeCliConfig({ distinctId, sessionId }) {
|
|
65
69
|
try {
|
|
66
|
-
writeFileSync(
|
|
70
|
+
writeFileSync(path3.join(__dirname, "mastra-cli.json"), JSON.stringify({ distinctId, sessionId }));
|
|
67
71
|
} catch {
|
|
68
72
|
}
|
|
69
73
|
}
|
|
@@ -113,6 +117,22 @@ var PosthogAnalytics = class {
|
|
|
113
117
|
}
|
|
114
118
|
});
|
|
115
119
|
}
|
|
120
|
+
trackEvent(eventName, properties) {
|
|
121
|
+
try {
|
|
122
|
+
if (!this.client) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
this.client.capture({
|
|
126
|
+
distinctId: this.distinctId,
|
|
127
|
+
event: eventName,
|
|
128
|
+
properties: {
|
|
129
|
+
...this.getSystemProperties(),
|
|
130
|
+
...properties
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
}
|
|
116
136
|
trackCommand(options) {
|
|
117
137
|
try {
|
|
118
138
|
if (!this.client) {
|
|
@@ -1125,9 +1145,7 @@ var PinoLogger = class extends MastraLogger {
|
|
|
1125
1145
|
{
|
|
1126
1146
|
name: options.name || "app",
|
|
1127
1147
|
level: options.level || LogLevel.INFO,
|
|
1128
|
-
formatters:
|
|
1129
|
-
level: (label) => ({ level: label })
|
|
1130
|
-
}
|
|
1148
|
+
formatters: options.formatters
|
|
1131
1149
|
},
|
|
1132
1150
|
options.overrideDefaultTransports ? options?.transports?.default : transportsAry.length === 0 ? prettyStream : pino.multistream([
|
|
1133
1151
|
...transportsAry.map(([, transport]) => ({
|
|
@@ -1155,6 +1173,195 @@ var PinoLogger = class extends MastraLogger {
|
|
|
1155
1173
|
}
|
|
1156
1174
|
};
|
|
1157
1175
|
|
|
1176
|
+
function getPackageManager() {
|
|
1177
|
+
const userAgent = process.env.npm_config_user_agent || "";
|
|
1178
|
+
const execPath = process.env.npm_execpath || "";
|
|
1179
|
+
if (userAgent.includes("yarn")) {
|
|
1180
|
+
return "yarn";
|
|
1181
|
+
}
|
|
1182
|
+
if (userAgent.includes("pnpm")) {
|
|
1183
|
+
return "pnpm";
|
|
1184
|
+
}
|
|
1185
|
+
if (userAgent.includes("npm")) {
|
|
1186
|
+
return "npm";
|
|
1187
|
+
}
|
|
1188
|
+
if (execPath.includes("yarn")) {
|
|
1189
|
+
return "yarn";
|
|
1190
|
+
}
|
|
1191
|
+
if (execPath.includes("pnpm")) {
|
|
1192
|
+
return "pnpm";
|
|
1193
|
+
}
|
|
1194
|
+
if (execPath.includes("npm")) {
|
|
1195
|
+
return "npm";
|
|
1196
|
+
}
|
|
1197
|
+
return "npm";
|
|
1198
|
+
}
|
|
1199
|
+
function getPackageManagerInstallCommand(pm) {
|
|
1200
|
+
switch (pm) {
|
|
1201
|
+
case "npm":
|
|
1202
|
+
return "install";
|
|
1203
|
+
case "yarn":
|
|
1204
|
+
return "add";
|
|
1205
|
+
case "pnpm":
|
|
1206
|
+
return "add";
|
|
1207
|
+
default:
|
|
1208
|
+
return "install";
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
var logger = new PinoLogger({
|
|
1212
|
+
name: "Mastra CLI",
|
|
1213
|
+
level: "info"
|
|
1214
|
+
});
|
|
1215
|
+
var exec = util.promisify(child_process.exec);
|
|
1216
|
+
async function cloneTemplate(options) {
|
|
1217
|
+
const { template, projectName, targetDir } = options;
|
|
1218
|
+
const projectPath = targetDir ? path3.resolve(targetDir, projectName) : path3.resolve(projectName);
|
|
1219
|
+
const spinner5 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
|
|
1220
|
+
try {
|
|
1221
|
+
if (await directoryExists(projectPath)) {
|
|
1222
|
+
spinner5.error(`Directory ${projectName} already exists`);
|
|
1223
|
+
throw new Error(`Directory ${projectName} already exists`);
|
|
1224
|
+
}
|
|
1225
|
+
await cloneRepositoryWithoutGit(template.githubUrl, projectPath);
|
|
1226
|
+
await updatePackageJson(projectPath, projectName);
|
|
1227
|
+
const envExamplePath = path3.join(projectPath, ".env.example");
|
|
1228
|
+
if (await fileExists(envExamplePath)) {
|
|
1229
|
+
await fs.copyFile(envExamplePath, path3.join(projectPath, ".env"));
|
|
1230
|
+
}
|
|
1231
|
+
spinner5.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
1232
|
+
return projectPath;
|
|
1233
|
+
} catch (error) {
|
|
1234
|
+
spinner5.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1235
|
+
throw error;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
async function directoryExists(dirPath) {
|
|
1239
|
+
try {
|
|
1240
|
+
const stat = await fs.stat(dirPath);
|
|
1241
|
+
return stat.isDirectory();
|
|
1242
|
+
} catch {
|
|
1243
|
+
return false;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
async function fileExists(filePath) {
|
|
1247
|
+
try {
|
|
1248
|
+
const stat = await fs.stat(filePath);
|
|
1249
|
+
return stat.isFile();
|
|
1250
|
+
} catch {
|
|
1251
|
+
return false;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
async function cloneRepositoryWithoutGit(repoUrl, targetPath) {
|
|
1255
|
+
await fs.mkdir(targetPath, { recursive: true });
|
|
1256
|
+
try {
|
|
1257
|
+
const degitRepo = repoUrl.replace("https://github.com/", "");
|
|
1258
|
+
const degitCommand = shellQuote.quote(["npx", "degit", degitRepo, targetPath]);
|
|
1259
|
+
await exec(degitCommand, {
|
|
1260
|
+
cwd: process.cwd()
|
|
1261
|
+
});
|
|
1262
|
+
} catch {
|
|
1263
|
+
try {
|
|
1264
|
+
const gitCommand = shellQuote.quote(["git", "clone", repoUrl, targetPath]);
|
|
1265
|
+
await exec(gitCommand, {
|
|
1266
|
+
cwd: process.cwd()
|
|
1267
|
+
});
|
|
1268
|
+
const gitDir = path3.join(targetPath, ".git");
|
|
1269
|
+
if (await directoryExists(gitDir)) {
|
|
1270
|
+
await fs.rm(gitDir, { recursive: true, force: true });
|
|
1271
|
+
}
|
|
1272
|
+
} catch (gitError) {
|
|
1273
|
+
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
async function updatePackageJson(projectPath, projectName) {
|
|
1278
|
+
const packageJsonPath = path3.join(projectPath, "package.json");
|
|
1279
|
+
try {
|
|
1280
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
1281
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
1282
|
+
packageJson.name = projectName;
|
|
1283
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
1284
|
+
} catch (error) {
|
|
1285
|
+
logger.warn(`Could not update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
async function installDependencies(projectPath, packageManager) {
|
|
1289
|
+
const spinner5 = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
1290
|
+
try {
|
|
1291
|
+
const pm = packageManager || getPackageManager();
|
|
1292
|
+
const installCommand = shellQuote.quote([pm, "install"]);
|
|
1293
|
+
await exec(installCommand, {
|
|
1294
|
+
cwd: projectPath
|
|
1295
|
+
});
|
|
1296
|
+
spinner5.success("Dependencies installed successfully");
|
|
1297
|
+
} catch (error) {
|
|
1298
|
+
spinner5.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1299
|
+
throw error;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
|
|
1303
|
+
async function loadTemplates() {
|
|
1304
|
+
try {
|
|
1305
|
+
const response = await fetch(TEMPLATES_API_URL);
|
|
1306
|
+
if (!response.ok) {
|
|
1307
|
+
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
1308
|
+
}
|
|
1309
|
+
const templates = await response.json();
|
|
1310
|
+
return templates;
|
|
1311
|
+
} catch (error) {
|
|
1312
|
+
console.error("Error loading templates:", error);
|
|
1313
|
+
throw new Error("Failed to load templates. Please check your internet connection and try again.");
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
function pluralize(count, singular, plural) {
|
|
1317
|
+
return count === 1 ? singular : plural || `${singular}s`;
|
|
1318
|
+
}
|
|
1319
|
+
async function selectTemplate(templates) {
|
|
1320
|
+
const choices = templates.map((template) => {
|
|
1321
|
+
const parts = [];
|
|
1322
|
+
if (template.agents?.length) {
|
|
1323
|
+
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
|
|
1324
|
+
}
|
|
1325
|
+
if (template.tools?.length) {
|
|
1326
|
+
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
|
|
1327
|
+
}
|
|
1328
|
+
if (template.workflows?.length) {
|
|
1329
|
+
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
|
|
1330
|
+
}
|
|
1331
|
+
if (template.mcp?.length) {
|
|
1332
|
+
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
|
|
1333
|
+
}
|
|
1334
|
+
if (template.networks?.length) {
|
|
1335
|
+
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
|
|
1336
|
+
}
|
|
1337
|
+
return {
|
|
1338
|
+
value: template,
|
|
1339
|
+
label: template.title,
|
|
1340
|
+
hint: parts.join(", ") || "Template components"
|
|
1341
|
+
};
|
|
1342
|
+
});
|
|
1343
|
+
const selected = await ve({
|
|
1344
|
+
message: "Select a template:",
|
|
1345
|
+
options: choices
|
|
1346
|
+
});
|
|
1347
|
+
if (pD(selected)) {
|
|
1348
|
+
return null;
|
|
1349
|
+
}
|
|
1350
|
+
return selected;
|
|
1351
|
+
}
|
|
1352
|
+
function findTemplateByName(templates, templateName) {
|
|
1353
|
+
let template = templates.find((t) => t.slug === templateName);
|
|
1354
|
+
if (template) return template;
|
|
1355
|
+
const slugWithPrefix = `template-${templateName}`;
|
|
1356
|
+
template = templates.find((t) => t.slug === slugWithPrefix);
|
|
1357
|
+
if (template) return template;
|
|
1358
|
+
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
|
|
1359
|
+
if (template) return template;
|
|
1360
|
+
return null;
|
|
1361
|
+
}
|
|
1362
|
+
function getDefaultProjectName(template) {
|
|
1363
|
+
return template.slug.replace(/^template-/, "");
|
|
1364
|
+
}
|
|
1158
1365
|
var DepsService = class {
|
|
1159
1366
|
packageManager;
|
|
1160
1367
|
constructor() {
|
|
@@ -1163,11 +1370,11 @@ var DepsService = class {
|
|
|
1163
1370
|
findLockFile(dir) {
|
|
1164
1371
|
const lockFiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock"];
|
|
1165
1372
|
for (const file of lockFiles) {
|
|
1166
|
-
if (
|
|
1373
|
+
if (fs4__default__default.existsSync(path3.join(dir, file))) {
|
|
1167
1374
|
return file;
|
|
1168
1375
|
}
|
|
1169
1376
|
}
|
|
1170
|
-
const parentDir =
|
|
1377
|
+
const parentDir = path3.resolve(dir, "..");
|
|
1171
1378
|
if (parentDir !== dir) {
|
|
1172
1379
|
return this.findLockFile(parentDir);
|
|
1173
1380
|
}
|
|
@@ -1204,13 +1411,13 @@ var DepsService = class {
|
|
|
1204
1411
|
}
|
|
1205
1412
|
async checkDependencies(dependencies) {
|
|
1206
1413
|
try {
|
|
1207
|
-
const packageJsonPath =
|
|
1414
|
+
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1208
1415
|
try {
|
|
1209
|
-
await
|
|
1416
|
+
await fs.access(packageJsonPath);
|
|
1210
1417
|
} catch {
|
|
1211
1418
|
return "No package.json file found in the current directory";
|
|
1212
1419
|
}
|
|
1213
|
-
const packageJson = JSON.parse(await
|
|
1420
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
|
|
1214
1421
|
for (const dependency of dependencies) {
|
|
1215
1422
|
if (!packageJson.dependencies || !packageJson.dependencies[dependency]) {
|
|
1216
1423
|
return `Please install ${dependency} before running this command (${this.packageManager} install ${dependency})`;
|
|
@@ -1224,8 +1431,8 @@ var DepsService = class {
|
|
|
1224
1431
|
}
|
|
1225
1432
|
async getProjectName() {
|
|
1226
1433
|
try {
|
|
1227
|
-
const packageJsonPath =
|
|
1228
|
-
const packageJson = await
|
|
1434
|
+
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1435
|
+
const packageJson = await fs.readFile(packageJsonPath, "utf-8");
|
|
1229
1436
|
const pkg = JSON.parse(packageJson);
|
|
1230
1437
|
return pkg.name;
|
|
1231
1438
|
} catch (err) {
|
|
@@ -1235,54 +1442,19 @@ var DepsService = class {
|
|
|
1235
1442
|
async getPackageVersion() {
|
|
1236
1443
|
const __filename = fileURLToPath(import.meta.url);
|
|
1237
1444
|
const __dirname = dirname(__filename);
|
|
1238
|
-
const pkgJsonPath =
|
|
1445
|
+
const pkgJsonPath = path3.join(__dirname, "..", "package.json");
|
|
1239
1446
|
const content = await fsExtra3.readJSON(pkgJsonPath);
|
|
1240
1447
|
return content.version;
|
|
1241
1448
|
}
|
|
1242
1449
|
async addScriptsToPackageJson(scripts) {
|
|
1243
|
-
const packageJson = JSON.parse(await
|
|
1450
|
+
const packageJson = JSON.parse(await fs.readFile("package.json", "utf-8"));
|
|
1244
1451
|
packageJson.scripts = {
|
|
1245
1452
|
...packageJson.scripts,
|
|
1246
1453
|
...scripts
|
|
1247
1454
|
};
|
|
1248
|
-
await
|
|
1455
|
+
await fs.writeFile("package.json", JSON.stringify(packageJson, null, 2));
|
|
1249
1456
|
}
|
|
1250
1457
|
};
|
|
1251
|
-
function getPackageManager() {
|
|
1252
|
-
const userAgent = process.env.npm_config_user_agent || "";
|
|
1253
|
-
const execPath = process.env.npm_execpath || "";
|
|
1254
|
-
if (userAgent.includes("yarn")) {
|
|
1255
|
-
return "yarn";
|
|
1256
|
-
}
|
|
1257
|
-
if (userAgent.includes("pnpm")) {
|
|
1258
|
-
return "pnpm";
|
|
1259
|
-
}
|
|
1260
|
-
if (userAgent.includes("npm")) {
|
|
1261
|
-
return "npm";
|
|
1262
|
-
}
|
|
1263
|
-
if (execPath.includes("yarn")) {
|
|
1264
|
-
return "yarn";
|
|
1265
|
-
}
|
|
1266
|
-
if (execPath.includes("pnpm")) {
|
|
1267
|
-
return "pnpm";
|
|
1268
|
-
}
|
|
1269
|
-
if (execPath.includes("npm")) {
|
|
1270
|
-
return "npm";
|
|
1271
|
-
}
|
|
1272
|
-
return "npm";
|
|
1273
|
-
}
|
|
1274
|
-
function getPackageManagerInstallCommand(pm) {
|
|
1275
|
-
switch (pm) {
|
|
1276
|
-
case "npm":
|
|
1277
|
-
return "install";
|
|
1278
|
-
case "yarn":
|
|
1279
|
-
return "add";
|
|
1280
|
-
case "pnpm":
|
|
1281
|
-
return "add";
|
|
1282
|
-
default:
|
|
1283
|
-
return "install";
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
1458
|
var args = ["-y", "@mastra/mcp-docs-server"];
|
|
1287
1459
|
var createMcpConfig = (editor) => {
|
|
1288
1460
|
if (editor === "vscode") {
|
|
@@ -1335,19 +1507,19 @@ async function writeMergedConfig(configPath, editor) {
|
|
|
1335
1507
|
spaces: 2
|
|
1336
1508
|
});
|
|
1337
1509
|
}
|
|
1338
|
-
var windsurfGlobalMCPConfigPath =
|
|
1339
|
-
var cursorGlobalMCPConfigPath =
|
|
1340
|
-
|
|
1341
|
-
var vscodeGlobalMCPConfigPath =
|
|
1510
|
+
var windsurfGlobalMCPConfigPath = path3.join(os.homedir(), ".codeium", "windsurf", "mcp_config.json");
|
|
1511
|
+
var cursorGlobalMCPConfigPath = path3.join(os.homedir(), ".cursor", "mcp.json");
|
|
1512
|
+
path3.join(process.cwd(), ".vscode", "mcp.json");
|
|
1513
|
+
var vscodeGlobalMCPConfigPath = path3.join(
|
|
1342
1514
|
os.homedir(),
|
|
1343
|
-
process.platform === "win32" ?
|
|
1515
|
+
process.platform === "win32" ? path3.join("AppData", "Roaming", "Code", "User", "settings.json") : process.platform === "darwin" ? path3.join("Library", "Application Support", "Code", "User", "settings.json") : path3.join(".config", "Code", "User", "settings.json")
|
|
1344
1516
|
);
|
|
1345
1517
|
async function installMastraDocsMCPServer({ editor, directory }) {
|
|
1346
1518
|
if (editor === `cursor`) {
|
|
1347
|
-
await writeMergedConfig(
|
|
1519
|
+
await writeMergedConfig(path3.join(directory, ".cursor", "mcp.json"), "cursor");
|
|
1348
1520
|
}
|
|
1349
1521
|
if (editor === `vscode`) {
|
|
1350
|
-
await writeMergedConfig(
|
|
1522
|
+
await writeMergedConfig(path3.join(directory, ".vscode", "mcp.json"), "vscode");
|
|
1351
1523
|
}
|
|
1352
1524
|
if (editor === `cursor-global`) {
|
|
1353
1525
|
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor);
|
|
@@ -1405,7 +1577,7 @@ var FileEnvService = class extends EnvService {
|
|
|
1405
1577
|
}
|
|
1406
1578
|
readFile(filePath) {
|
|
1407
1579
|
return new Promise((resolve, reject) => {
|
|
1408
|
-
|
|
1580
|
+
fs4__default.readFile(filePath, "utf8", (err, data) => {
|
|
1409
1581
|
if (err) reject(err);
|
|
1410
1582
|
else resolve(data);
|
|
1411
1583
|
});
|
|
@@ -1413,7 +1585,7 @@ var FileEnvService = class extends EnvService {
|
|
|
1413
1585
|
}
|
|
1414
1586
|
writeFile({ filePath, data }) {
|
|
1415
1587
|
return new Promise((resolve, reject) => {
|
|
1416
|
-
|
|
1588
|
+
fs4__default.writeFile(filePath, data, "utf8", (err) => {
|
|
1417
1589
|
if (err) reject(err);
|
|
1418
1590
|
else resolve();
|
|
1419
1591
|
});
|
|
@@ -1466,10 +1638,10 @@ var FileService = class {
|
|
|
1466
1638
|
*/
|
|
1467
1639
|
async copyStarterFile(inputFile, outputFilePath, replaceIfExists) {
|
|
1468
1640
|
const __filename = fileURLToPath(import.meta.url);
|
|
1469
|
-
const __dirname =
|
|
1470
|
-
const filePath =
|
|
1471
|
-
const fileString =
|
|
1472
|
-
if (
|
|
1641
|
+
const __dirname = path3.dirname(__filename);
|
|
1642
|
+
const filePath = path3.resolve(__dirname, "starter-files", inputFile);
|
|
1643
|
+
const fileString = fs4__default__default.readFileSync(filePath, "utf8");
|
|
1644
|
+
if (fs4__default__default.existsSync(outputFilePath) && !replaceIfExists) {
|
|
1473
1645
|
console.log(`${outputFilePath} already exists`);
|
|
1474
1646
|
return false;
|
|
1475
1647
|
}
|
|
@@ -1477,14 +1649,14 @@ var FileService = class {
|
|
|
1477
1649
|
return true;
|
|
1478
1650
|
}
|
|
1479
1651
|
async setupEnvFile({ dbUrl }) {
|
|
1480
|
-
const envPath =
|
|
1652
|
+
const envPath = path3.join(process.cwd(), ".env.development");
|
|
1481
1653
|
await fsExtra3.ensureFile(envPath);
|
|
1482
1654
|
const fileEnvService = new FileEnvService(envPath);
|
|
1483
1655
|
await fileEnvService.setEnvValue("DB_URL", dbUrl);
|
|
1484
1656
|
}
|
|
1485
1657
|
getFirstExistingFile(files) {
|
|
1486
1658
|
for (const f of files) {
|
|
1487
|
-
if (
|
|
1659
|
+
if (fs4__default__default.existsSync(f)) {
|
|
1488
1660
|
return f;
|
|
1489
1661
|
}
|
|
1490
1662
|
}
|
|
@@ -1494,18 +1666,22 @@ var FileService = class {
|
|
|
1494
1666
|
filePath,
|
|
1495
1667
|
replacements
|
|
1496
1668
|
}) {
|
|
1497
|
-
let fileContent =
|
|
1669
|
+
let fileContent = fs4__default__default.readFileSync(filePath, "utf8");
|
|
1498
1670
|
replacements.forEach(({ search, replace }) => {
|
|
1499
1671
|
fileContent = fileContent.replaceAll(search, replace);
|
|
1500
1672
|
});
|
|
1501
|
-
|
|
1673
|
+
fs4__default__default.writeFileSync(filePath, fileContent);
|
|
1674
|
+
}
|
|
1675
|
+
};
|
|
1676
|
+
var exec2 = util.promisify(child_process.exec);
|
|
1677
|
+
var getAISDKPackageVersion = (llmProvider) => {
|
|
1678
|
+
switch (llmProvider) {
|
|
1679
|
+
case "cerebras":
|
|
1680
|
+
return "^0.2.14";
|
|
1681
|
+
default:
|
|
1682
|
+
return "^1.0.0";
|
|
1502
1683
|
}
|
|
1503
1684
|
};
|
|
1504
|
-
new PinoLogger({
|
|
1505
|
-
name: "Mastra CLI",
|
|
1506
|
-
level: "info"
|
|
1507
|
-
});
|
|
1508
|
-
var exec = util.promisify(child_process.exec);
|
|
1509
1685
|
var getAISDKPackage = (llmProvider) => {
|
|
1510
1686
|
switch (llmProvider) {
|
|
1511
1687
|
case "openai":
|
|
@@ -1536,7 +1712,7 @@ var getProviderImportAndModelItem = (llmProvider) => {
|
|
|
1536
1712
|
modelItem = `groq('llama-3.3-70b-versatile')`;
|
|
1537
1713
|
} else if (llmProvider === "google") {
|
|
1538
1714
|
providerImport = `import { google } from '${getAISDKPackage(llmProvider)}';`;
|
|
1539
|
-
modelItem = `google('gemini-
|
|
1715
|
+
modelItem = `google('gemini-2.5-pro')`;
|
|
1540
1716
|
} else if (llmProvider === "cerebras") {
|
|
1541
1717
|
providerImport = `import { cerebras } from '${getAISDKPackage(llmProvider)}';`;
|
|
1542
1718
|
modelItem = `cerebras('llama-3.3-70b')`;
|
|
@@ -1546,14 +1722,16 @@ var getProviderImportAndModelItem = (llmProvider) => {
|
|
|
1546
1722
|
async function writeAgentSample(llmProvider, destPath, addExampleTool) {
|
|
1547
1723
|
const { providerImport, modelItem } = getProviderImportAndModelItem(llmProvider);
|
|
1548
1724
|
const instructions = `
|
|
1549
|
-
You are a helpful weather assistant that provides accurate weather information.
|
|
1725
|
+
You are a helpful weather assistant that provides accurate weather information and can help planning activities based on the weather.
|
|
1550
1726
|
|
|
1551
1727
|
Your primary function is to help users get weather details for specific locations. When responding:
|
|
1552
1728
|
- Always ask for a location if none is provided
|
|
1553
|
-
- If the location name isn
|
|
1729
|
+
- If the location name isn't in English, please translate it
|
|
1554
1730
|
- If giving a location with multiple parts (e.g. "New York, NY"), use the most relevant part (e.g. "New York")
|
|
1555
1731
|
- Include relevant details like humidity, wind conditions, and precipitation
|
|
1556
1732
|
- Keep responses concise but informative
|
|
1733
|
+
- If the user asks for activities and provides the weather forecast, suggest activities based on the weather forecast.
|
|
1734
|
+
- If the user asks for activities, respond in the format they request.
|
|
1557
1735
|
|
|
1558
1736
|
${addExampleTool ? "Use the weatherTool to fetch current weather data." : ""}
|
|
1559
1737
|
`;
|
|
@@ -1580,66 +1758,13 @@ export const weatherAgent = new Agent({
|
|
|
1580
1758
|
parser: "typescript",
|
|
1581
1759
|
singleQuote: true
|
|
1582
1760
|
});
|
|
1583
|
-
await
|
|
1584
|
-
await
|
|
1761
|
+
await fs.writeFile(destPath, "");
|
|
1762
|
+
await fs.writeFile(destPath, formattedContent);
|
|
1585
1763
|
}
|
|
1586
|
-
async function writeWorkflowSample(destPath
|
|
1587
|
-
const {
|
|
1588
|
-
const content = `${providerImport}
|
|
1589
|
-
import { Agent } from '@mastra/core/agent';
|
|
1590
|
-
import { createStep, createWorkflow } from '@mastra/core/workflows';
|
|
1764
|
+
async function writeWorkflowSample(destPath) {
|
|
1765
|
+
const content = `import { createStep, createWorkflow } from '@mastra/core/workflows';
|
|
1591
1766
|
import { z } from 'zod';
|
|
1592
1767
|
|
|
1593
|
-
const llm = ${modelItem};
|
|
1594
|
-
|
|
1595
|
-
const agent = new Agent({
|
|
1596
|
-
name: 'Weather Agent',
|
|
1597
|
-
model: llm,
|
|
1598
|
-
instructions: \`
|
|
1599
|
-
You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations.
|
|
1600
|
-
|
|
1601
|
-
For each day in the forecast, structure your response exactly as follows:
|
|
1602
|
-
|
|
1603
|
-
\u{1F4C5} [Day, Month Date, Year]
|
|
1604
|
-
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
1605
|
-
|
|
1606
|
-
\u{1F321}\uFE0F WEATHER SUMMARY
|
|
1607
|
-
\u2022 Conditions: [brief description]
|
|
1608
|
-
\u2022 Temperature: [X\xB0C/Y\xB0F to A\xB0C/B\xB0F]
|
|
1609
|
-
\u2022 Precipitation: [X% chance]
|
|
1610
|
-
|
|
1611
|
-
\u{1F305} MORNING ACTIVITIES
|
|
1612
|
-
Outdoor:
|
|
1613
|
-
\u2022 [Activity Name] - [Brief description including specific location/route]
|
|
1614
|
-
Best timing: [specific time range]
|
|
1615
|
-
Note: [relevant weather consideration]
|
|
1616
|
-
|
|
1617
|
-
\u{1F31E} AFTERNOON ACTIVITIES
|
|
1618
|
-
Outdoor:
|
|
1619
|
-
\u2022 [Activity Name] - [Brief description including specific location/route]
|
|
1620
|
-
Best timing: [specific time range]
|
|
1621
|
-
Note: [relevant weather consideration]
|
|
1622
|
-
|
|
1623
|
-
\u{1F3E0} INDOOR ALTERNATIVES
|
|
1624
|
-
\u2022 [Activity Name] - [Brief description including specific venue]
|
|
1625
|
-
Ideal for: [weather condition that would trigger this alternative]
|
|
1626
|
-
|
|
1627
|
-
\u26A0\uFE0F SPECIAL CONSIDERATIONS
|
|
1628
|
-
\u2022 [Any relevant weather warnings, UV index, wind conditions, etc.]
|
|
1629
|
-
|
|
1630
|
-
Guidelines:
|
|
1631
|
-
- Suggest 2-3 time-specific outdoor activities per day
|
|
1632
|
-
- Include 1-2 indoor backup options
|
|
1633
|
-
- For precipitation >50%, lead with indoor activities
|
|
1634
|
-
- All activities must be specific to the location
|
|
1635
|
-
- Include specific venues, trails, or locations
|
|
1636
|
-
- Consider activity intensity based on temperature
|
|
1637
|
-
- Keep descriptions concise but informative
|
|
1638
|
-
|
|
1639
|
-
Maintain this exact formatting for consistency, using the emoji and section headers as shown.
|
|
1640
|
-
\`,
|
|
1641
|
-
});
|
|
1642
|
-
|
|
1643
1768
|
const forecastSchema = z.object({
|
|
1644
1769
|
date: z.string(),
|
|
1645
1770
|
maxTemp: z.number(),
|
|
@@ -1733,16 +1858,59 @@ const planActivities = createStep({
|
|
|
1733
1858
|
outputSchema: z.object({
|
|
1734
1859
|
activities: z.string(),
|
|
1735
1860
|
}),
|
|
1736
|
-
execute: async ({ inputData }) => {
|
|
1861
|
+
execute: async ({ inputData, mastra }) => {
|
|
1737
1862
|
const forecast = inputData
|
|
1738
1863
|
|
|
1739
1864
|
if (!forecast) {
|
|
1740
1865
|
throw new Error('Forecast data not found')
|
|
1741
1866
|
}
|
|
1742
1867
|
|
|
1868
|
+
const agent = mastra?.getAgent('weatherAgent');
|
|
1869
|
+
if (!agent) {
|
|
1870
|
+
throw new Error('Weather agent not found');
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1743
1873
|
const prompt = \`Based on the following weather forecast for \${forecast.location}, suggest appropriate activities:
|
|
1744
1874
|
\${JSON.stringify(forecast, null, 2)}
|
|
1745
|
-
|
|
1875
|
+
For each day in the forecast, structure your response exactly as follows:
|
|
1876
|
+
|
|
1877
|
+
\u{1F4C5} [Day, Month Date, Year]
|
|
1878
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
1879
|
+
|
|
1880
|
+
\u{1F321}\uFE0F WEATHER SUMMARY
|
|
1881
|
+
\u2022 Conditions: [brief description]
|
|
1882
|
+
\u2022 Temperature: [X\xB0C/Y\xB0F to A\xB0C/B\xB0F]
|
|
1883
|
+
\u2022 Precipitation: [X% chance]
|
|
1884
|
+
|
|
1885
|
+
\u{1F305} MORNING ACTIVITIES
|
|
1886
|
+
Outdoor:
|
|
1887
|
+
\u2022 [Activity Name] - [Brief description including specific location/route]
|
|
1888
|
+
Best timing: [specific time range]
|
|
1889
|
+
Note: [relevant weather consideration]
|
|
1890
|
+
|
|
1891
|
+
\u{1F31E} AFTERNOON ACTIVITIES
|
|
1892
|
+
Outdoor:
|
|
1893
|
+
\u2022 [Activity Name] - [Brief description including specific location/route]
|
|
1894
|
+
Best timing: [specific time range]
|
|
1895
|
+
Note: [relevant weather consideration]
|
|
1896
|
+
|
|
1897
|
+
\u{1F3E0} INDOOR ALTERNATIVES
|
|
1898
|
+
\u2022 [Activity Name] - [Brief description including specific venue]
|
|
1899
|
+
Ideal for: [weather condition that would trigger this alternative]
|
|
1900
|
+
|
|
1901
|
+
\u26A0\uFE0F SPECIAL CONSIDERATIONS
|
|
1902
|
+
\u2022 [Any relevant weather warnings, UV index, wind conditions, etc.]
|
|
1903
|
+
|
|
1904
|
+
Guidelines:
|
|
1905
|
+
- Suggest 2-3 time-specific outdoor activities per day
|
|
1906
|
+
- Include 1-2 indoor backup options
|
|
1907
|
+
- For precipitation >50%, lead with indoor activities
|
|
1908
|
+
- All activities must be specific to the location
|
|
1909
|
+
- Include specific venues, trails, or locations
|
|
1910
|
+
- Consider activity intensity based on temperature
|
|
1911
|
+
- Keep descriptions concise but informative
|
|
1912
|
+
|
|
1913
|
+
Maintain this exact formatting for consistency, using the emoji and section headers as shown.\`;
|
|
1746
1914
|
|
|
1747
1915
|
const response = await agent.stream([
|
|
1748
1916
|
{
|
|
@@ -1784,7 +1952,7 @@ export { weatherWorkflow };`;
|
|
|
1784
1952
|
semi: true,
|
|
1785
1953
|
singleQuote: true
|
|
1786
1954
|
});
|
|
1787
|
-
await
|
|
1955
|
+
await fs.writeFile(destPath, formattedContent);
|
|
1788
1956
|
}
|
|
1789
1957
|
async function writeToolSample(destPath) {
|
|
1790
1958
|
const fileService = new FileService();
|
|
@@ -1797,7 +1965,7 @@ async function writeCodeSampleForComponents(llmprovider, component, destPath, im
|
|
|
1797
1965
|
case "tools":
|
|
1798
1966
|
return writeToolSample(destPath);
|
|
1799
1967
|
case "workflows":
|
|
1800
|
-
return writeWorkflowSample(destPath
|
|
1968
|
+
return writeWorkflowSample(destPath);
|
|
1801
1969
|
default:
|
|
1802
1970
|
return "";
|
|
1803
1971
|
}
|
|
@@ -1813,15 +1981,15 @@ var writeIndexFile = async ({
|
|
|
1813
1981
|
addWorkflow
|
|
1814
1982
|
}) => {
|
|
1815
1983
|
const indexPath = dirPath + "/index.ts";
|
|
1816
|
-
const destPath =
|
|
1984
|
+
const destPath = path3.join(indexPath);
|
|
1817
1985
|
try {
|
|
1818
|
-
await
|
|
1986
|
+
await fs.writeFile(destPath, "");
|
|
1819
1987
|
const filteredExports = [
|
|
1820
1988
|
addWorkflow ? `workflows: { weatherWorkflow },` : "",
|
|
1821
1989
|
addAgent ? `agents: { weatherAgent },` : ""
|
|
1822
1990
|
].filter(Boolean);
|
|
1823
1991
|
if (!addExample) {
|
|
1824
|
-
await
|
|
1992
|
+
await fs.writeFile(
|
|
1825
1993
|
destPath,
|
|
1826
1994
|
`
|
|
1827
1995
|
import { Mastra } from '@mastra/core';
|
|
@@ -1831,7 +1999,7 @@ export const mastra = new Mastra()
|
|
|
1831
1999
|
);
|
|
1832
2000
|
return;
|
|
1833
2001
|
}
|
|
1834
|
-
await
|
|
2002
|
+
await fs.writeFile(
|
|
1835
2003
|
destPath,
|
|
1836
2004
|
`
|
|
1837
2005
|
import { Mastra } from '@mastra/core/mastra';
|
|
@@ -1884,13 +2052,13 @@ var writeAPIKey = async ({
|
|
|
1884
2052
|
const key = await getAPIKey(provider);
|
|
1885
2053
|
const escapedKey = shellQuote.quote([key]);
|
|
1886
2054
|
const escapedApiKey = shellQuote.quote([apiKey]);
|
|
1887
|
-
await
|
|
2055
|
+
await exec2(`echo ${escapedKey}=${escapedApiKey} >> .env`);
|
|
1888
2056
|
};
|
|
1889
2057
|
var createMastraDir = async (directory) => {
|
|
1890
2058
|
let dir = directory.trim().split("/").filter((item) => item !== "");
|
|
1891
|
-
const dirPath =
|
|
2059
|
+
const dirPath = path3.join(process.cwd(), ...dir, "mastra");
|
|
1892
2060
|
try {
|
|
1893
|
-
await
|
|
2061
|
+
await fs.access(dirPath);
|
|
1894
2062
|
return { ok: false };
|
|
1895
2063
|
} catch {
|
|
1896
2064
|
await fsExtra3.ensureDir(dirPath);
|
|
@@ -2027,7 +2195,7 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2027
2195
|
return mastraProject;
|
|
2028
2196
|
};
|
|
2029
2197
|
var s = Y();
|
|
2030
|
-
var
|
|
2198
|
+
var exec3 = util.promisify(child_process.exec);
|
|
2031
2199
|
var init = async ({
|
|
2032
2200
|
directory,
|
|
2033
2201
|
addExample = false,
|
|
@@ -2076,10 +2244,11 @@ var init = async ({
|
|
|
2076
2244
|
}
|
|
2077
2245
|
const key = await getAPIKey(llmProvider || "openai");
|
|
2078
2246
|
const aiSdkPackage = getAISDKPackage(llmProvider);
|
|
2247
|
+
const aiSdkPackageVersion = getAISDKPackageVersion(llmProvider);
|
|
2079
2248
|
const depsService = new DepsService();
|
|
2080
2249
|
const pm = depsService.packageManager;
|
|
2081
2250
|
const installCommand = getPackageManagerInstallCommand(pm);
|
|
2082
|
-
await
|
|
2251
|
+
await exec3(`${pm} ${installCommand} ${aiSdkPackage}@${aiSdkPackageVersion}`);
|
|
2083
2252
|
if (configureEditorWithDocsMCP) {
|
|
2084
2253
|
await installMastraDocsMCPServer({
|
|
2085
2254
|
editor: configureEditorWithDocsMCP,
|
|
@@ -2106,10 +2275,10 @@ var init = async ({
|
|
|
2106
2275
|
return { success: false };
|
|
2107
2276
|
}
|
|
2108
2277
|
};
|
|
2109
|
-
var
|
|
2278
|
+
var exec4 = util.promisify(child_process.exec);
|
|
2110
2279
|
var execWithTimeout = async (command, timeoutMs) => {
|
|
2111
2280
|
try {
|
|
2112
|
-
const promise =
|
|
2281
|
+
const promise = exec4(command, { killSignal: "SIGTERM" });
|
|
2113
2282
|
if (!timeoutMs) {
|
|
2114
2283
|
return await promise;
|
|
2115
2284
|
}
|
|
@@ -2173,7 +2342,7 @@ var createMastraProject = async ({
|
|
|
2173
2342
|
try {
|
|
2174
2343
|
s2.start("Creating project");
|
|
2175
2344
|
try {
|
|
2176
|
-
await
|
|
2345
|
+
await fs.mkdir(projectName);
|
|
2177
2346
|
} catch (error) {
|
|
2178
2347
|
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
2179
2348
|
s2.stop(`A directory named "${projectName}" already exists. Please choose a different name.`);
|
|
@@ -2188,9 +2357,9 @@ var createMastraProject = async ({
|
|
|
2188
2357
|
const installCommand = getPackageManagerInstallCommand(pm);
|
|
2189
2358
|
s2.message("Initializing project structure");
|
|
2190
2359
|
try {
|
|
2191
|
-
await
|
|
2192
|
-
await
|
|
2193
|
-
await
|
|
2360
|
+
await exec4(`npm init -y`);
|
|
2361
|
+
await exec4(`npm pkg set type="module"`);
|
|
2362
|
+
await exec4(`npm pkg set engines.node=">=20.9.0"`);
|
|
2194
2363
|
const depsService = new DepsService();
|
|
2195
2364
|
await depsService.addScriptsToPackageJson({
|
|
2196
2365
|
dev: "mastra dev",
|
|
@@ -2205,9 +2374,9 @@ var createMastraProject = async ({
|
|
|
2205
2374
|
s2.stop("Project structure created");
|
|
2206
2375
|
s2.start(`Installing ${pm} dependencies`);
|
|
2207
2376
|
try {
|
|
2208
|
-
await
|
|
2209
|
-
await
|
|
2210
|
-
await
|
|
2377
|
+
await exec4(`${pm} ${installCommand} zod@^3`);
|
|
2378
|
+
await exec4(`${pm} ${installCommand} typescript @types/node --save-dev`);
|
|
2379
|
+
await exec4(`echo '{
|
|
2211
2380
|
"compilerOptions": {
|
|
2212
2381
|
"target": "ES2022",
|
|
2213
2382
|
"module": "ES2022",
|
|
@@ -2250,14 +2419,14 @@ var createMastraProject = async ({
|
|
|
2250
2419
|
s2.stop("Mastra dependencies installed");
|
|
2251
2420
|
s2.start("Adding .gitignore");
|
|
2252
2421
|
try {
|
|
2253
|
-
await
|
|
2254
|
-
await
|
|
2255
|
-
await
|
|
2256
|
-
await
|
|
2257
|
-
await
|
|
2258
|
-
await
|
|
2259
|
-
await
|
|
2260
|
-
await
|
|
2422
|
+
await exec4(`echo output.txt >> .gitignore`);
|
|
2423
|
+
await exec4(`echo node_modules >> .gitignore`);
|
|
2424
|
+
await exec4(`echo dist >> .gitignore`);
|
|
2425
|
+
await exec4(`echo .mastra >> .gitignore`);
|
|
2426
|
+
await exec4(`echo .env.development >> .gitignore`);
|
|
2427
|
+
await exec4(`echo .env >> .gitignore`);
|
|
2428
|
+
await exec4(`echo *.db >> .gitignore`);
|
|
2429
|
+
await exec4(`echo *.db-* >> .gitignore`);
|
|
2261
2430
|
} catch (error) {
|
|
2262
2431
|
throw new Error(`Failed to create .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2263
2432
|
}
|
|
@@ -2273,6 +2442,10 @@ var createMastraProject = async ({
|
|
|
2273
2442
|
}
|
|
2274
2443
|
};
|
|
2275
2444
|
var create = async (args2) => {
|
|
2445
|
+
if (args2.template !== void 0) {
|
|
2446
|
+
await createFromTemplate(args2);
|
|
2447
|
+
return;
|
|
2448
|
+
}
|
|
2276
2449
|
const { projectName } = await createMastraProject({
|
|
2277
2450
|
projectName: args2?.projectName,
|
|
2278
2451
|
createVersionTag: args2?.createVersionTag,
|
|
@@ -2310,11 +2483,160 @@ var postCreate = ({ projectName }) => {
|
|
|
2310
2483
|
${color2.cyan(`${packageManager} run dev`)}
|
|
2311
2484
|
`);
|
|
2312
2485
|
};
|
|
2486
|
+
function isGitHubUrl(url) {
|
|
2487
|
+
try {
|
|
2488
|
+
const parsedUrl = new URL(url);
|
|
2489
|
+
return parsedUrl.hostname === "github.com" && parsedUrl.pathname.split("/").length >= 3;
|
|
2490
|
+
} catch {
|
|
2491
|
+
return false;
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
async function validateGitHubProject(githubUrl) {
|
|
2495
|
+
const errors = [];
|
|
2496
|
+
try {
|
|
2497
|
+
const urlParts = new URL(githubUrl).pathname.split("/").filter(Boolean);
|
|
2498
|
+
const owner = urlParts[0];
|
|
2499
|
+
const repo = urlParts[1]?.replace(".git", "");
|
|
2500
|
+
if (!owner || !repo) {
|
|
2501
|
+
throw new Error("Invalid GitHub URL format");
|
|
2502
|
+
}
|
|
2503
|
+
const branches = ["main", "master"];
|
|
2504
|
+
let packageJsonContent = null;
|
|
2505
|
+
let indexContent = null;
|
|
2506
|
+
for (const branch of branches) {
|
|
2507
|
+
try {
|
|
2508
|
+
const packageJsonUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/package.json`;
|
|
2509
|
+
const packageJsonResponse = await fetch(packageJsonUrl);
|
|
2510
|
+
if (packageJsonResponse.ok) {
|
|
2511
|
+
packageJsonContent = await packageJsonResponse.text();
|
|
2512
|
+
const indexUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/src/mastra/index.ts`;
|
|
2513
|
+
const indexResponse = await fetch(indexUrl);
|
|
2514
|
+
if (indexResponse.ok) {
|
|
2515
|
+
indexContent = await indexResponse.text();
|
|
2516
|
+
}
|
|
2517
|
+
break;
|
|
2518
|
+
}
|
|
2519
|
+
} catch {
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
if (!packageJsonContent) {
|
|
2523
|
+
errors.push("Could not fetch package.json from repository");
|
|
2524
|
+
return { isValid: false, errors };
|
|
2525
|
+
}
|
|
2526
|
+
try {
|
|
2527
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
2528
|
+
const hasMastraCore = packageJson.dependencies?.["@mastra/core"] || packageJson.devDependencies?.["@mastra/core"] || packageJson.peerDependencies?.["@mastra/core"];
|
|
2529
|
+
if (!hasMastraCore) {
|
|
2530
|
+
errors.push("Missing @mastra/core dependency in package.json");
|
|
2531
|
+
}
|
|
2532
|
+
} catch {
|
|
2533
|
+
errors.push("Invalid package.json format");
|
|
2534
|
+
}
|
|
2535
|
+
if (!indexContent) {
|
|
2536
|
+
errors.push("Missing src/mastra/index.ts file");
|
|
2537
|
+
} else {
|
|
2538
|
+
const hasMastraExport = indexContent.includes("export") && (indexContent.includes("new Mastra") || indexContent.includes("Mastra("));
|
|
2539
|
+
if (!hasMastraExport) {
|
|
2540
|
+
errors.push("src/mastra/index.ts does not export a Mastra instance");
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
return { isValid: errors.length === 0, errors };
|
|
2544
|
+
} catch (error) {
|
|
2545
|
+
errors.push(`Failed to validate GitHub repository: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2546
|
+
return { isValid: false, errors };
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
async function createFromGitHubUrl(url) {
|
|
2550
|
+
const urlParts = new URL(url).pathname.split("/").filter(Boolean);
|
|
2551
|
+
const owner = urlParts[0] || "unknown";
|
|
2552
|
+
const repo = urlParts[1] || "unknown";
|
|
2553
|
+
return {
|
|
2554
|
+
githubUrl: url,
|
|
2555
|
+
title: `${owner}/${repo}`,
|
|
2556
|
+
slug: repo,
|
|
2557
|
+
agents: [],
|
|
2558
|
+
mcp: [],
|
|
2559
|
+
tools: [],
|
|
2560
|
+
networks: [],
|
|
2561
|
+
workflows: []
|
|
2562
|
+
};
|
|
2563
|
+
}
|
|
2564
|
+
async function createFromTemplate(args2) {
|
|
2565
|
+
let selectedTemplate;
|
|
2566
|
+
if (args2.template === true) {
|
|
2567
|
+
const templates = await loadTemplates();
|
|
2568
|
+
const selected = await selectTemplate(templates);
|
|
2569
|
+
if (!selected) {
|
|
2570
|
+
M.info("No template selected. Exiting.");
|
|
2571
|
+
return;
|
|
2572
|
+
}
|
|
2573
|
+
selectedTemplate = selected;
|
|
2574
|
+
} else if (args2.template && typeof args2.template === "string") {
|
|
2575
|
+
if (isGitHubUrl(args2.template)) {
|
|
2576
|
+
const spinner5 = Y();
|
|
2577
|
+
spinner5.start("Validating GitHub repository...");
|
|
2578
|
+
const validation = await validateGitHubProject(args2.template);
|
|
2579
|
+
if (!validation.isValid) {
|
|
2580
|
+
spinner5.stop("Validation failed");
|
|
2581
|
+
M.error("This does not appear to be a valid Mastra project:");
|
|
2582
|
+
validation.errors.forEach((error) => M.error(` - ${error}`));
|
|
2583
|
+
throw new Error("Invalid Mastra project");
|
|
2584
|
+
}
|
|
2585
|
+
spinner5.stop("Valid Mastra project \u2713");
|
|
2586
|
+
selectedTemplate = await createFromGitHubUrl(args2.template);
|
|
2587
|
+
} else {
|
|
2588
|
+
const templates = await loadTemplates();
|
|
2589
|
+
const found = findTemplateByName(templates, args2.template);
|
|
2590
|
+
if (!found) {
|
|
2591
|
+
M.error(`Template "${args2.template}" not found. Available templates:`);
|
|
2592
|
+
templates.forEach((t) => M.info(` - ${t.title} (use: ${t.slug.replace("template-", "")})`));
|
|
2593
|
+
throw new Error(`Template "${args2.template}" not found`);
|
|
2594
|
+
}
|
|
2595
|
+
selectedTemplate = found;
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
if (!selectedTemplate) {
|
|
2599
|
+
throw new Error("No template selected");
|
|
2600
|
+
}
|
|
2601
|
+
let projectName = args2.projectName;
|
|
2602
|
+
if (!projectName) {
|
|
2603
|
+
const defaultName = getDefaultProjectName(selectedTemplate);
|
|
2604
|
+
const response = await he({
|
|
2605
|
+
message: "What is your project name?",
|
|
2606
|
+
defaultValue: defaultName,
|
|
2607
|
+
placeholder: defaultName
|
|
2608
|
+
});
|
|
2609
|
+
if (pD(response)) {
|
|
2610
|
+
M.info("Project creation cancelled.");
|
|
2611
|
+
return;
|
|
2612
|
+
}
|
|
2613
|
+
projectName = response;
|
|
2614
|
+
}
|
|
2615
|
+
try {
|
|
2616
|
+
const analytics = getAnalytics();
|
|
2617
|
+
if (analytics) ;
|
|
2618
|
+
const projectPath = await cloneTemplate({
|
|
2619
|
+
template: selectedTemplate,
|
|
2620
|
+
projectName
|
|
2621
|
+
});
|
|
2622
|
+
await installDependencies(projectPath);
|
|
2623
|
+
Me(`
|
|
2624
|
+
${color2.green("Mastra template installed!")}
|
|
2625
|
+
|
|
2626
|
+
Add the necessary environment
|
|
2627
|
+
variables in your ${color2.cyan(".env")} file
|
|
2628
|
+
`);
|
|
2629
|
+
postCreate({ projectName });
|
|
2630
|
+
} catch (error) {
|
|
2631
|
+
M.error(`Failed to create project from template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2632
|
+
throw error;
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2313
2635
|
|
|
2314
2636
|
async function getPackageVersion() {
|
|
2315
2637
|
const __filename = fileURLToPath(import.meta.url);
|
|
2316
2638
|
const __dirname = dirname(__filename);
|
|
2317
|
-
const pkgJsonPath =
|
|
2639
|
+
const pkgJsonPath = path3.join(__dirname, "..", "package.json");
|
|
2318
2640
|
const content = await fsExtra.readJSON(pkgJsonPath);
|
|
2319
2641
|
return content.version;
|
|
2320
2642
|
}
|
|
@@ -2352,7 +2674,10 @@ program.version(`${version}`, "-v, --version").description(`create-mastra ${vers
|
|
|
2352
2674
|
program.name("create-mastra").description("Create a new Mastra project").argument("[project-name]", "Directory name of the project").option(
|
|
2353
2675
|
"-p, --project-name <string>",
|
|
2354
2676
|
"Project name that will be used in package.json and as the project directory name."
|
|
2355
|
-
).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)").
|
|
2677
|
+
).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(
|
|
2678
|
+
"--template [template-name]",
|
|
2679
|
+
"Create project from a template (use template name, public GitHub URL, or leave blank to select from list)"
|
|
2680
|
+
).action(async (projectNameArg, args) => {
|
|
2356
2681
|
const projectName = projectNameArg || args.projectName;
|
|
2357
2682
|
const timeout = args?.timeout ? args?.timeout === true ? 6e4 : parseInt(args?.timeout, 10) : void 0;
|
|
2358
2683
|
if (args.default) {
|
|
@@ -2363,7 +2688,8 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2363
2688
|
createVersionTag,
|
|
2364
2689
|
timeout,
|
|
2365
2690
|
mcpServer: args.mcp,
|
|
2366
|
-
directory: "src/"
|
|
2691
|
+
directory: "src/",
|
|
2692
|
+
template: args.template
|
|
2367
2693
|
});
|
|
2368
2694
|
return;
|
|
2369
2695
|
}
|
|
@@ -2376,7 +2702,8 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2376
2702
|
timeout,
|
|
2377
2703
|
projectName,
|
|
2378
2704
|
directory: args.dir,
|
|
2379
|
-
mcpServer: args.mcp
|
|
2705
|
+
mcpServer: args.mcp,
|
|
2706
|
+
template: args.template
|
|
2380
2707
|
});
|
|
2381
2708
|
});
|
|
2382
2709
|
program.parse(process.argv);
|