create-mastra 0.0.0-roamin-openaivoice-speak-options-passing-20250926163614 → 0.0.0-safe-stringify-telemetry-20251205024938
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/CHANGELOG.md +373 -1
- package/README.md +10 -32
- package/dist/index.js +632 -454
- package/dist/index.js.map +1 -1
- package/package.json +15 -8
package/dist/index.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
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 fs3__default from 'node:fs';
|
|
5
|
+
import fs3__default__default, { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
6
|
import os from 'node:os';
|
|
7
|
-
import
|
|
7
|
+
import path, { dirname } from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { PostHog } from 'posthog-node';
|
|
10
|
+
import fs4 from 'node:fs/promises';
|
|
10
11
|
import util, { stripVTControlCharacters } from 'node:util';
|
|
11
12
|
import y$1, { stdout, stdin } from 'node:process';
|
|
12
13
|
import * as g from 'node:readline';
|
|
13
14
|
import g__default from 'node:readline';
|
|
14
15
|
import { Writable } from 'node:stream';
|
|
15
|
-
import fs5 from 'node:fs/promises';
|
|
16
16
|
import child_process from 'node:child_process';
|
|
17
17
|
import tty from 'node:tty';
|
|
18
|
-
import pino from 'pino';
|
|
19
|
-
import pretty from 'pino-pretty';
|
|
20
|
-
import { execa } from 'execa';
|
|
21
18
|
import fsExtra, { readJSON, ensureFile, writeJSON } from 'fs-extra/esm';
|
|
22
19
|
import prettier from 'prettier';
|
|
20
|
+
import { execa } from 'execa';
|
|
21
|
+
import pino from 'pino';
|
|
22
|
+
import pretty from 'pino-pretty';
|
|
23
23
|
import fsExtra$1 from 'fs-extra';
|
|
24
24
|
|
|
25
25
|
var __filename = fileURLToPath(import.meta.url);
|
|
26
|
-
var __dirname =
|
|
26
|
+
var __dirname = path.dirname(__filename);
|
|
27
27
|
var analyticsInstance = null;
|
|
28
28
|
function getAnalytics() {
|
|
29
29
|
return analyticsInstance;
|
|
@@ -39,7 +39,7 @@ var PosthogAnalytics = class {
|
|
|
39
39
|
host = "https://app.posthog.com"
|
|
40
40
|
}) {
|
|
41
41
|
this.version = version;
|
|
42
|
-
const cliConfigPath =
|
|
42
|
+
const cliConfigPath = path.join(__dirname, "mastra-cli.json");
|
|
43
43
|
if (existsSync(cliConfigPath)) {
|
|
44
44
|
try {
|
|
45
45
|
const { distinctId, sessionId } = JSON.parse(readFileSync(cliConfigPath, "utf-8"));
|
|
@@ -67,7 +67,7 @@ var PosthogAnalytics = class {
|
|
|
67
67
|
}
|
|
68
68
|
writeCliConfig({ distinctId, sessionId }) {
|
|
69
69
|
try {
|
|
70
|
-
writeFileSync(
|
|
70
|
+
writeFileSync(path.join(__dirname, "mastra-cli.json"), JSON.stringify({ distinctId, sessionId }));
|
|
71
71
|
} catch {
|
|
72
72
|
}
|
|
73
73
|
}
|
|
@@ -422,7 +422,7 @@ ${color2.gray(d)} ${t}
|
|
|
422
422
|
`):process.stdout.write(`${w} ${l}
|
|
423
423
|
`),E(),s();};return {start:H,stop:N,message:(m="")=>{l=R(m??l);}}},Ce=async(t,n)=>{const r={},i=Object.keys(t);for(const s of i){const c=t[s],a=await c({results:r})?.catch(l=>{throw l});if(typeof n?.onCancel=="function"&&pD(a)){r[s]="canceled",n.onCancel({results:r});continue}r[s]=a;}return r};
|
|
424
424
|
|
|
425
|
-
var shellQuote
|
|
425
|
+
var shellQuote = {};
|
|
426
426
|
|
|
427
427
|
var quote;
|
|
428
428
|
var hasRequiredQuote;
|
|
@@ -688,16 +688,16 @@ function requireParse () {
|
|
|
688
688
|
var hasRequiredShellQuote;
|
|
689
689
|
|
|
690
690
|
function requireShellQuote () {
|
|
691
|
-
if (hasRequiredShellQuote) return shellQuote
|
|
691
|
+
if (hasRequiredShellQuote) return shellQuote;
|
|
692
692
|
hasRequiredShellQuote = 1;
|
|
693
693
|
|
|
694
|
-
shellQuote
|
|
695
|
-
shellQuote
|
|
696
|
-
return shellQuote
|
|
694
|
+
shellQuote.quote = requireQuote();
|
|
695
|
+
shellQuote.parse = requireParse();
|
|
696
|
+
return shellQuote;
|
|
697
697
|
}
|
|
698
698
|
|
|
699
699
|
var shellQuoteExports = requireShellQuote();
|
|
700
|
-
var
|
|
700
|
+
var shellQuote2 = /*@__PURE__*/getDefaultExportFromCjs(shellQuoteExports);
|
|
701
701
|
|
|
702
702
|
// eslint-disable-next-line no-warning-comments
|
|
703
703
|
// TODO: Use a better method when it's added to Node.js (https://github.com/nodejs/node/pull/40240)
|
|
@@ -724,13 +724,18 @@ const format = (open, close) => {
|
|
|
724
724
|
// Handle nested colors.
|
|
725
725
|
|
|
726
726
|
// We could have done this, but it's too slow (as of Node.js 22).
|
|
727
|
-
// return openCode + string.replaceAll(closeCode, openCode) + closeCode;
|
|
727
|
+
// return openCode + string.replaceAll(closeCode, (close === 22 ? closeCode : '') + openCode) + closeCode;
|
|
728
728
|
|
|
729
729
|
let result = openCode;
|
|
730
730
|
let lastIndex = 0;
|
|
731
731
|
|
|
732
|
+
// SGR 22 resets both bold (1) and dim (2). When we encounter a nested
|
|
733
|
+
// close for styles that use 22, we need to re-open the outer style.
|
|
734
|
+
const reopenOnNestedClose = close === 22;
|
|
735
|
+
const replaceCode = (reopenOnNestedClose ? closeCode : '') + openCode;
|
|
736
|
+
|
|
732
737
|
while (index !== -1) {
|
|
733
|
-
result += string.slice(lastIndex, index) +
|
|
738
|
+
result += string.slice(lastIndex, index) + replaceCode;
|
|
734
739
|
lastIndex = index + closeCode.length;
|
|
735
740
|
index = string.indexOf(closeCode, lastIndex);
|
|
736
741
|
}
|
|
@@ -1173,279 +1178,6 @@ var PinoLogger = class extends MastraLogger {
|
|
|
1173
1178
|
}
|
|
1174
1179
|
};
|
|
1175
1180
|
|
|
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
|
-
var logger = new PinoLogger({
|
|
1200
|
-
name: "Mastra CLI",
|
|
1201
|
-
level: "info"
|
|
1202
|
-
});
|
|
1203
|
-
var exec = util.promisify(child_process.exec);
|
|
1204
|
-
async function cloneTemplate(options) {
|
|
1205
|
-
const { template, projectName, targetDir } = options;
|
|
1206
|
-
const projectPath = targetDir ? path3.resolve(targetDir, projectName) : path3.resolve(projectName);
|
|
1207
|
-
const spinner5 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
|
|
1208
|
-
try {
|
|
1209
|
-
if (await directoryExists(projectPath)) {
|
|
1210
|
-
spinner5.error(`Directory ${projectName} already exists`);
|
|
1211
|
-
throw new Error(`Directory ${projectName} already exists`);
|
|
1212
|
-
}
|
|
1213
|
-
await cloneRepositoryWithoutGit(template.githubUrl, projectPath);
|
|
1214
|
-
await updatePackageJson(projectPath, projectName);
|
|
1215
|
-
const envExamplePath = path3.join(projectPath, ".env.example");
|
|
1216
|
-
if (await fileExists(envExamplePath)) {
|
|
1217
|
-
await fs5.copyFile(envExamplePath, path3.join(projectPath, ".env"));
|
|
1218
|
-
}
|
|
1219
|
-
spinner5.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
1220
|
-
return projectPath;
|
|
1221
|
-
} catch (error) {
|
|
1222
|
-
spinner5.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1223
|
-
throw error;
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
async function directoryExists(dirPath) {
|
|
1227
|
-
try {
|
|
1228
|
-
const stat = await fs5.stat(dirPath);
|
|
1229
|
-
return stat.isDirectory();
|
|
1230
|
-
} catch {
|
|
1231
|
-
return false;
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
async function fileExists(filePath) {
|
|
1235
|
-
try {
|
|
1236
|
-
const stat = await fs5.stat(filePath);
|
|
1237
|
-
return stat.isFile();
|
|
1238
|
-
} catch {
|
|
1239
|
-
return false;
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
async function cloneRepositoryWithoutGit(repoUrl, targetPath) {
|
|
1243
|
-
await fs5.mkdir(targetPath, { recursive: true });
|
|
1244
|
-
try {
|
|
1245
|
-
const degitRepo = repoUrl.replace("https://github.com/", "");
|
|
1246
|
-
const degitCommand = shellQuote.quote(["npx", "degit", degitRepo, targetPath]);
|
|
1247
|
-
await exec(degitCommand, {
|
|
1248
|
-
cwd: process.cwd()
|
|
1249
|
-
});
|
|
1250
|
-
} catch {
|
|
1251
|
-
try {
|
|
1252
|
-
const gitCommand = shellQuote.quote(["git", "clone", repoUrl, targetPath]);
|
|
1253
|
-
await exec(gitCommand, {
|
|
1254
|
-
cwd: process.cwd()
|
|
1255
|
-
});
|
|
1256
|
-
const gitDir = path3.join(targetPath, ".git");
|
|
1257
|
-
if (await directoryExists(gitDir)) {
|
|
1258
|
-
await fs5.rm(gitDir, { recursive: true, force: true });
|
|
1259
|
-
}
|
|
1260
|
-
} catch (gitError) {
|
|
1261
|
-
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
async function updatePackageJson(projectPath, projectName) {
|
|
1266
|
-
const packageJsonPath = path3.join(projectPath, "package.json");
|
|
1267
|
-
try {
|
|
1268
|
-
const packageJsonContent = await fs5.readFile(packageJsonPath, "utf-8");
|
|
1269
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
1270
|
-
packageJson.name = projectName;
|
|
1271
|
-
await fs5.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
1272
|
-
} catch (error) {
|
|
1273
|
-
logger.warn(`Could not update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
async function installDependencies(projectPath, packageManager) {
|
|
1277
|
-
const spinner5 = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
1278
|
-
try {
|
|
1279
|
-
const pm = packageManager || getPackageManager();
|
|
1280
|
-
const installCommand = shellQuote.quote([pm, "install"]);
|
|
1281
|
-
await exec(installCommand, {
|
|
1282
|
-
cwd: projectPath
|
|
1283
|
-
});
|
|
1284
|
-
spinner5.success("Dependencies installed successfully");
|
|
1285
|
-
} catch (error) {
|
|
1286
|
-
spinner5.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1287
|
-
throw error;
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
|
|
1291
|
-
async function loadTemplates() {
|
|
1292
|
-
try {
|
|
1293
|
-
const response = await fetch(TEMPLATES_API_URL);
|
|
1294
|
-
if (!response.ok) {
|
|
1295
|
-
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
1296
|
-
}
|
|
1297
|
-
const templates = await response.json();
|
|
1298
|
-
return templates;
|
|
1299
|
-
} catch (error) {
|
|
1300
|
-
console.error("Error loading templates:", error);
|
|
1301
|
-
throw new Error("Failed to load templates. Please check your internet connection and try again.");
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
function pluralize(count, singular, plural) {
|
|
1305
|
-
return count === 1 ? singular : plural || `${singular}s`;
|
|
1306
|
-
}
|
|
1307
|
-
async function selectTemplate(templates) {
|
|
1308
|
-
const choices = templates.map((template) => {
|
|
1309
|
-
const parts = [];
|
|
1310
|
-
if (template.agents?.length) {
|
|
1311
|
-
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
|
|
1312
|
-
}
|
|
1313
|
-
if (template.tools?.length) {
|
|
1314
|
-
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
|
|
1315
|
-
}
|
|
1316
|
-
if (template.workflows?.length) {
|
|
1317
|
-
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
|
|
1318
|
-
}
|
|
1319
|
-
if (template.mcp?.length) {
|
|
1320
|
-
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
|
|
1321
|
-
}
|
|
1322
|
-
if (template.networks?.length) {
|
|
1323
|
-
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
|
|
1324
|
-
}
|
|
1325
|
-
return {
|
|
1326
|
-
value: template,
|
|
1327
|
-
label: template.title,
|
|
1328
|
-
hint: parts.join(", ") || "Template components"
|
|
1329
|
-
};
|
|
1330
|
-
});
|
|
1331
|
-
const selected = await ve({
|
|
1332
|
-
message: "Select a template:",
|
|
1333
|
-
options: choices
|
|
1334
|
-
});
|
|
1335
|
-
if (pD(selected)) {
|
|
1336
|
-
return null;
|
|
1337
|
-
}
|
|
1338
|
-
return selected;
|
|
1339
|
-
}
|
|
1340
|
-
function findTemplateByName(templates, templateName) {
|
|
1341
|
-
let template = templates.find((t) => t.slug === templateName);
|
|
1342
|
-
if (template) return template;
|
|
1343
|
-
const slugWithPrefix = `template-${templateName}`;
|
|
1344
|
-
template = templates.find((t) => t.slug === slugWithPrefix);
|
|
1345
|
-
if (template) return template;
|
|
1346
|
-
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
|
|
1347
|
-
if (template) return template;
|
|
1348
|
-
return null;
|
|
1349
|
-
}
|
|
1350
|
-
function getDefaultProjectName(template) {
|
|
1351
|
-
return template.slug.replace(/^template-/, "");
|
|
1352
|
-
}
|
|
1353
|
-
function getPackageManagerAddCommand(pm) {
|
|
1354
|
-
switch (pm) {
|
|
1355
|
-
case "npm":
|
|
1356
|
-
return "install --audit=false --fund=false --loglevel=error --progress=false --update-notifier=false";
|
|
1357
|
-
case "yarn":
|
|
1358
|
-
return "add";
|
|
1359
|
-
case "pnpm":
|
|
1360
|
-
return "add --loglevel=error";
|
|
1361
|
-
case "bun":
|
|
1362
|
-
return "add";
|
|
1363
|
-
default:
|
|
1364
|
-
return "add";
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
var DepsService = class {
|
|
1368
|
-
packageManager;
|
|
1369
|
-
constructor() {
|
|
1370
|
-
this.packageManager = this.getPackageManager();
|
|
1371
|
-
}
|
|
1372
|
-
findLockFile(dir) {
|
|
1373
|
-
const lockFiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock"];
|
|
1374
|
-
for (const file of lockFiles) {
|
|
1375
|
-
if (fs4__default__default.existsSync(path3.join(dir, file))) {
|
|
1376
|
-
return file;
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
const parentDir = path3.resolve(dir, "..");
|
|
1380
|
-
if (parentDir !== dir) {
|
|
1381
|
-
return this.findLockFile(parentDir);
|
|
1382
|
-
}
|
|
1383
|
-
return null;
|
|
1384
|
-
}
|
|
1385
|
-
getPackageManager() {
|
|
1386
|
-
const lockFile = this.findLockFile(process.cwd());
|
|
1387
|
-
switch (lockFile) {
|
|
1388
|
-
case "pnpm-lock.yaml":
|
|
1389
|
-
return "pnpm";
|
|
1390
|
-
case "package-lock.json":
|
|
1391
|
-
return "npm";
|
|
1392
|
-
case "yarn.lock":
|
|
1393
|
-
return "yarn";
|
|
1394
|
-
case "bun.lock":
|
|
1395
|
-
return "bun";
|
|
1396
|
-
default:
|
|
1397
|
-
return "npm";
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
async installPackages(packages) {
|
|
1401
|
-
const pm = this.packageManager;
|
|
1402
|
-
const installCommand = getPackageManagerAddCommand(pm);
|
|
1403
|
-
const packageList = packages.join(" ");
|
|
1404
|
-
return execa(`${pm} ${installCommand} ${packageList}`, {
|
|
1405
|
-
all: true,
|
|
1406
|
-
shell: true,
|
|
1407
|
-
stdio: "inherit"
|
|
1408
|
-
});
|
|
1409
|
-
}
|
|
1410
|
-
async checkDependencies(dependencies) {
|
|
1411
|
-
try {
|
|
1412
|
-
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1413
|
-
try {
|
|
1414
|
-
await fs5.access(packageJsonPath);
|
|
1415
|
-
} catch {
|
|
1416
|
-
return "No package.json file found in the current directory";
|
|
1417
|
-
}
|
|
1418
|
-
const packageJson = JSON.parse(await fs5.readFile(packageJsonPath, "utf-8"));
|
|
1419
|
-
for (const dependency of dependencies) {
|
|
1420
|
-
if (!packageJson.dependencies || !packageJson.dependencies[dependency]) {
|
|
1421
|
-
return `Please install ${dependency} before running this command (${this.packageManager} install ${dependency})`;
|
|
1422
|
-
}
|
|
1423
|
-
}
|
|
1424
|
-
return "ok";
|
|
1425
|
-
} catch (err) {
|
|
1426
|
-
console.error(err);
|
|
1427
|
-
return "Could not check dependencies";
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1430
|
-
async getProjectName() {
|
|
1431
|
-
try {
|
|
1432
|
-
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1433
|
-
const packageJson = await fs5.readFile(packageJsonPath, "utf-8");
|
|
1434
|
-
const pkg = JSON.parse(packageJson);
|
|
1435
|
-
return pkg.name;
|
|
1436
|
-
} catch (err) {
|
|
1437
|
-
throw err;
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
async addScriptsToPackageJson(scripts) {
|
|
1441
|
-
const packageJson = JSON.parse(await fs5.readFile("package.json", "utf-8"));
|
|
1442
|
-
packageJson.scripts = {
|
|
1443
|
-
...packageJson.scripts,
|
|
1444
|
-
...scripts
|
|
1445
|
-
};
|
|
1446
|
-
await fs5.writeFile("package.json", JSON.stringify(packageJson, null, 2));
|
|
1447
|
-
}
|
|
1448
|
-
};
|
|
1449
1181
|
var args = ["-y", "@mastra/mcp-docs-server"];
|
|
1450
1182
|
var createMcpConfig = (editor) => {
|
|
1451
1183
|
if (editor === "vscode") {
|
|
@@ -1498,19 +1230,19 @@ async function writeMergedConfig(configPath, editor) {
|
|
|
1498
1230
|
spaces: 2
|
|
1499
1231
|
});
|
|
1500
1232
|
}
|
|
1501
|
-
var windsurfGlobalMCPConfigPath =
|
|
1502
|
-
var cursorGlobalMCPConfigPath =
|
|
1503
|
-
|
|
1504
|
-
var vscodeGlobalMCPConfigPath =
|
|
1233
|
+
var windsurfGlobalMCPConfigPath = path.join(os.homedir(), ".codeium", "windsurf", "mcp_config.json");
|
|
1234
|
+
var cursorGlobalMCPConfigPath = path.join(os.homedir(), ".cursor", "mcp.json");
|
|
1235
|
+
path.join(process.cwd(), ".vscode", "mcp.json");
|
|
1236
|
+
var vscodeGlobalMCPConfigPath = path.join(
|
|
1505
1237
|
os.homedir(),
|
|
1506
|
-
process.platform === "win32" ?
|
|
1238
|
+
process.platform === "win32" ? path.join("AppData", "Roaming", "Code", "User", "settings.json") : process.platform === "darwin" ? path.join("Library", "Application Support", "Code", "User", "settings.json") : path.join(".config", "Code", "User", "settings.json")
|
|
1507
1239
|
);
|
|
1508
1240
|
async function installMastraDocsMCPServer({ editor, directory }) {
|
|
1509
1241
|
if (editor === `cursor`) {
|
|
1510
|
-
await writeMergedConfig(
|
|
1242
|
+
await writeMergedConfig(path.join(directory, ".cursor", "mcp.json"), "cursor");
|
|
1511
1243
|
}
|
|
1512
1244
|
if (editor === `vscode`) {
|
|
1513
|
-
await writeMergedConfig(
|
|
1245
|
+
await writeMergedConfig(path.join(directory, ".vscode", "mcp.json"), "vscode");
|
|
1514
1246
|
}
|
|
1515
1247
|
if (editor === `cursor-global`) {
|
|
1516
1248
|
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor);
|
|
@@ -1558,25 +1290,121 @@ async function globalMCPIsAlreadyInstalled(editor) {
|
|
|
1558
1290
|
return false;
|
|
1559
1291
|
}
|
|
1560
1292
|
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1293
|
+
function getPackageManagerAddCommand(pm) {
|
|
1294
|
+
switch (pm) {
|
|
1295
|
+
case "npm":
|
|
1296
|
+
return "install --audit=false --fund=false --loglevel=error --progress=false --update-notifier=false";
|
|
1297
|
+
case "yarn":
|
|
1298
|
+
return "add";
|
|
1299
|
+
case "pnpm":
|
|
1300
|
+
return "add --loglevel=error";
|
|
1301
|
+
case "bun":
|
|
1302
|
+
return "add";
|
|
1303
|
+
default:
|
|
1304
|
+
return "add";
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
var DepsService = class {
|
|
1308
|
+
packageManager;
|
|
1309
|
+
constructor() {
|
|
1310
|
+
this.packageManager = this.getPackageManager();
|
|
1311
|
+
}
|
|
1312
|
+
findLockFile(dir) {
|
|
1313
|
+
const lockFiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock"];
|
|
1314
|
+
for (const file of lockFiles) {
|
|
1315
|
+
if (fs3__default__default.existsSync(path.join(dir, file))) {
|
|
1316
|
+
return file;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
const parentDir = path.resolve(dir, "..");
|
|
1320
|
+
if (parentDir !== dir) {
|
|
1321
|
+
return this.findLockFile(parentDir);
|
|
1322
|
+
}
|
|
1323
|
+
return null;
|
|
1324
|
+
}
|
|
1325
|
+
getPackageManager() {
|
|
1326
|
+
const lockFile = this.findLockFile(process.cwd());
|
|
1327
|
+
switch (lockFile) {
|
|
1328
|
+
case "pnpm-lock.yaml":
|
|
1329
|
+
return "pnpm";
|
|
1330
|
+
case "package-lock.json":
|
|
1331
|
+
return "npm";
|
|
1332
|
+
case "yarn.lock":
|
|
1333
|
+
return "yarn";
|
|
1334
|
+
case "bun.lock":
|
|
1335
|
+
return "bun";
|
|
1336
|
+
default:
|
|
1337
|
+
return "npm";
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
async installPackages(packages) {
|
|
1341
|
+
const pm = this.packageManager;
|
|
1342
|
+
const installCommand = getPackageManagerAddCommand(pm);
|
|
1343
|
+
const packageList = packages.join(" ");
|
|
1344
|
+
return execa(`${pm} ${installCommand} ${packageList}`, {
|
|
1345
|
+
all: true,
|
|
1346
|
+
shell: true,
|
|
1347
|
+
stdio: "inherit"
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
async checkDependencies(dependencies) {
|
|
1351
|
+
try {
|
|
1352
|
+
const packageJsonPath = path.join(process.cwd(), "package.json");
|
|
1353
|
+
try {
|
|
1354
|
+
await fs4.access(packageJsonPath);
|
|
1355
|
+
} catch {
|
|
1356
|
+
return "No package.json file found in the current directory";
|
|
1357
|
+
}
|
|
1358
|
+
const packageJson = JSON.parse(await fs4.readFile(packageJsonPath, "utf-8"));
|
|
1359
|
+
for (const dependency of dependencies) {
|
|
1360
|
+
if (!packageJson.dependencies || !packageJson.dependencies[dependency]) {
|
|
1361
|
+
return `Please install ${dependency} before running this command (${this.packageManager} install ${dependency})`;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
return "ok";
|
|
1365
|
+
} catch (err) {
|
|
1366
|
+
console.error(err);
|
|
1367
|
+
return "Could not check dependencies";
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
async getProjectName() {
|
|
1371
|
+
try {
|
|
1372
|
+
const packageJsonPath = path.join(process.cwd(), "package.json");
|
|
1373
|
+
const packageJson = await fs4.readFile(packageJsonPath, "utf-8");
|
|
1374
|
+
const pkg = JSON.parse(packageJson);
|
|
1375
|
+
return pkg.name;
|
|
1376
|
+
} catch (err) {
|
|
1377
|
+
throw err;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
async addScriptsToPackageJson(scripts) {
|
|
1381
|
+
const packageJson = JSON.parse(await fs4.readFile("package.json", "utf-8"));
|
|
1382
|
+
packageJson.scripts = {
|
|
1383
|
+
...packageJson.scripts,
|
|
1384
|
+
...scripts
|
|
1385
|
+
};
|
|
1386
|
+
await fs4.writeFile("package.json", JSON.stringify(packageJson, null, 2));
|
|
1387
|
+
}
|
|
1388
|
+
};
|
|
1389
|
+
var EnvService = class {
|
|
1390
|
+
};
|
|
1391
|
+
var FileEnvService = class extends EnvService {
|
|
1392
|
+
filePath;
|
|
1393
|
+
constructor(filePath) {
|
|
1394
|
+
super();
|
|
1395
|
+
this.filePath = filePath;
|
|
1396
|
+
}
|
|
1397
|
+
readFile(filePath) {
|
|
1398
|
+
return new Promise((resolve, reject) => {
|
|
1399
|
+
fs3__default.readFile(filePath, "utf8", (err, data) => {
|
|
1400
|
+
if (err) reject(err);
|
|
1401
|
+
else resolve(data);
|
|
1574
1402
|
});
|
|
1575
1403
|
});
|
|
1576
1404
|
}
|
|
1577
1405
|
writeFile({ filePath, data }) {
|
|
1578
1406
|
return new Promise((resolve, reject) => {
|
|
1579
|
-
|
|
1407
|
+
fs3__default.writeFile(filePath, data, "utf8", (err) => {
|
|
1580
1408
|
if (err) reject(err);
|
|
1581
1409
|
else resolve();
|
|
1582
1410
|
});
|
|
@@ -1629,10 +1457,10 @@ var FileService = class {
|
|
|
1629
1457
|
*/
|
|
1630
1458
|
async copyStarterFile(inputFile, outputFilePath, replaceIfExists) {
|
|
1631
1459
|
const __filename = fileURLToPath(import.meta.url);
|
|
1632
|
-
const __dirname =
|
|
1633
|
-
const filePath =
|
|
1634
|
-
const fileString =
|
|
1635
|
-
if (
|
|
1460
|
+
const __dirname = path.dirname(__filename);
|
|
1461
|
+
const filePath = path.resolve(__dirname, "starter-files", inputFile);
|
|
1462
|
+
const fileString = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1463
|
+
if (fs3__default__default.existsSync(outputFilePath) && !replaceIfExists) {
|
|
1636
1464
|
console.info(`${outputFilePath} already exists`);
|
|
1637
1465
|
return false;
|
|
1638
1466
|
}
|
|
@@ -1640,14 +1468,14 @@ var FileService = class {
|
|
|
1640
1468
|
return true;
|
|
1641
1469
|
}
|
|
1642
1470
|
async setupEnvFile({ dbUrl }) {
|
|
1643
|
-
const envPath =
|
|
1471
|
+
const envPath = path.join(process.cwd(), ".env.development");
|
|
1644
1472
|
await fsExtra.ensureFile(envPath);
|
|
1645
1473
|
const fileEnvService = new FileEnvService(envPath);
|
|
1646
1474
|
await fileEnvService.setEnvValue("DB_URL", dbUrl);
|
|
1647
1475
|
}
|
|
1648
1476
|
getFirstExistingFile(files) {
|
|
1649
1477
|
for (const f of files) {
|
|
1650
|
-
if (
|
|
1478
|
+
if (fs3__default__default.existsSync(f)) {
|
|
1651
1479
|
return f;
|
|
1652
1480
|
}
|
|
1653
1481
|
}
|
|
@@ -1657,66 +1485,31 @@ var FileService = class {
|
|
|
1657
1485
|
filePath,
|
|
1658
1486
|
replacements
|
|
1659
1487
|
}) {
|
|
1660
|
-
let fileContent =
|
|
1488
|
+
let fileContent = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1661
1489
|
replacements.forEach(({ search, replace }) => {
|
|
1662
1490
|
fileContent = fileContent.replaceAll(search, replace);
|
|
1663
1491
|
});
|
|
1664
|
-
|
|
1492
|
+
fs3__default__default.writeFileSync(filePath, fileContent);
|
|
1665
1493
|
}
|
|
1666
1494
|
};
|
|
1667
|
-
var
|
|
1668
|
-
var
|
|
1669
|
-
switch (llmProvider) {
|
|
1670
|
-
case "cerebras":
|
|
1671
|
-
return "^0.2.14";
|
|
1672
|
-
default:
|
|
1673
|
-
return "^1.0.0";
|
|
1674
|
-
}
|
|
1675
|
-
};
|
|
1676
|
-
var getAISDKPackage = (llmProvider) => {
|
|
1677
|
-
switch (llmProvider) {
|
|
1678
|
-
case "openai":
|
|
1679
|
-
return "@ai-sdk/openai";
|
|
1680
|
-
case "anthropic":
|
|
1681
|
-
return "@ai-sdk/anthropic";
|
|
1682
|
-
case "groq":
|
|
1683
|
-
return "@ai-sdk/groq";
|
|
1684
|
-
case "google":
|
|
1685
|
-
return "@ai-sdk/google";
|
|
1686
|
-
case "cerebras":
|
|
1687
|
-
return "@ai-sdk/cerebras";
|
|
1688
|
-
case "mistral":
|
|
1689
|
-
return "@ai-sdk/mistral";
|
|
1690
|
-
default:
|
|
1691
|
-
return "@ai-sdk/openai";
|
|
1692
|
-
}
|
|
1693
|
-
};
|
|
1694
|
-
var getProviderImportAndModelItem = (llmProvider) => {
|
|
1695
|
-
let providerImport = "";
|
|
1696
|
-
let modelItem = "";
|
|
1495
|
+
var exec = util.promisify(child_process.exec);
|
|
1496
|
+
var getModelIdentifier = (llmProvider) => {
|
|
1697
1497
|
if (llmProvider === "openai") {
|
|
1698
|
-
|
|
1699
|
-
modelItem = `openai('gpt-4o-mini')`;
|
|
1498
|
+
return `'openai/gpt-4o-mini'`;
|
|
1700
1499
|
} else if (llmProvider === "anthropic") {
|
|
1701
|
-
|
|
1702
|
-
modelItem = `anthropic('claude-3-5-sonnet-20241022')`;
|
|
1500
|
+
return `'anthropic/claude-sonnet-4-5-20250929'`;
|
|
1703
1501
|
} else if (llmProvider === "groq") {
|
|
1704
|
-
|
|
1705
|
-
modelItem = `groq('llama-3.3-70b-versatile')`;
|
|
1502
|
+
return `'groq/llama-3.3-70b-versatile'`;
|
|
1706
1503
|
} else if (llmProvider === "google") {
|
|
1707
|
-
|
|
1708
|
-
modelItem = `google('gemini-2.5-pro')`;
|
|
1504
|
+
return `'google/gemini-2.5-pro'`;
|
|
1709
1505
|
} else if (llmProvider === "cerebras") {
|
|
1710
|
-
|
|
1711
|
-
modelItem = `cerebras('llama-3.3-70b')`;
|
|
1506
|
+
return `'cerebras/llama-3.3-70b'`;
|
|
1712
1507
|
} else if (llmProvider === "mistral") {
|
|
1713
|
-
|
|
1714
|
-
modelItem = `mistral('mistral-medium-2508')`;
|
|
1508
|
+
return `'mistral/mistral-medium-2508'`;
|
|
1715
1509
|
}
|
|
1716
|
-
return { providerImport, modelItem };
|
|
1717
1510
|
};
|
|
1718
|
-
async function writeAgentSample(llmProvider, destPath, addExampleTool) {
|
|
1719
|
-
const
|
|
1511
|
+
async function writeAgentSample(llmProvider, destPath, addExampleTool, addScorers) {
|
|
1512
|
+
const modelString = getModelIdentifier(llmProvider);
|
|
1720
1513
|
const instructions = `
|
|
1721
1514
|
You are a helpful weather assistant that provides accurate weather information and can help planning activities based on the weather.
|
|
1722
1515
|
|
|
@@ -1732,17 +1525,40 @@ async function writeAgentSample(llmProvider, destPath, addExampleTool) {
|
|
|
1732
1525
|
${addExampleTool ? "Use the weatherTool to fetch current weather data." : ""}
|
|
1733
1526
|
`;
|
|
1734
1527
|
const content = `
|
|
1735
|
-
${providerImport}
|
|
1736
1528
|
import { Agent } from '@mastra/core/agent';
|
|
1737
1529
|
import { Memory } from '@mastra/memory';
|
|
1738
1530
|
import { LibSQLStore } from '@mastra/libsql';
|
|
1739
1531
|
${addExampleTool ? `import { weatherTool } from '../tools/weather-tool';` : ""}
|
|
1532
|
+
${addScorers ? `import { scorers } from '../scorers/weather-scorer';` : ""}
|
|
1740
1533
|
|
|
1741
1534
|
export const weatherAgent = new Agent({
|
|
1742
1535
|
name: 'Weather Agent',
|
|
1743
1536
|
instructions: \`${instructions}\`,
|
|
1744
|
-
model: ${
|
|
1537
|
+
model: ${modelString},
|
|
1745
1538
|
${addExampleTool ? "tools: { weatherTool }," : ""}
|
|
1539
|
+
${addScorers ? `scorers: {
|
|
1540
|
+
toolCallAppropriateness: {
|
|
1541
|
+
scorer: scorers.toolCallAppropriatenessScorer,
|
|
1542
|
+
sampling: {
|
|
1543
|
+
type: 'ratio',
|
|
1544
|
+
rate: 1,
|
|
1545
|
+
},
|
|
1546
|
+
},
|
|
1547
|
+
completeness: {
|
|
1548
|
+
scorer: scorers.completenessScorer,
|
|
1549
|
+
sampling: {
|
|
1550
|
+
type: 'ratio',
|
|
1551
|
+
rate: 1,
|
|
1552
|
+
},
|
|
1553
|
+
},
|
|
1554
|
+
translation: {
|
|
1555
|
+
scorer: scorers.translationScorer,
|
|
1556
|
+
sampling: {
|
|
1557
|
+
type: 'ratio',
|
|
1558
|
+
rate: 1,
|
|
1559
|
+
},
|
|
1560
|
+
},
|
|
1561
|
+
},` : ""}
|
|
1746
1562
|
memory: new Memory({
|
|
1747
1563
|
storage: new LibSQLStore({
|
|
1748
1564
|
url: "file:../mastra.db", // path is relative to the .mastra/output directory
|
|
@@ -1754,8 +1570,8 @@ export const weatherAgent = new Agent({
|
|
|
1754
1570
|
parser: "typescript",
|
|
1755
1571
|
singleQuote: true
|
|
1756
1572
|
});
|
|
1757
|
-
await
|
|
1758
|
-
await
|
|
1573
|
+
await fs4.writeFile(destPath, "");
|
|
1574
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1759
1575
|
}
|
|
1760
1576
|
async function writeWorkflowSample(destPath) {
|
|
1761
1577
|
const content = `import { createStep, createWorkflow } from '@mastra/core/workflows';
|
|
@@ -1948,20 +1764,113 @@ export { weatherWorkflow };`;
|
|
|
1948
1764
|
semi: true,
|
|
1949
1765
|
singleQuote: true
|
|
1950
1766
|
});
|
|
1951
|
-
await
|
|
1767
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1952
1768
|
}
|
|
1953
1769
|
async function writeToolSample(destPath) {
|
|
1954
1770
|
const fileService = new FileService();
|
|
1955
1771
|
await fileService.copyStarterFile("tools.ts", destPath);
|
|
1956
1772
|
}
|
|
1773
|
+
async function writeScorersSample(llmProvider, destPath) {
|
|
1774
|
+
const modelString = getModelIdentifier(llmProvider);
|
|
1775
|
+
const content = `import { z } from 'zod';
|
|
1776
|
+
import { createToolCallAccuracyScorerCode } from '@mastra/evals/scorers/code';
|
|
1777
|
+
import { createCompletenessScorer } from '@mastra/evals/scorers/code';
|
|
1778
|
+
import { createScorer } from '@mastra/core/scores';
|
|
1779
|
+
|
|
1780
|
+
export const toolCallAppropriatenessScorer = createToolCallAccuracyScorerCode({
|
|
1781
|
+
expectedTool: 'weatherTool',
|
|
1782
|
+
strictMode: false,
|
|
1783
|
+
});
|
|
1784
|
+
|
|
1785
|
+
export const completenessScorer = createCompletenessScorer();
|
|
1786
|
+
|
|
1787
|
+
// Custom LLM-judged scorer: evaluates if non-English locations are translated appropriately
|
|
1788
|
+
export const translationScorer = createScorer({
|
|
1789
|
+
name: 'Translation Quality',
|
|
1790
|
+
description: 'Checks that non-English location names are translated and used correctly',
|
|
1791
|
+
type: 'agent',
|
|
1792
|
+
judge: {
|
|
1793
|
+
model: ${modelString},
|
|
1794
|
+
instructions:
|
|
1795
|
+
'You are an expert evaluator of translation quality for geographic locations. ' +
|
|
1796
|
+
'Determine whether the user text mentions a non-English location and whether the assistant correctly uses an English translation of that location. ' +
|
|
1797
|
+
'Be lenient with transliteration differences and diacritics. ' +
|
|
1798
|
+
'Return only the structured JSON matching the provided schema.',
|
|
1799
|
+
},
|
|
1800
|
+
})
|
|
1801
|
+
.preprocess(({ run }) => {
|
|
1802
|
+
const userText = (run.input?.inputMessages?.[0]?.content as string) || '';
|
|
1803
|
+
const assistantText = (run.output?.[0]?.content as string) || '';
|
|
1804
|
+
return { userText, assistantText };
|
|
1805
|
+
})
|
|
1806
|
+
.analyze({
|
|
1807
|
+
description: 'Extract location names and detect language/translation adequacy',
|
|
1808
|
+
outputSchema: z.object({
|
|
1809
|
+
nonEnglish: z.boolean(),
|
|
1810
|
+
translated: z.boolean(),
|
|
1811
|
+
confidence: z.number().min(0).max(1).default(1),
|
|
1812
|
+
explanation: z.string().default(''),
|
|
1813
|
+
}),
|
|
1814
|
+
createPrompt: ({ results }) => \`
|
|
1815
|
+
You are evaluating if a weather assistant correctly handled translation of a non-English location.
|
|
1816
|
+
User text:
|
|
1817
|
+
"""
|
|
1818
|
+
\${results.preprocessStepResult.userText}
|
|
1819
|
+
"""
|
|
1820
|
+
Assistant response:
|
|
1821
|
+
"""
|
|
1822
|
+
\${results.preprocessStepResult.assistantText}
|
|
1823
|
+
"""
|
|
1824
|
+
Tasks:
|
|
1825
|
+
1) Identify if the user mentioned a location that appears non-English.
|
|
1826
|
+
2) If non-English, check whether the assistant used a correct English translation of that location in its response.
|
|
1827
|
+
3) Be lenient with transliteration differences (e.g., accents/diacritics).
|
|
1828
|
+
Return JSON with fields:
|
|
1829
|
+
{
|
|
1830
|
+
"nonEnglish": boolean,
|
|
1831
|
+
"translated": boolean,
|
|
1832
|
+
"confidence": number, // 0-1
|
|
1833
|
+
"explanation": string
|
|
1834
|
+
}
|
|
1835
|
+
\`,
|
|
1836
|
+
})
|
|
1837
|
+
.generateScore(({ results }) => {
|
|
1838
|
+
const r = (results as any)?.analyzeStepResult || {};
|
|
1839
|
+
if (!r.nonEnglish) return 1; // If not applicable, full credit
|
|
1840
|
+
if (r.translated) return Math.max(0, Math.min(1, 0.7 + 0.3 * (r.confidence ?? 1)));
|
|
1841
|
+
return 0; // Non-English but not translated
|
|
1842
|
+
})
|
|
1843
|
+
.generateReason(({ results, score }) => {
|
|
1844
|
+
const r = (results as any)?.analyzeStepResult || {};
|
|
1845
|
+
return \`Translation scoring: nonEnglish=\${r.nonEnglish ?? false}, translated=\${r.translated ?? false}, confidence=\${r.confidence ?? 0}. Score=\${score}. \${r.explanation ?? ''}\`;
|
|
1846
|
+
});
|
|
1847
|
+
|
|
1848
|
+
export const scorers = {
|
|
1849
|
+
toolCallAppropriatenessScorer,
|
|
1850
|
+
completenessScorer,
|
|
1851
|
+
translationScorer,
|
|
1852
|
+
};`;
|
|
1853
|
+
const formattedContent = await prettier.format(content, {
|
|
1854
|
+
parser: "typescript",
|
|
1855
|
+
singleQuote: true
|
|
1856
|
+
});
|
|
1857
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1858
|
+
}
|
|
1957
1859
|
async function writeCodeSampleForComponents(llmprovider, component, destPath, importComponents) {
|
|
1958
1860
|
switch (component) {
|
|
1959
1861
|
case "agents":
|
|
1960
|
-
return writeAgentSample(
|
|
1862
|
+
return writeAgentSample(
|
|
1863
|
+
llmprovider,
|
|
1864
|
+
destPath,
|
|
1865
|
+
importComponents.includes("tools"),
|
|
1866
|
+
importComponents.includes("scorers")
|
|
1867
|
+
);
|
|
1961
1868
|
case "tools":
|
|
1962
1869
|
return writeToolSample(destPath);
|
|
1963
1870
|
case "workflows":
|
|
1964
1871
|
return writeWorkflowSample(destPath);
|
|
1872
|
+
case "scorers":
|
|
1873
|
+
return writeScorersSample(llmprovider, destPath);
|
|
1965
1874
|
default:
|
|
1966
1875
|
return "";
|
|
1967
1876
|
}
|
|
@@ -1974,18 +1883,20 @@ var writeIndexFile = async ({
|
|
|
1974
1883
|
dirPath,
|
|
1975
1884
|
addAgent,
|
|
1976
1885
|
addExample,
|
|
1977
|
-
addWorkflow
|
|
1886
|
+
addWorkflow,
|
|
1887
|
+
addScorers
|
|
1978
1888
|
}) => {
|
|
1979
1889
|
const indexPath = dirPath + "/index.ts";
|
|
1980
|
-
const destPath =
|
|
1890
|
+
const destPath = path.join(indexPath);
|
|
1981
1891
|
try {
|
|
1982
|
-
await
|
|
1892
|
+
await fs4.writeFile(destPath, "");
|
|
1983
1893
|
const filteredExports = [
|
|
1984
1894
|
addWorkflow ? `workflows: { weatherWorkflow },` : "",
|
|
1985
|
-
addAgent ? `agents: { weatherAgent },` : ""
|
|
1895
|
+
addAgent ? `agents: { weatherAgent },` : "",
|
|
1896
|
+
addScorers ? `scorers: { toolCallAppropriatenessScorer, completenessScorer, translationScorer },` : ""
|
|
1986
1897
|
].filter(Boolean);
|
|
1987
1898
|
if (!addExample) {
|
|
1988
|
-
await
|
|
1899
|
+
await fs4.writeFile(
|
|
1989
1900
|
destPath,
|
|
1990
1901
|
`
|
|
1991
1902
|
import { Mastra } from '@mastra/core';
|
|
@@ -1995,7 +1906,7 @@ export const mastra = new Mastra()
|
|
|
1995
1906
|
);
|
|
1996
1907
|
return;
|
|
1997
1908
|
}
|
|
1998
|
-
await
|
|
1909
|
+
await fs4.writeFile(
|
|
1999
1910
|
destPath,
|
|
2000
1911
|
`
|
|
2001
1912
|
import { Mastra } from '@mastra/core/mastra';
|
|
@@ -2003,17 +1914,26 @@ import { PinoLogger } from '@mastra/loggers';
|
|
|
2003
1914
|
import { LibSQLStore } from '@mastra/libsql';
|
|
2004
1915
|
${addWorkflow ? `import { weatherWorkflow } from './workflows/weather-workflow';` : ""}
|
|
2005
1916
|
${addAgent ? `import { weatherAgent } from './agents/weather-agent';` : ""}
|
|
1917
|
+
${addScorers ? `import { toolCallAppropriatenessScorer, completenessScorer, translationScorer } from './scorers/weather-scorer';` : ""}
|
|
2006
1918
|
|
|
2007
1919
|
export const mastra = new Mastra({
|
|
2008
1920
|
${filteredExports.join("\n ")}
|
|
2009
1921
|
storage: new LibSQLStore({
|
|
2010
|
-
// stores
|
|
1922
|
+
// stores observability, scores, ... into memory storage, if it needs to persist, change to file:../mastra.db
|
|
2011
1923
|
url: ":memory:",
|
|
2012
1924
|
}),
|
|
2013
1925
|
logger: new PinoLogger({
|
|
2014
1926
|
name: 'Mastra',
|
|
2015
1927
|
level: 'info',
|
|
2016
1928
|
}),
|
|
1929
|
+
telemetry: {
|
|
1930
|
+
// Telemetry is deprecated and will be removed in the Nov 4th release
|
|
1931
|
+
enabled: false,
|
|
1932
|
+
},
|
|
1933
|
+
observability: {
|
|
1934
|
+
// Enables DefaultExporter and CloudExporter for AI tracing
|
|
1935
|
+
default: { enabled: true },
|
|
1936
|
+
},
|
|
2017
1937
|
});
|
|
2018
1938
|
`
|
|
2019
1939
|
);
|
|
@@ -2021,7 +1941,6 @@ export const mastra = new Mastra({
|
|
|
2021
1941
|
throw err;
|
|
2022
1942
|
}
|
|
2023
1943
|
};
|
|
2024
|
-
yoctoSpinner({ text: "Installing Mastra core dependencies\n" });
|
|
2025
1944
|
var getAPIKey = async (provider) => {
|
|
2026
1945
|
let key = "OPENAI_API_KEY";
|
|
2027
1946
|
switch (provider) {
|
|
@@ -2044,20 +1963,18 @@ var getAPIKey = async (provider) => {
|
|
|
2044
1963
|
return key;
|
|
2045
1964
|
}
|
|
2046
1965
|
};
|
|
2047
|
-
var writeAPIKey = async ({
|
|
2048
|
-
|
|
2049
|
-
apiKey = "your-api-key"
|
|
2050
|
-
}) => {
|
|
1966
|
+
var writeAPIKey = async ({ provider, apiKey }) => {
|
|
1967
|
+
const envFileName = apiKey ? ".env" : ".env.example";
|
|
2051
1968
|
const key = await getAPIKey(provider);
|
|
2052
|
-
const escapedKey =
|
|
2053
|
-
const escapedApiKey =
|
|
2054
|
-
await
|
|
1969
|
+
const escapedKey = shellQuote2.quote([key]);
|
|
1970
|
+
const escapedApiKey = shellQuote2.quote([apiKey ? apiKey : "your-api-key"]);
|
|
1971
|
+
await exec(`echo ${escapedKey}=${escapedApiKey} >> ${envFileName}`);
|
|
2055
1972
|
};
|
|
2056
1973
|
var createMastraDir = async (directory) => {
|
|
2057
1974
|
let dir = directory.trim().split("/").filter((item) => item !== "");
|
|
2058
|
-
const dirPath =
|
|
1975
|
+
const dirPath = path.join(process.cwd(), ...dir, "mastra");
|
|
2059
1976
|
try {
|
|
2060
|
-
await
|
|
1977
|
+
await fs4.access(dirPath);
|
|
2061
1978
|
return { ok: false };
|
|
2062
1979
|
} catch {
|
|
2063
1980
|
await fsExtra.ensureDir(dirPath);
|
|
@@ -2072,8 +1989,19 @@ var writeCodeSample = async (dirPath, component, llmProvider, importComponents)
|
|
|
2072
1989
|
throw err;
|
|
2073
1990
|
}
|
|
2074
1991
|
};
|
|
2075
|
-
var
|
|
2076
|
-
|
|
1992
|
+
var LLM_PROVIDERS = [
|
|
1993
|
+
{ value: "openai", label: "OpenAI", hint: "recommended" },
|
|
1994
|
+
{ value: "anthropic", label: "Anthropic" },
|
|
1995
|
+
{ value: "groq", label: "Groq" },
|
|
1996
|
+
{ value: "google", label: "Google" },
|
|
1997
|
+
{ value: "cerebras", label: "Cerebras" },
|
|
1998
|
+
{ value: "mistral", label: "Mistral" }
|
|
1999
|
+
];
|
|
2000
|
+
var interactivePrompt = async (args2 = {}) => {
|
|
2001
|
+
const { skip = {}, options: { showBanner = true } = {} } = args2;
|
|
2002
|
+
if (showBanner) {
|
|
2003
|
+
Ie(color2.inverse(" Mastra Init "));
|
|
2004
|
+
}
|
|
2077
2005
|
const mastraProject = await Ce(
|
|
2078
2006
|
{
|
|
2079
2007
|
directory: () => he({
|
|
@@ -2081,20 +2009,15 @@ var interactivePrompt = async () => {
|
|
|
2081
2009
|
placeholder: "src/",
|
|
2082
2010
|
defaultValue: "src/"
|
|
2083
2011
|
}),
|
|
2084
|
-
llmProvider: () => ve({
|
|
2085
|
-
message: "Select default provider:",
|
|
2086
|
-
options:
|
|
2087
|
-
{ value: "openai", label: "OpenAI", hint: "recommended" },
|
|
2088
|
-
{ value: "anthropic", label: "Anthropic" },
|
|
2089
|
-
{ value: "groq", label: "Groq" },
|
|
2090
|
-
{ value: "google", label: "Google" },
|
|
2091
|
-
{ value: "cerebras", label: "Cerebras" },
|
|
2092
|
-
{ value: "mistral", label: "Mistral" }
|
|
2093
|
-
]
|
|
2012
|
+
llmProvider: () => skip?.llmProvider ? void 0 : ve({
|
|
2013
|
+
message: "Select a default provider:",
|
|
2014
|
+
options: LLM_PROVIDERS
|
|
2094
2015
|
}),
|
|
2095
2016
|
llmApiKey: async ({ results: { llmProvider } }) => {
|
|
2017
|
+
if (skip?.llmApiKey) return void 0;
|
|
2018
|
+
const llmName = LLM_PROVIDERS.find((p6) => p6.value === llmProvider)?.label || "provider";
|
|
2096
2019
|
const keyChoice = await ve({
|
|
2097
|
-
message: `Enter your ${
|
|
2020
|
+
message: `Enter your ${llmName} API key?`,
|
|
2098
2021
|
options: [
|
|
2099
2022
|
{ value: "skip", label: "Skip for now", hint: "default" },
|
|
2100
2023
|
{ value: "enter", label: "Enter API key" }
|
|
@@ -2104,7 +2027,10 @@ var interactivePrompt = async () => {
|
|
|
2104
2027
|
if (keyChoice === "enter") {
|
|
2105
2028
|
return he({
|
|
2106
2029
|
message: "Enter your API key:",
|
|
2107
|
-
placeholder: "sk-..."
|
|
2030
|
+
placeholder: "sk-...",
|
|
2031
|
+
validate: (value) => {
|
|
2032
|
+
if (value.length === 0) return "API key cannot be empty";
|
|
2033
|
+
}
|
|
2108
2034
|
});
|
|
2109
2035
|
}
|
|
2110
2036
|
return void 0;
|
|
@@ -2114,7 +2040,7 @@ var interactivePrompt = async () => {
|
|
|
2114
2040
|
const cursorIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`cursor`);
|
|
2115
2041
|
const vscodeIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`vscode`);
|
|
2116
2042
|
const editor = await ve({
|
|
2117
|
-
message: `Make your
|
|
2043
|
+
message: `Make your IDE into a Mastra expert? (Installs Mastra's MCP server)`,
|
|
2118
2044
|
options: [
|
|
2119
2045
|
{ value: "skip", label: "Skip for now", hint: "default" },
|
|
2120
2046
|
{
|
|
@@ -2158,19 +2084,19 @@ Note: you will need to go into Cursor Settings -> MCP Settings and manually enab
|
|
|
2158
2084
|
);
|
|
2159
2085
|
}
|
|
2160
2086
|
if (editor === `cursor-global`) {
|
|
2161
|
-
const
|
|
2087
|
+
const confirm = await ve({
|
|
2162
2088
|
message: `Global install will add/update ${cursorGlobalMCPConfigPath} and make the Mastra docs MCP server available in all your Cursor projects. Continue?`,
|
|
2163
2089
|
options: [
|
|
2164
2090
|
{ value: "yes", label: "Yes, I understand" },
|
|
2165
2091
|
{ value: "skip", label: "No, skip for now" }
|
|
2166
2092
|
]
|
|
2167
2093
|
});
|
|
2168
|
-
if (
|
|
2094
|
+
if (confirm !== `yes`) {
|
|
2169
2095
|
return void 0;
|
|
2170
2096
|
}
|
|
2171
2097
|
}
|
|
2172
2098
|
if (editor === `windsurf`) {
|
|
2173
|
-
const
|
|
2099
|
+
const confirm = await ve({
|
|
2174
2100
|
message: `Windsurf only supports a global MCP config (at ${windsurfGlobalMCPConfigPath}) is it ok to add/update that global config?
|
|
2175
2101
|
This means the Mastra docs MCP server will be available in all your Windsurf projects.`,
|
|
2176
2102
|
options: [
|
|
@@ -2178,7 +2104,7 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2178
2104
|
{ value: "skip", label: "No, skip for now" }
|
|
2179
2105
|
]
|
|
2180
2106
|
});
|
|
2181
|
-
if (
|
|
2107
|
+
if (confirm !== `yes`) {
|
|
2182
2108
|
return void 0;
|
|
2183
2109
|
}
|
|
2184
2110
|
}
|
|
@@ -2194,14 +2120,199 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2194
2120
|
);
|
|
2195
2121
|
return mastraProject;
|
|
2196
2122
|
};
|
|
2123
|
+
function getPackageManager() {
|
|
2124
|
+
const userAgent = process.env.npm_config_user_agent || "";
|
|
2125
|
+
const execPath = process.env.npm_execpath || "";
|
|
2126
|
+
if (userAgent.includes("bun")) {
|
|
2127
|
+
return "bun";
|
|
2128
|
+
}
|
|
2129
|
+
if (userAgent.includes("yarn")) {
|
|
2130
|
+
return "yarn";
|
|
2131
|
+
}
|
|
2132
|
+
if (userAgent.includes("pnpm")) {
|
|
2133
|
+
return "pnpm";
|
|
2134
|
+
}
|
|
2135
|
+
if (userAgent.includes("npm")) {
|
|
2136
|
+
return "npm";
|
|
2137
|
+
}
|
|
2138
|
+
if (execPath.includes("bun")) {
|
|
2139
|
+
return "bun";
|
|
2140
|
+
}
|
|
2141
|
+
if (execPath.includes("yarn")) {
|
|
2142
|
+
return "yarn";
|
|
2143
|
+
}
|
|
2144
|
+
if (execPath.includes("pnpm")) {
|
|
2145
|
+
return "pnpm";
|
|
2146
|
+
}
|
|
2147
|
+
if (execPath.includes("npm")) {
|
|
2148
|
+
return "npm";
|
|
2149
|
+
}
|
|
2150
|
+
return "npm";
|
|
2151
|
+
}
|
|
2152
|
+
var logger = createLogger(false);
|
|
2153
|
+
function createLogger(debug = false) {
|
|
2154
|
+
return new PinoLogger({
|
|
2155
|
+
name: "Mastra CLI",
|
|
2156
|
+
level: debug ? "debug" : "info"
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2159
|
+
var exec2 = util.promisify(child_process.exec);
|
|
2160
|
+
async function cloneTemplate(options) {
|
|
2161
|
+
const { template, projectName, targetDir } = options;
|
|
2162
|
+
const projectPath = targetDir ? path.resolve(targetDir, projectName) : path.resolve(projectName);
|
|
2163
|
+
const spinner4 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
|
|
2164
|
+
try {
|
|
2165
|
+
if (await directoryExists(projectPath)) {
|
|
2166
|
+
spinner4.error(`Directory ${projectName} already exists`);
|
|
2167
|
+
throw new Error(`Directory ${projectName} already exists`);
|
|
2168
|
+
}
|
|
2169
|
+
await cloneRepositoryWithoutGit(template.githubUrl, projectPath);
|
|
2170
|
+
await updatePackageJson(projectPath, projectName);
|
|
2171
|
+
const envExamplePath = path.join(projectPath, ".env.example");
|
|
2172
|
+
if (await fileExists(envExamplePath)) {
|
|
2173
|
+
await fs4.copyFile(envExamplePath, path.join(projectPath, ".env"));
|
|
2174
|
+
}
|
|
2175
|
+
spinner4.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
2176
|
+
return projectPath;
|
|
2177
|
+
} catch (error) {
|
|
2178
|
+
spinner4.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2179
|
+
throw error;
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
async function directoryExists(dirPath) {
|
|
2183
|
+
try {
|
|
2184
|
+
const stat = await fs4.stat(dirPath);
|
|
2185
|
+
return stat.isDirectory();
|
|
2186
|
+
} catch {
|
|
2187
|
+
return false;
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
async function fileExists(filePath) {
|
|
2191
|
+
try {
|
|
2192
|
+
const stat = await fs4.stat(filePath);
|
|
2193
|
+
return stat.isFile();
|
|
2194
|
+
} catch {
|
|
2195
|
+
return false;
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
async function cloneRepositoryWithoutGit(repoUrl, targetPath) {
|
|
2199
|
+
await fs4.mkdir(targetPath, { recursive: true });
|
|
2200
|
+
try {
|
|
2201
|
+
const degitRepo = repoUrl.replace("https://github.com/", "");
|
|
2202
|
+
const degitCommand = shellQuote2.quote(["npx", "degit", degitRepo, targetPath]);
|
|
2203
|
+
await exec2(degitCommand, {
|
|
2204
|
+
cwd: process.cwd()
|
|
2205
|
+
});
|
|
2206
|
+
} catch {
|
|
2207
|
+
try {
|
|
2208
|
+
const gitCommand = shellQuote2.quote(["git", "clone", repoUrl, targetPath]);
|
|
2209
|
+
await exec2(gitCommand, {
|
|
2210
|
+
cwd: process.cwd()
|
|
2211
|
+
});
|
|
2212
|
+
const gitDir = path.join(targetPath, ".git");
|
|
2213
|
+
if (await directoryExists(gitDir)) {
|
|
2214
|
+
await fs4.rm(gitDir, { recursive: true, force: true });
|
|
2215
|
+
}
|
|
2216
|
+
} catch (gitError) {
|
|
2217
|
+
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
async function updatePackageJson(projectPath, projectName) {
|
|
2222
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
2223
|
+
try {
|
|
2224
|
+
const packageJsonContent = await fs4.readFile(packageJsonPath, "utf-8");
|
|
2225
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
2226
|
+
packageJson.name = projectName;
|
|
2227
|
+
await fs4.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
2228
|
+
} catch (error) {
|
|
2229
|
+
logger.warn(`Could not update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
async function installDependencies(projectPath, packageManager) {
|
|
2233
|
+
const spinner4 = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
2234
|
+
try {
|
|
2235
|
+
const pm = packageManager || getPackageManager();
|
|
2236
|
+
const installCommand = shellQuote2.quote([pm, "install"]);
|
|
2237
|
+
await exec2(installCommand, {
|
|
2238
|
+
cwd: projectPath
|
|
2239
|
+
});
|
|
2240
|
+
spinner4.success("Dependencies installed successfully");
|
|
2241
|
+
} catch (error) {
|
|
2242
|
+
spinner4.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2243
|
+
throw error;
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
|
|
2247
|
+
async function loadTemplates() {
|
|
2248
|
+
try {
|
|
2249
|
+
const response = await fetch(TEMPLATES_API_URL);
|
|
2250
|
+
if (!response.ok) {
|
|
2251
|
+
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
2252
|
+
}
|
|
2253
|
+
const templates = await response.json();
|
|
2254
|
+
return templates;
|
|
2255
|
+
} catch (error) {
|
|
2256
|
+
console.error("Error loading templates:", error);
|
|
2257
|
+
throw new Error("Failed to load templates. Please check your internet connection and try again.");
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
function pluralize(count, singular, plural) {
|
|
2261
|
+
return count === 1 ? singular : plural || `${singular}s`;
|
|
2262
|
+
}
|
|
2263
|
+
async function selectTemplate(templates) {
|
|
2264
|
+
const choices = templates.map((template) => {
|
|
2265
|
+
const parts = [];
|
|
2266
|
+
if (template.agents?.length) {
|
|
2267
|
+
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
|
|
2268
|
+
}
|
|
2269
|
+
if (template.tools?.length) {
|
|
2270
|
+
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
|
|
2271
|
+
}
|
|
2272
|
+
if (template.workflows?.length) {
|
|
2273
|
+
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
|
|
2274
|
+
}
|
|
2275
|
+
if (template.mcp?.length) {
|
|
2276
|
+
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
|
|
2277
|
+
}
|
|
2278
|
+
if (template.networks?.length) {
|
|
2279
|
+
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
|
|
2280
|
+
}
|
|
2281
|
+
return {
|
|
2282
|
+
value: template,
|
|
2283
|
+
label: template.title,
|
|
2284
|
+
hint: parts.join(", ") || "Template components"
|
|
2285
|
+
};
|
|
2286
|
+
});
|
|
2287
|
+
const selected = await ve({
|
|
2288
|
+
message: "Select a template:",
|
|
2289
|
+
options: choices
|
|
2290
|
+
});
|
|
2291
|
+
if (pD(selected)) {
|
|
2292
|
+
return null;
|
|
2293
|
+
}
|
|
2294
|
+
return selected;
|
|
2295
|
+
}
|
|
2296
|
+
function findTemplateByName(templates, templateName) {
|
|
2297
|
+
let template = templates.find((t) => t.slug === templateName);
|
|
2298
|
+
if (template) return template;
|
|
2299
|
+
const slugWithPrefix = `template-${templateName}`;
|
|
2300
|
+
template = templates.find((t) => t.slug === slugWithPrefix);
|
|
2301
|
+
if (template) return template;
|
|
2302
|
+
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
|
|
2303
|
+
if (template) return template;
|
|
2304
|
+
return null;
|
|
2305
|
+
}
|
|
2306
|
+
function getDefaultProjectName(template) {
|
|
2307
|
+
return template.slug.replace(/^template-/, "");
|
|
2308
|
+
}
|
|
2197
2309
|
var s = Y();
|
|
2198
|
-
var exec3 = util.promisify(child_process.exec);
|
|
2199
2310
|
var init = async ({
|
|
2200
|
-
directory,
|
|
2201
|
-
addExample = false,
|
|
2311
|
+
directory = "src/",
|
|
2202
2312
|
components,
|
|
2203
2313
|
llmProvider = "openai",
|
|
2204
2314
|
llmApiKey,
|
|
2315
|
+
addExample = false,
|
|
2205
2316
|
configureEditorWithDocsMCP
|
|
2206
2317
|
}) => {
|
|
2207
2318
|
s.start("Initializing Mastra");
|
|
@@ -2217,7 +2328,8 @@ var init = async ({
|
|
|
2217
2328
|
dirPath,
|
|
2218
2329
|
addExample,
|
|
2219
2330
|
addWorkflow: components.includes("workflows"),
|
|
2220
|
-
addAgent: components.includes("agents")
|
|
2331
|
+
addAgent: components.includes("agents"),
|
|
2332
|
+
addScorers: components.includes("scorers")
|
|
2221
2333
|
}),
|
|
2222
2334
|
...components.map((component) => createComponentsDir(dirPath, component)),
|
|
2223
2335
|
writeAPIKey({ provider: llmProvider, apiKey: llmApiKey })
|
|
@@ -2241,14 +2353,12 @@ var init = async ({
|
|
|
2241
2353
|
if (needsLoggers) {
|
|
2242
2354
|
await depService.installPackages(["@mastra/loggers"]);
|
|
2243
2355
|
}
|
|
2356
|
+
const needsEvals = components.includes(`scorers`) && await depService.checkDependencies(["@mastra/evals"]) !== `ok`;
|
|
2357
|
+
if (needsEvals) {
|
|
2358
|
+
await depService.installPackages(["@mastra/evals"]);
|
|
2359
|
+
}
|
|
2244
2360
|
}
|
|
2245
2361
|
const key = await getAPIKey(llmProvider || "openai");
|
|
2246
|
-
const aiSdkPackage = getAISDKPackage(llmProvider);
|
|
2247
|
-
const aiSdkPackageVersion = getAISDKPackageVersion(llmProvider);
|
|
2248
|
-
const depsService = new DepsService();
|
|
2249
|
-
const pm = depsService.packageManager;
|
|
2250
|
-
const installCommand = getPackageManagerAddCommand(pm);
|
|
2251
|
-
await exec3(`${pm} ${installCommand} ${aiSdkPackage}@${aiSdkPackageVersion}`);
|
|
2252
2362
|
if (configureEditorWithDocsMCP) {
|
|
2253
2363
|
await installMastraDocsMCPServer({
|
|
2254
2364
|
editor: configureEditorWithDocsMCP,
|
|
@@ -2275,10 +2385,10 @@ var init = async ({
|
|
|
2275
2385
|
return { success: false };
|
|
2276
2386
|
}
|
|
2277
2387
|
};
|
|
2278
|
-
var
|
|
2388
|
+
var exec3 = util.promisify(child_process.exec);
|
|
2279
2389
|
var execWithTimeout = async (command, timeoutMs) => {
|
|
2280
2390
|
try {
|
|
2281
|
-
const promise =
|
|
2391
|
+
const promise = exec3(command, { killSignal: "SIGTERM" });
|
|
2282
2392
|
if (!timeoutMs) {
|
|
2283
2393
|
return await promise;
|
|
2284
2394
|
}
|
|
@@ -2301,6 +2411,32 @@ var execWithTimeout = async (command, timeoutMs) => {
|
|
|
2301
2411
|
throw error;
|
|
2302
2412
|
}
|
|
2303
2413
|
};
|
|
2414
|
+
async function getInitCommand(pm) {
|
|
2415
|
+
switch (pm) {
|
|
2416
|
+
case "npm":
|
|
2417
|
+
return "npm init -y";
|
|
2418
|
+
case "pnpm":
|
|
2419
|
+
return "pnpm init";
|
|
2420
|
+
case "yarn":
|
|
2421
|
+
return "yarn init -y";
|
|
2422
|
+
case "bun":
|
|
2423
|
+
return "bun init -y";
|
|
2424
|
+
default:
|
|
2425
|
+
return "npm init -y";
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
async function initializePackageJson(pm) {
|
|
2429
|
+
const initCommand = await getInitCommand(pm);
|
|
2430
|
+
await exec3(initCommand);
|
|
2431
|
+
const packageJsonPath = path.join(process.cwd(), "package.json");
|
|
2432
|
+
const packageJson = JSON.parse(await fs4.readFile(packageJsonPath, "utf-8"));
|
|
2433
|
+
packageJson.type = "module";
|
|
2434
|
+
packageJson.engines = {
|
|
2435
|
+
...packageJson.engines,
|
|
2436
|
+
node: ">=22.13.0"
|
|
2437
|
+
};
|
|
2438
|
+
await fs4.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
2439
|
+
}
|
|
2304
2440
|
async function installMastraDependency(pm, dependency, versionTag, isDev, timeout) {
|
|
2305
2441
|
let installCommand = getPackageManagerAddCommand(pm);
|
|
2306
2442
|
if (isDev) {
|
|
@@ -2326,23 +2462,42 @@ async function installMastraDependency(pm, dependency, versionTag, isDev, timeou
|
|
|
2326
2462
|
var createMastraProject = async ({
|
|
2327
2463
|
projectName: name,
|
|
2328
2464
|
createVersionTag,
|
|
2329
|
-
timeout
|
|
2465
|
+
timeout,
|
|
2466
|
+
llmProvider,
|
|
2467
|
+
llmApiKey,
|
|
2468
|
+
needsInteractive
|
|
2330
2469
|
}) => {
|
|
2331
2470
|
Ie(color2.inverse(" Mastra Create "));
|
|
2332
2471
|
const projectName = name ?? await he({
|
|
2333
2472
|
message: "What do you want to name your project?",
|
|
2334
2473
|
placeholder: "my-mastra-app",
|
|
2335
|
-
defaultValue: "my-mastra-app"
|
|
2474
|
+
defaultValue: "my-mastra-app",
|
|
2475
|
+
validate: (value) => {
|
|
2476
|
+
if (value.length === 0) return "Project name cannot be empty";
|
|
2477
|
+
if (fs3__default__default.existsSync(value)) {
|
|
2478
|
+
return `A directory named "${value}" already exists. Please choose a different name.`;
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2336
2481
|
});
|
|
2337
2482
|
if (pD(projectName)) {
|
|
2338
2483
|
xe("Operation cancelled");
|
|
2339
2484
|
process.exit(0);
|
|
2340
2485
|
}
|
|
2486
|
+
let result;
|
|
2487
|
+
if (needsInteractive) {
|
|
2488
|
+
result = await interactivePrompt({
|
|
2489
|
+
options: { showBanner: false },
|
|
2490
|
+
skip: { llmProvider: llmProvider !== void 0, llmApiKey: llmApiKey !== void 0 }
|
|
2491
|
+
});
|
|
2492
|
+
}
|
|
2341
2493
|
const s2 = Y();
|
|
2494
|
+
const originalCwd = process.cwd();
|
|
2495
|
+
let projectPath = null;
|
|
2342
2496
|
try {
|
|
2343
2497
|
s2.start("Creating project");
|
|
2344
2498
|
try {
|
|
2345
|
-
await
|
|
2499
|
+
await fs4.mkdir(projectName);
|
|
2500
|
+
projectPath = path.resolve(originalCwd, projectName);
|
|
2346
2501
|
} catch (error) {
|
|
2347
2502
|
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
2348
2503
|
s2.stop(`A directory named "${projectName}" already exists. Please choose a different name.`);
|
|
@@ -2357,9 +2512,7 @@ var createMastraProject = async ({
|
|
|
2357
2512
|
const installCommand = getPackageManagerAddCommand(pm);
|
|
2358
2513
|
s2.message("Initializing project structure");
|
|
2359
2514
|
try {
|
|
2360
|
-
await
|
|
2361
|
-
await exec4(`npm pkg set type="module"`);
|
|
2362
|
-
await exec4(`npm pkg set engines.node=">=20.9.0"`);
|
|
2515
|
+
await initializePackageJson(pm);
|
|
2363
2516
|
const depsService = new DepsService();
|
|
2364
2517
|
await depsService.addScriptsToPackageJson({
|
|
2365
2518
|
dev: "mastra dev",
|
|
@@ -2374,9 +2527,9 @@ var createMastraProject = async ({
|
|
|
2374
2527
|
s2.stop("Project structure created");
|
|
2375
2528
|
s2.start(`Installing ${pm} dependencies`);
|
|
2376
2529
|
try {
|
|
2377
|
-
await
|
|
2378
|
-
await
|
|
2379
|
-
await
|
|
2530
|
+
await exec3(`${pm} ${installCommand} zod@^4`);
|
|
2531
|
+
await exec3(`${pm} ${installCommand} typescript @types/node --save-dev`);
|
|
2532
|
+
await exec3(`echo '{
|
|
2380
2533
|
"compilerOptions": {
|
|
2381
2534
|
"target": "ES2022",
|
|
2382
2535
|
"module": "ES2022",
|
|
@@ -2398,15 +2551,15 @@ var createMastraProject = async ({
|
|
|
2398
2551
|
);
|
|
2399
2552
|
}
|
|
2400
2553
|
s2.stop(`${pm} dependencies installed`);
|
|
2401
|
-
s2.start("Installing
|
|
2554
|
+
s2.start("Installing Mastra CLI");
|
|
2402
2555
|
const versionTag = createVersionTag ? `@${createVersionTag}` : "@latest";
|
|
2403
2556
|
try {
|
|
2404
2557
|
await installMastraDependency(pm, "mastra", versionTag, true, timeout);
|
|
2405
2558
|
} catch (error) {
|
|
2406
2559
|
throw new Error(`Failed to install Mastra CLI: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2407
2560
|
}
|
|
2408
|
-
s2.stop("
|
|
2409
|
-
s2.start("Installing dependencies");
|
|
2561
|
+
s2.stop("Mastra CLI installed");
|
|
2562
|
+
s2.start("Installing Mastra dependencies");
|
|
2410
2563
|
try {
|
|
2411
2564
|
await installMastraDependency(pm, "@mastra/core", versionTag, false, timeout);
|
|
2412
2565
|
await installMastraDependency(pm, "@mastra/libsql", versionTag, false, timeout);
|
|
@@ -2419,25 +2572,35 @@ var createMastraProject = async ({
|
|
|
2419
2572
|
s2.stop("Mastra dependencies installed");
|
|
2420
2573
|
s2.start("Adding .gitignore");
|
|
2421
2574
|
try {
|
|
2422
|
-
await
|
|
2423
|
-
await
|
|
2424
|
-
await
|
|
2425
|
-
await
|
|
2426
|
-
await
|
|
2427
|
-
await
|
|
2428
|
-
await
|
|
2429
|
-
await
|
|
2575
|
+
await exec3(`echo output.txt >> .gitignore`);
|
|
2576
|
+
await exec3(`echo node_modules >> .gitignore`);
|
|
2577
|
+
await exec3(`echo dist >> .gitignore`);
|
|
2578
|
+
await exec3(`echo .mastra >> .gitignore`);
|
|
2579
|
+
await exec3(`echo .env.development >> .gitignore`);
|
|
2580
|
+
await exec3(`echo .env >> .gitignore`);
|
|
2581
|
+
await exec3(`echo *.db >> .gitignore`);
|
|
2582
|
+
await exec3(`echo *.db-* >> .gitignore`);
|
|
2430
2583
|
} catch (error) {
|
|
2431
2584
|
throw new Error(`Failed to create .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2432
2585
|
}
|
|
2433
2586
|
s2.stop(".gitignore added");
|
|
2434
2587
|
Se("Project created successfully");
|
|
2435
2588
|
console.info("");
|
|
2436
|
-
return { projectName };
|
|
2589
|
+
return { projectName, result };
|
|
2437
2590
|
} catch (error) {
|
|
2438
2591
|
s2.stop();
|
|
2439
2592
|
const errorMessage = error instanceof Error ? error.message : "An unexpected error occurred";
|
|
2440
2593
|
xe(`Project creation failed: ${errorMessage}`);
|
|
2594
|
+
if (projectPath && fs3__default__default.existsSync(projectPath)) {
|
|
2595
|
+
try {
|
|
2596
|
+
process.chdir(originalCwd);
|
|
2597
|
+
await fs4.rm(projectPath, { recursive: true, force: true });
|
|
2598
|
+
} catch (cleanupError) {
|
|
2599
|
+
console.error(
|
|
2600
|
+
`Warning: Failed to clean up project directory: ${cleanupError instanceof Error ? cleanupError.message : "Unknown error"}`
|
|
2601
|
+
);
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2441
2604
|
process.exit(1);
|
|
2442
2605
|
}
|
|
2443
2606
|
};
|
|
@@ -2446,18 +2609,21 @@ var create = async (args2) => {
|
|
|
2446
2609
|
await createFromTemplate({ ...args2, injectedAnalytics: args2.analytics });
|
|
2447
2610
|
return;
|
|
2448
2611
|
}
|
|
2449
|
-
const
|
|
2612
|
+
const needsInteractive = args2.components === void 0 || args2.llmProvider === void 0 || args2.addExample === void 0;
|
|
2613
|
+
const { projectName, result } = await createMastraProject({
|
|
2450
2614
|
projectName: args2?.projectName,
|
|
2451
2615
|
createVersionTag: args2?.createVersionTag,
|
|
2452
|
-
timeout: args2?.timeout
|
|
2616
|
+
timeout: args2?.timeout,
|
|
2617
|
+
llmProvider: args2?.llmProvider,
|
|
2618
|
+
llmApiKey: args2?.llmApiKey,
|
|
2619
|
+
needsInteractive
|
|
2453
2620
|
});
|
|
2454
2621
|
const directory = args2.directory || "src/";
|
|
2455
|
-
if (
|
|
2456
|
-
const result = await interactivePrompt();
|
|
2622
|
+
if (needsInteractive && result) {
|
|
2457
2623
|
await init({
|
|
2458
2624
|
...result,
|
|
2459
2625
|
llmApiKey: result?.llmApiKey,
|
|
2460
|
-
components: ["agents", "tools", "workflows"],
|
|
2626
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2461
2627
|
addExample: true
|
|
2462
2628
|
});
|
|
2463
2629
|
postCreate({ projectName });
|
|
@@ -2573,16 +2739,16 @@ async function createFromTemplate(args2) {
|
|
|
2573
2739
|
selectedTemplate = selected;
|
|
2574
2740
|
} else if (args2.template && typeof args2.template === "string") {
|
|
2575
2741
|
if (isGitHubUrl(args2.template)) {
|
|
2576
|
-
const
|
|
2577
|
-
|
|
2742
|
+
const spinner4 = Y();
|
|
2743
|
+
spinner4.start("Validating GitHub repository...");
|
|
2578
2744
|
const validation = await validateGitHubProject(args2.template);
|
|
2579
2745
|
if (!validation.isValid) {
|
|
2580
|
-
|
|
2746
|
+
spinner4.stop("Validation failed");
|
|
2581
2747
|
M.error("This does not appear to be a valid Mastra project:");
|
|
2582
2748
|
validation.errors.forEach((error) => M.error(` - ${error}`));
|
|
2583
2749
|
throw new Error("Invalid Mastra project");
|
|
2584
2750
|
}
|
|
2585
|
-
|
|
2751
|
+
spinner4.stop("Valid Mastra project \u2713");
|
|
2586
2752
|
selectedTemplate = await createFromGitHubUrl(args2.template);
|
|
2587
2753
|
} else {
|
|
2588
2754
|
const templates = await loadTemplates();
|
|
@@ -2612,6 +2778,7 @@ async function createFromTemplate(args2) {
|
|
|
2612
2778
|
}
|
|
2613
2779
|
projectName = response;
|
|
2614
2780
|
}
|
|
2781
|
+
let projectPath = null;
|
|
2615
2782
|
try {
|
|
2616
2783
|
const analytics = args2.injectedAnalytics || getAnalytics();
|
|
2617
2784
|
if (analytics) {
|
|
@@ -2620,7 +2787,7 @@ async function createFromTemplate(args2) {
|
|
|
2620
2787
|
template_title: selectedTemplate.title
|
|
2621
2788
|
});
|
|
2622
2789
|
}
|
|
2623
|
-
|
|
2790
|
+
projectPath = await cloneTemplate({
|
|
2624
2791
|
template: selectedTemplate,
|
|
2625
2792
|
projectName
|
|
2626
2793
|
});
|
|
@@ -2633,6 +2800,17 @@ async function createFromTemplate(args2) {
|
|
|
2633
2800
|
`);
|
|
2634
2801
|
postCreate({ projectName });
|
|
2635
2802
|
} catch (error) {
|
|
2803
|
+
if (projectPath) {
|
|
2804
|
+
try {
|
|
2805
|
+
if (fs3__default__default.existsSync(projectPath)) {
|
|
2806
|
+
await fs4.rm(projectPath, { recursive: true, force: true });
|
|
2807
|
+
}
|
|
2808
|
+
} catch (cleanupError) {
|
|
2809
|
+
console.error(
|
|
2810
|
+
`Warning: Failed to clean up project directory: ${cleanupError instanceof Error ? cleanupError.message : "Unknown error"}`
|
|
2811
|
+
);
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2636
2814
|
M.error(`Failed to create project from template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2637
2815
|
throw error;
|
|
2638
2816
|
}
|
|
@@ -2641,7 +2819,7 @@ async function createFromTemplate(args2) {
|
|
|
2641
2819
|
async function getPackageVersion() {
|
|
2642
2820
|
const __filename = fileURLToPath(import.meta.url);
|
|
2643
2821
|
const __dirname = dirname(__filename);
|
|
2644
|
-
const pkgJsonPath =
|
|
2822
|
+
const pkgJsonPath = path.join(__dirname, "..", "package.json");
|
|
2645
2823
|
const content = await fsExtra$1.readJSON(pkgJsonPath);
|
|
2646
2824
|
return content.version;
|
|
2647
2825
|
}
|
|
@@ -2679,7 +2857,7 @@ program.version(`${version}`, "-v, --version").description(`create-mastra ${vers
|
|
|
2679
2857
|
program.name("create-mastra").description("Create a new Mastra project").argument("[project-name]", "Directory name of the project").option(
|
|
2680
2858
|
"-p, --project-name <string>",
|
|
2681
2859
|
"Project name that will be used in package.json and as the project directory name."
|
|
2682
|
-
).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(
|
|
2860
|
+
).option("--default", "Quick start with defaults (src, OpenAI, examples)").option("-c, --components <components>", "Comma-separated list of components (agents, tools, workflows, scorers)").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(
|
|
2683
2861
|
"--template [template-name]",
|
|
2684
2862
|
"Create project from a template (use template name, public GitHub URL, or leave blank to select from list)"
|
|
2685
2863
|
).action(async (projectNameArg, args) => {
|
|
@@ -2687,7 +2865,7 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2687
2865
|
const timeout = args?.timeout ? args?.timeout === true ? 6e4 : parseInt(args?.timeout, 10) : void 0;
|
|
2688
2866
|
if (args.default) {
|
|
2689
2867
|
await create({
|
|
2690
|
-
components: ["agents", "tools", "workflows"],
|
|
2868
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2691
2869
|
llmProvider: "openai",
|
|
2692
2870
|
addExample: true,
|
|
2693
2871
|
createVersionTag,
|
|
@@ -2703,7 +2881,7 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2703
2881
|
components: args.components ? args.components.split(",") : [],
|
|
2704
2882
|
llmProvider: args.llm,
|
|
2705
2883
|
addExample: args.example,
|
|
2706
|
-
llmApiKey: args
|
|
2884
|
+
llmApiKey: args.llmApiKey,
|
|
2707
2885
|
createVersionTag,
|
|
2708
2886
|
timeout,
|
|
2709
2887
|
projectName,
|