create-mastra 0.0.0-monorepo-binary-20251013210052 → 0.0.0-netlify-no-bundle-20251127120354
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 +151 -1
- package/README.md +10 -32
- package/dist/index.js +685 -433
- package/dist/index.js.map +1 -1
- package/dist/starter-files/tools.ts +2 -2
- package/dist/templates/dev.entry.js +2 -45
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
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
7
|
import path3, { 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);
|
|
@@ -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)
|
|
@@ -887,6 +887,7 @@ class YoctoSpinner {
|
|
|
887
887
|
#exitHandlerBound;
|
|
888
888
|
#isInteractive;
|
|
889
889
|
#lastSpinnerFrameTime = 0;
|
|
890
|
+
#isSpinning = false;
|
|
890
891
|
|
|
891
892
|
constructor(options = {}) {
|
|
892
893
|
const spinner = options.spinner ?? defaultSpinner;
|
|
@@ -908,13 +909,17 @@ class YoctoSpinner {
|
|
|
908
909
|
return this;
|
|
909
910
|
}
|
|
910
911
|
|
|
912
|
+
this.#isSpinning = true;
|
|
911
913
|
this.#hideCursor();
|
|
912
914
|
this.#render();
|
|
913
915
|
this.#subscribeToProcessEvents();
|
|
914
916
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
917
|
+
// Only start the timer in interactive mode
|
|
918
|
+
if (this.#isInteractive) {
|
|
919
|
+
this.#timer = setInterval(() => {
|
|
920
|
+
this.#render();
|
|
921
|
+
}, this.#interval);
|
|
922
|
+
}
|
|
918
923
|
|
|
919
924
|
return this;
|
|
920
925
|
}
|
|
@@ -924,8 +929,12 @@ class YoctoSpinner {
|
|
|
924
929
|
return this;
|
|
925
930
|
}
|
|
926
931
|
|
|
927
|
-
|
|
928
|
-
this.#timer
|
|
932
|
+
this.#isSpinning = false;
|
|
933
|
+
if (this.#timer) {
|
|
934
|
+
clearInterval(this.#timer);
|
|
935
|
+
this.#timer = undefined;
|
|
936
|
+
}
|
|
937
|
+
|
|
929
938
|
this.#showCursor();
|
|
930
939
|
this.clear();
|
|
931
940
|
this.#unsubscribeFromProcessEvents();
|
|
@@ -958,7 +967,7 @@ class YoctoSpinner {
|
|
|
958
967
|
}
|
|
959
968
|
|
|
960
969
|
get isSpinning() {
|
|
961
|
-
return this.#
|
|
970
|
+
return this.#isSpinning;
|
|
962
971
|
}
|
|
963
972
|
|
|
964
973
|
get text() {
|
|
@@ -1095,11 +1104,11 @@ var MastraLogger = class {
|
|
|
1095
1104
|
}
|
|
1096
1105
|
trackException(_error) {
|
|
1097
1106
|
}
|
|
1098
|
-
async
|
|
1107
|
+
async listLogs(transportId, params) {
|
|
1099
1108
|
if (!transportId || !this.transports.has(transportId)) {
|
|
1100
1109
|
return { logs: [], total: 0, page: params?.page ?? 1, perPage: params?.perPage ?? 100, hasMore: false };
|
|
1101
1110
|
}
|
|
1102
|
-
return this.transports.get(transportId).
|
|
1111
|
+
return this.transports.get(transportId).listLogs(params) ?? {
|
|
1103
1112
|
logs: [],
|
|
1104
1113
|
total: 0,
|
|
1105
1114
|
page: params?.page ?? 1,
|
|
@@ -1107,7 +1116,7 @@ var MastraLogger = class {
|
|
|
1107
1116
|
hasMore: false
|
|
1108
1117
|
};
|
|
1109
1118
|
}
|
|
1110
|
-
async
|
|
1119
|
+
async listLogsByRunId({
|
|
1111
1120
|
transportId,
|
|
1112
1121
|
runId,
|
|
1113
1122
|
fromDate,
|
|
@@ -1120,7 +1129,7 @@ var MastraLogger = class {
|
|
|
1120
1129
|
if (!transportId || !this.transports.has(transportId) || !runId) {
|
|
1121
1130
|
return { logs: [], total: 0, page: page ?? 1, perPage: perPage ?? 100, hasMore: false };
|
|
1122
1131
|
}
|
|
1123
|
-
return this.transports.get(transportId).
|
|
1132
|
+
return this.transports.get(transportId).listLogsByRunId({ runId, fromDate, toDate, logLevel, filters, page, perPage }) ?? {
|
|
1124
1133
|
logs: [],
|
|
1125
1134
|
total: 0,
|
|
1126
1135
|
page: page ?? 1,
|
|
@@ -1178,183 +1187,8 @@ var PinoLogger = class extends MastraLogger {
|
|
|
1178
1187
|
}
|
|
1179
1188
|
};
|
|
1180
1189
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
const execPath = process.env.npm_execpath || "";
|
|
1184
|
-
if (userAgent.includes("yarn")) {
|
|
1185
|
-
return "yarn";
|
|
1186
|
-
}
|
|
1187
|
-
if (userAgent.includes("pnpm")) {
|
|
1188
|
-
return "pnpm";
|
|
1189
|
-
}
|
|
1190
|
-
if (userAgent.includes("npm")) {
|
|
1191
|
-
return "npm";
|
|
1192
|
-
}
|
|
1193
|
-
if (execPath.includes("yarn")) {
|
|
1194
|
-
return "yarn";
|
|
1195
|
-
}
|
|
1196
|
-
if (execPath.includes("pnpm")) {
|
|
1197
|
-
return "pnpm";
|
|
1198
|
-
}
|
|
1199
|
-
if (execPath.includes("npm")) {
|
|
1200
|
-
return "npm";
|
|
1201
|
-
}
|
|
1202
|
-
return "npm";
|
|
1203
|
-
}
|
|
1204
|
-
var logger = new PinoLogger({
|
|
1205
|
-
name: "Mastra CLI",
|
|
1206
|
-
level: "info"
|
|
1207
|
-
});
|
|
1208
|
-
var exec = util.promisify(child_process.exec);
|
|
1209
|
-
async function cloneTemplate(options) {
|
|
1210
|
-
const { template, projectName, targetDir } = options;
|
|
1211
|
-
const projectPath = targetDir ? path3.resolve(targetDir, projectName) : path3.resolve(projectName);
|
|
1212
|
-
const spinner5 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
|
|
1213
|
-
try {
|
|
1214
|
-
if (await directoryExists(projectPath)) {
|
|
1215
|
-
spinner5.error(`Directory ${projectName} already exists`);
|
|
1216
|
-
throw new Error(`Directory ${projectName} already exists`);
|
|
1217
|
-
}
|
|
1218
|
-
await cloneRepositoryWithoutGit(template.githubUrl, projectPath);
|
|
1219
|
-
await updatePackageJson(projectPath, projectName);
|
|
1220
|
-
const envExamplePath = path3.join(projectPath, ".env.example");
|
|
1221
|
-
if (await fileExists(envExamplePath)) {
|
|
1222
|
-
await fs5.copyFile(envExamplePath, path3.join(projectPath, ".env"));
|
|
1223
|
-
}
|
|
1224
|
-
spinner5.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
1225
|
-
return projectPath;
|
|
1226
|
-
} catch (error) {
|
|
1227
|
-
spinner5.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1228
|
-
throw error;
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
async function directoryExists(dirPath) {
|
|
1232
|
-
try {
|
|
1233
|
-
const stat = await fs5.stat(dirPath);
|
|
1234
|
-
return stat.isDirectory();
|
|
1235
|
-
} catch {
|
|
1236
|
-
return false;
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
async function fileExists(filePath) {
|
|
1240
|
-
try {
|
|
1241
|
-
const stat = await fs5.stat(filePath);
|
|
1242
|
-
return stat.isFile();
|
|
1243
|
-
} catch {
|
|
1244
|
-
return false;
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
async function cloneRepositoryWithoutGit(repoUrl, targetPath) {
|
|
1248
|
-
await fs5.mkdir(targetPath, { recursive: true });
|
|
1249
|
-
try {
|
|
1250
|
-
const degitRepo = repoUrl.replace("https://github.com/", "");
|
|
1251
|
-
const degitCommand = shellQuote.quote(["npx", "degit", degitRepo, targetPath]);
|
|
1252
|
-
await exec(degitCommand, {
|
|
1253
|
-
cwd: process.cwd()
|
|
1254
|
-
});
|
|
1255
|
-
} catch {
|
|
1256
|
-
try {
|
|
1257
|
-
const gitCommand = shellQuote.quote(["git", "clone", repoUrl, targetPath]);
|
|
1258
|
-
await exec(gitCommand, {
|
|
1259
|
-
cwd: process.cwd()
|
|
1260
|
-
});
|
|
1261
|
-
const gitDir = path3.join(targetPath, ".git");
|
|
1262
|
-
if (await directoryExists(gitDir)) {
|
|
1263
|
-
await fs5.rm(gitDir, { recursive: true, force: true });
|
|
1264
|
-
}
|
|
1265
|
-
} catch (gitError) {
|
|
1266
|
-
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
async function updatePackageJson(projectPath, projectName) {
|
|
1271
|
-
const packageJsonPath = path3.join(projectPath, "package.json");
|
|
1272
|
-
try {
|
|
1273
|
-
const packageJsonContent = await fs5.readFile(packageJsonPath, "utf-8");
|
|
1274
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
1275
|
-
packageJson.name = projectName;
|
|
1276
|
-
await fs5.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
1277
|
-
} catch (error) {
|
|
1278
|
-
logger.warn(`Could not update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
async function installDependencies(projectPath, packageManager) {
|
|
1282
|
-
const spinner5 = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
1283
|
-
try {
|
|
1284
|
-
const pm = packageManager || getPackageManager();
|
|
1285
|
-
const installCommand = shellQuote.quote([pm, "install"]);
|
|
1286
|
-
await exec(installCommand, {
|
|
1287
|
-
cwd: projectPath
|
|
1288
|
-
});
|
|
1289
|
-
spinner5.success("Dependencies installed successfully");
|
|
1290
|
-
} catch (error) {
|
|
1291
|
-
spinner5.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1292
|
-
throw error;
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
|
|
1296
|
-
async function loadTemplates() {
|
|
1297
|
-
try {
|
|
1298
|
-
const response = await fetch(TEMPLATES_API_URL);
|
|
1299
|
-
if (!response.ok) {
|
|
1300
|
-
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
1301
|
-
}
|
|
1302
|
-
const templates = await response.json();
|
|
1303
|
-
return templates;
|
|
1304
|
-
} catch (error) {
|
|
1305
|
-
console.error("Error loading templates:", error);
|
|
1306
|
-
throw new Error("Failed to load templates. Please check your internet connection and try again.");
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
function pluralize(count, singular, plural) {
|
|
1310
|
-
return count === 1 ? singular : plural || `${singular}s`;
|
|
1311
|
-
}
|
|
1312
|
-
async function selectTemplate(templates) {
|
|
1313
|
-
const choices = templates.map((template) => {
|
|
1314
|
-
const parts = [];
|
|
1315
|
-
if (template.agents?.length) {
|
|
1316
|
-
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
|
|
1317
|
-
}
|
|
1318
|
-
if (template.tools?.length) {
|
|
1319
|
-
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
|
|
1320
|
-
}
|
|
1321
|
-
if (template.workflows?.length) {
|
|
1322
|
-
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
|
|
1323
|
-
}
|
|
1324
|
-
if (template.mcp?.length) {
|
|
1325
|
-
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
|
|
1326
|
-
}
|
|
1327
|
-
if (template.networks?.length) {
|
|
1328
|
-
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
|
|
1329
|
-
}
|
|
1330
|
-
return {
|
|
1331
|
-
value: template,
|
|
1332
|
-
label: template.title,
|
|
1333
|
-
hint: parts.join(", ") || "Template components"
|
|
1334
|
-
};
|
|
1335
|
-
});
|
|
1336
|
-
const selected = await ve({
|
|
1337
|
-
message: "Select a template:",
|
|
1338
|
-
options: choices
|
|
1339
|
-
});
|
|
1340
|
-
if (pD(selected)) {
|
|
1341
|
-
return null;
|
|
1342
|
-
}
|
|
1343
|
-
return selected;
|
|
1344
|
-
}
|
|
1345
|
-
function findTemplateByName(templates, templateName) {
|
|
1346
|
-
let template = templates.find((t) => t.slug === templateName);
|
|
1347
|
-
if (template) return template;
|
|
1348
|
-
const slugWithPrefix = `template-${templateName}`;
|
|
1349
|
-
template = templates.find((t) => t.slug === slugWithPrefix);
|
|
1350
|
-
if (template) return template;
|
|
1351
|
-
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
|
|
1352
|
-
if (template) return template;
|
|
1353
|
-
return null;
|
|
1354
|
-
}
|
|
1355
|
-
function getDefaultProjectName(template) {
|
|
1356
|
-
return template.slug.replace(/^template-/, "");
|
|
1357
|
-
}
|
|
1190
|
+
var package_default = {
|
|
1191
|
+
version: "1.0.0-beta.4"};
|
|
1358
1192
|
function getPackageManagerAddCommand(pm) {
|
|
1359
1193
|
switch (pm) {
|
|
1360
1194
|
case "npm":
|
|
@@ -1377,7 +1211,7 @@ var DepsService = class {
|
|
|
1377
1211
|
findLockFile(dir) {
|
|
1378
1212
|
const lockFiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock"];
|
|
1379
1213
|
for (const file of lockFiles) {
|
|
1380
|
-
if (
|
|
1214
|
+
if (fs3__default__default.existsSync(path3.join(dir, file))) {
|
|
1381
1215
|
return file;
|
|
1382
1216
|
}
|
|
1383
1217
|
}
|
|
@@ -1416,11 +1250,11 @@ var DepsService = class {
|
|
|
1416
1250
|
try {
|
|
1417
1251
|
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1418
1252
|
try {
|
|
1419
|
-
await
|
|
1253
|
+
await fs4.access(packageJsonPath);
|
|
1420
1254
|
} catch {
|
|
1421
1255
|
return "No package.json file found in the current directory";
|
|
1422
1256
|
}
|
|
1423
|
-
const packageJson = JSON.parse(await
|
|
1257
|
+
const packageJson = JSON.parse(await fs4.readFile(packageJsonPath, "utf-8"));
|
|
1424
1258
|
for (const dependency of dependencies) {
|
|
1425
1259
|
if (!packageJson.dependencies || !packageJson.dependencies[dependency]) {
|
|
1426
1260
|
return `Please install ${dependency} before running this command (${this.packageManager} install ${dependency})`;
|
|
@@ -1435,7 +1269,7 @@ var DepsService = class {
|
|
|
1435
1269
|
async getProjectName() {
|
|
1436
1270
|
try {
|
|
1437
1271
|
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1438
|
-
const packageJson = await
|
|
1272
|
+
const packageJson = await fs4.readFile(packageJsonPath, "utf-8");
|
|
1439
1273
|
const pkg = JSON.parse(packageJson);
|
|
1440
1274
|
return pkg.name;
|
|
1441
1275
|
} catch (err) {
|
|
@@ -1443,126 +1277,14 @@ var DepsService = class {
|
|
|
1443
1277
|
}
|
|
1444
1278
|
}
|
|
1445
1279
|
async addScriptsToPackageJson(scripts) {
|
|
1446
|
-
const packageJson = JSON.parse(await
|
|
1280
|
+
const packageJson = JSON.parse(await fs4.readFile("package.json", "utf-8"));
|
|
1447
1281
|
packageJson.scripts = {
|
|
1448
1282
|
...packageJson.scripts,
|
|
1449
1283
|
...scripts
|
|
1450
1284
|
};
|
|
1451
|
-
await
|
|
1452
|
-
}
|
|
1453
|
-
};
|
|
1454
|
-
var args = ["-y", "@mastra/mcp-docs-server"];
|
|
1455
|
-
var createMcpConfig = (editor) => {
|
|
1456
|
-
if (editor === "vscode") {
|
|
1457
|
-
return {
|
|
1458
|
-
servers: {
|
|
1459
|
-
mastra: process.platform === `win32` ? {
|
|
1460
|
-
command: "cmd",
|
|
1461
|
-
args: ["/c", "npx", ...args],
|
|
1462
|
-
type: "stdio"
|
|
1463
|
-
} : {
|
|
1464
|
-
command: "npx",
|
|
1465
|
-
args,
|
|
1466
|
-
type: "stdio"
|
|
1467
|
-
}
|
|
1468
|
-
}
|
|
1469
|
-
};
|
|
1285
|
+
await fs4.writeFile("package.json", JSON.stringify(packageJson, null, 2));
|
|
1470
1286
|
}
|
|
1471
|
-
return {
|
|
1472
|
-
mcpServers: {
|
|
1473
|
-
mastra: {
|
|
1474
|
-
command: "npx",
|
|
1475
|
-
args
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
};
|
|
1479
1287
|
};
|
|
1480
|
-
function makeConfig(original, editor) {
|
|
1481
|
-
if (editor === "vscode") {
|
|
1482
|
-
return {
|
|
1483
|
-
...original,
|
|
1484
|
-
servers: {
|
|
1485
|
-
...original?.servers || {},
|
|
1486
|
-
...createMcpConfig(editor).servers
|
|
1487
|
-
}
|
|
1488
|
-
};
|
|
1489
|
-
}
|
|
1490
|
-
return {
|
|
1491
|
-
...original,
|
|
1492
|
-
mcpServers: {
|
|
1493
|
-
...original?.mcpServers || {},
|
|
1494
|
-
...createMcpConfig(editor).mcpServers
|
|
1495
|
-
}
|
|
1496
|
-
};
|
|
1497
|
-
}
|
|
1498
|
-
async function writeMergedConfig(configPath, editor) {
|
|
1499
|
-
const configExists = existsSync(configPath);
|
|
1500
|
-
const config = makeConfig(configExists ? await readJSON(configPath) : {}, editor);
|
|
1501
|
-
await ensureFile(configPath);
|
|
1502
|
-
await writeJSON(configPath, config, {
|
|
1503
|
-
spaces: 2
|
|
1504
|
-
});
|
|
1505
|
-
}
|
|
1506
|
-
var windsurfGlobalMCPConfigPath = path3.join(os.homedir(), ".codeium", "windsurf", "mcp_config.json");
|
|
1507
|
-
var cursorGlobalMCPConfigPath = path3.join(os.homedir(), ".cursor", "mcp.json");
|
|
1508
|
-
path3.join(process.cwd(), ".vscode", "mcp.json");
|
|
1509
|
-
var vscodeGlobalMCPConfigPath = path3.join(
|
|
1510
|
-
os.homedir(),
|
|
1511
|
-
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")
|
|
1512
|
-
);
|
|
1513
|
-
async function installMastraDocsMCPServer({ editor, directory }) {
|
|
1514
|
-
if (editor === `cursor`) {
|
|
1515
|
-
await writeMergedConfig(path3.join(directory, ".cursor", "mcp.json"), "cursor");
|
|
1516
|
-
}
|
|
1517
|
-
if (editor === `vscode`) {
|
|
1518
|
-
await writeMergedConfig(path3.join(directory, ".vscode", "mcp.json"), "vscode");
|
|
1519
|
-
}
|
|
1520
|
-
if (editor === `cursor-global`) {
|
|
1521
|
-
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor);
|
|
1522
|
-
if (alreadyInstalled) {
|
|
1523
|
-
return;
|
|
1524
|
-
}
|
|
1525
|
-
await writeMergedConfig(cursorGlobalMCPConfigPath, "cursor-global");
|
|
1526
|
-
}
|
|
1527
|
-
if (editor === `windsurf`) {
|
|
1528
|
-
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor);
|
|
1529
|
-
if (alreadyInstalled) {
|
|
1530
|
-
return;
|
|
1531
|
-
}
|
|
1532
|
-
await writeMergedConfig(windsurfGlobalMCPConfigPath, editor);
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
async function globalMCPIsAlreadyInstalled(editor) {
|
|
1536
|
-
let configPath = ``;
|
|
1537
|
-
if (editor === "windsurf") {
|
|
1538
|
-
configPath = windsurfGlobalMCPConfigPath;
|
|
1539
|
-
} else if (editor === "cursor-global") {
|
|
1540
|
-
configPath = cursorGlobalMCPConfigPath;
|
|
1541
|
-
} else if (editor === "vscode") {
|
|
1542
|
-
configPath = vscodeGlobalMCPConfigPath;
|
|
1543
|
-
}
|
|
1544
|
-
if (!configPath || !existsSync(configPath)) {
|
|
1545
|
-
return false;
|
|
1546
|
-
}
|
|
1547
|
-
try {
|
|
1548
|
-
const configContents = await readJSON(configPath);
|
|
1549
|
-
if (!configContents) return false;
|
|
1550
|
-
if (editor === "vscode") {
|
|
1551
|
-
if (!configContents.servers) return false;
|
|
1552
|
-
const hasMastraMCP2 = Object.values(configContents.servers).some(
|
|
1553
|
-
(server) => server?.args?.find((arg) => arg?.includes(`@mastra/mcp-docs-server`))
|
|
1554
|
-
);
|
|
1555
|
-
return hasMastraMCP2;
|
|
1556
|
-
}
|
|
1557
|
-
if (!configContents?.mcpServers) return false;
|
|
1558
|
-
const hasMastraMCP = Object.values(configContents.mcpServers).some(
|
|
1559
|
-
(server) => server?.args?.find((arg) => arg?.includes(`@mastra/mcp-docs-server`))
|
|
1560
|
-
);
|
|
1561
|
-
return hasMastraMCP;
|
|
1562
|
-
} catch {
|
|
1563
|
-
return false;
|
|
1564
|
-
}
|
|
1565
|
-
}
|
|
1566
1288
|
var EnvService = class {
|
|
1567
1289
|
};
|
|
1568
1290
|
var FileEnvService = class extends EnvService {
|
|
@@ -1573,7 +1295,7 @@ var FileEnvService = class extends EnvService {
|
|
|
1573
1295
|
}
|
|
1574
1296
|
readFile(filePath) {
|
|
1575
1297
|
return new Promise((resolve, reject) => {
|
|
1576
|
-
|
|
1298
|
+
fs3__default.readFile(filePath, "utf8", (err, data) => {
|
|
1577
1299
|
if (err) reject(err);
|
|
1578
1300
|
else resolve(data);
|
|
1579
1301
|
});
|
|
@@ -1581,7 +1303,7 @@ var FileEnvService = class extends EnvService {
|
|
|
1581
1303
|
}
|
|
1582
1304
|
writeFile({ filePath, data }) {
|
|
1583
1305
|
return new Promise((resolve, reject) => {
|
|
1584
|
-
|
|
1306
|
+
fs3__default.writeFile(filePath, data, "utf8", (err) => {
|
|
1585
1307
|
if (err) reject(err);
|
|
1586
1308
|
else resolve();
|
|
1587
1309
|
});
|
|
@@ -1636,8 +1358,8 @@ var FileService = class {
|
|
|
1636
1358
|
const __filename = fileURLToPath(import.meta.url);
|
|
1637
1359
|
const __dirname = path3.dirname(__filename);
|
|
1638
1360
|
const filePath = path3.resolve(__dirname, "starter-files", inputFile);
|
|
1639
|
-
const fileString =
|
|
1640
|
-
if (
|
|
1361
|
+
const fileString = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1362
|
+
if (fs3__default__default.existsSync(outputFilePath) && !replaceIfExists) {
|
|
1641
1363
|
console.info(`${outputFilePath} already exists`);
|
|
1642
1364
|
return false;
|
|
1643
1365
|
}
|
|
@@ -1652,7 +1374,7 @@ var FileService = class {
|
|
|
1652
1374
|
}
|
|
1653
1375
|
getFirstExistingFile(files) {
|
|
1654
1376
|
for (const f of files) {
|
|
1655
|
-
if (
|
|
1377
|
+
if (fs3__default__default.existsSync(f)) {
|
|
1656
1378
|
return f;
|
|
1657
1379
|
}
|
|
1658
1380
|
}
|
|
@@ -1662,30 +1384,151 @@ var FileService = class {
|
|
|
1662
1384
|
filePath,
|
|
1663
1385
|
replacements
|
|
1664
1386
|
}) {
|
|
1665
|
-
let fileContent =
|
|
1387
|
+
let fileContent = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1666
1388
|
replacements.forEach(({ search, replace }) => {
|
|
1667
1389
|
fileContent = fileContent.replaceAll(search, replace);
|
|
1668
1390
|
});
|
|
1669
|
-
|
|
1391
|
+
fs3__default__default.writeFileSync(filePath, fileContent);
|
|
1670
1392
|
}
|
|
1671
1393
|
};
|
|
1672
|
-
var
|
|
1394
|
+
var createArgs = (versionTag) => {
|
|
1395
|
+
const packageName = versionTag ? `@mastra/mcp-docs-server@${versionTag}` : "@mastra/mcp-docs-server";
|
|
1396
|
+
return ["-y", packageName];
|
|
1397
|
+
};
|
|
1398
|
+
var createMcpConfig = (editor, versionTag) => {
|
|
1399
|
+
const args = createArgs(versionTag);
|
|
1400
|
+
if (editor === "vscode") {
|
|
1401
|
+
return {
|
|
1402
|
+
servers: {
|
|
1403
|
+
mastra: process.platform === `win32` ? {
|
|
1404
|
+
command: "cmd",
|
|
1405
|
+
args: ["/c", "npx", ...args],
|
|
1406
|
+
type: "stdio"
|
|
1407
|
+
} : {
|
|
1408
|
+
command: "npx",
|
|
1409
|
+
args,
|
|
1410
|
+
type: "stdio"
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1415
|
+
return {
|
|
1416
|
+
mcpServers: {
|
|
1417
|
+
mastra: {
|
|
1418
|
+
command: "npx",
|
|
1419
|
+
args
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1423
|
+
};
|
|
1424
|
+
function makeConfig(original, editor, versionTag) {
|
|
1425
|
+
if (editor === "vscode") {
|
|
1426
|
+
return {
|
|
1427
|
+
...original,
|
|
1428
|
+
servers: {
|
|
1429
|
+
...original?.servers || {},
|
|
1430
|
+
...createMcpConfig(editor, versionTag).servers
|
|
1431
|
+
}
|
|
1432
|
+
};
|
|
1433
|
+
}
|
|
1434
|
+
return {
|
|
1435
|
+
...original,
|
|
1436
|
+
mcpServers: {
|
|
1437
|
+
...original?.mcpServers || {},
|
|
1438
|
+
...createMcpConfig(editor, versionTag).mcpServers
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
}
|
|
1442
|
+
async function writeMergedConfig(configPath, editor, versionTag) {
|
|
1443
|
+
const configExists = existsSync(configPath);
|
|
1444
|
+
const config = makeConfig(configExists ? await readJSON(configPath) : {}, editor, versionTag);
|
|
1445
|
+
await ensureFile(configPath);
|
|
1446
|
+
await writeJSON(configPath, config, {
|
|
1447
|
+
spaces: 2
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
var windsurfGlobalMCPConfigPath = path3.join(os.homedir(), ".codeium", "windsurf", "mcp_config.json");
|
|
1451
|
+
var cursorGlobalMCPConfigPath = path3.join(os.homedir(), ".cursor", "mcp.json");
|
|
1452
|
+
path3.join(process.cwd(), ".vscode", "mcp.json");
|
|
1453
|
+
var vscodeGlobalMCPConfigPath = path3.join(
|
|
1454
|
+
os.homedir(),
|
|
1455
|
+
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")
|
|
1456
|
+
);
|
|
1457
|
+
async function installMastraDocsMCPServer({
|
|
1458
|
+
editor,
|
|
1459
|
+
directory,
|
|
1460
|
+
versionTag
|
|
1461
|
+
}) {
|
|
1462
|
+
if (editor === `cursor`) {
|
|
1463
|
+
await writeMergedConfig(path3.join(directory, ".cursor", "mcp.json"), "cursor", versionTag);
|
|
1464
|
+
}
|
|
1465
|
+
if (editor === `vscode`) {
|
|
1466
|
+
await writeMergedConfig(path3.join(directory, ".vscode", "mcp.json"), "vscode", versionTag);
|
|
1467
|
+
}
|
|
1468
|
+
if (editor === `cursor-global`) {
|
|
1469
|
+
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor, versionTag);
|
|
1470
|
+
if (alreadyInstalled) {
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
await writeMergedConfig(cursorGlobalMCPConfigPath, "cursor-global", versionTag);
|
|
1474
|
+
}
|
|
1475
|
+
if (editor === `windsurf`) {
|
|
1476
|
+
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor, versionTag);
|
|
1477
|
+
if (alreadyInstalled) {
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
await writeMergedConfig(windsurfGlobalMCPConfigPath, editor, versionTag);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
async function globalMCPIsAlreadyInstalled(editor, versionTag) {
|
|
1484
|
+
let configPath = ``;
|
|
1485
|
+
if (editor === "windsurf") {
|
|
1486
|
+
configPath = windsurfGlobalMCPConfigPath;
|
|
1487
|
+
} else if (editor === "cursor-global") {
|
|
1488
|
+
configPath = cursorGlobalMCPConfigPath;
|
|
1489
|
+
} else if (editor === "vscode") {
|
|
1490
|
+
configPath = vscodeGlobalMCPConfigPath;
|
|
1491
|
+
}
|
|
1492
|
+
if (!configPath || !existsSync(configPath)) {
|
|
1493
|
+
return false;
|
|
1494
|
+
}
|
|
1495
|
+
try {
|
|
1496
|
+
const configContents = await readJSON(configPath);
|
|
1497
|
+
if (!configContents) return false;
|
|
1498
|
+
const expectedPackage = versionTag ? `@mastra/mcp-docs-server@${versionTag}` : "@mastra/mcp-docs-server";
|
|
1499
|
+
if (editor === "vscode") {
|
|
1500
|
+
if (!configContents.servers) return false;
|
|
1501
|
+
const hasMastraMCP2 = Object.values(configContents.servers).some(
|
|
1502
|
+
(server) => server?.args?.find((arg) => arg === expectedPackage)
|
|
1503
|
+
);
|
|
1504
|
+
return hasMastraMCP2;
|
|
1505
|
+
}
|
|
1506
|
+
if (!configContents?.mcpServers) return false;
|
|
1507
|
+
const hasMastraMCP = Object.values(configContents.mcpServers).some(
|
|
1508
|
+
(server) => server?.args?.find((arg) => arg === expectedPackage)
|
|
1509
|
+
);
|
|
1510
|
+
return hasMastraMCP;
|
|
1511
|
+
} catch {
|
|
1512
|
+
return false;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
var exec = util.promisify(child_process.exec);
|
|
1673
1516
|
var getModelIdentifier = (llmProvider) => {
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
return `'anthropic/claude-3-5-sonnet-20241022'`;
|
|
1517
|
+
let model = "openai/gpt-4o";
|
|
1518
|
+
if (llmProvider === "anthropic") {
|
|
1519
|
+
model = "anthropic/claude-sonnet-4-5";
|
|
1678
1520
|
} else if (llmProvider === "groq") {
|
|
1679
|
-
|
|
1521
|
+
model = "groq/llama-3.3-70b-versatile";
|
|
1680
1522
|
} else if (llmProvider === "google") {
|
|
1681
|
-
|
|
1523
|
+
model = "google/gemini-2.5-pro";
|
|
1682
1524
|
} else if (llmProvider === "cerebras") {
|
|
1683
|
-
|
|
1525
|
+
model = "cerebras/llama-3.3-70b";
|
|
1684
1526
|
} else if (llmProvider === "mistral") {
|
|
1685
|
-
|
|
1527
|
+
model = "mistral/mistral-medium-2508";
|
|
1686
1528
|
}
|
|
1529
|
+
return model;
|
|
1687
1530
|
};
|
|
1688
|
-
async function writeAgentSample(llmProvider, destPath, addExampleTool) {
|
|
1531
|
+
async function writeAgentSample(llmProvider, destPath, addExampleTool, addScorers) {
|
|
1689
1532
|
const modelString = getModelIdentifier(llmProvider);
|
|
1690
1533
|
const instructions = `
|
|
1691
1534
|
You are a helpful weather assistant that provides accurate weather information and can help planning activities based on the weather.
|
|
@@ -1706,14 +1549,40 @@ import { Agent } from '@mastra/core/agent';
|
|
|
1706
1549
|
import { Memory } from '@mastra/memory';
|
|
1707
1550
|
import { LibSQLStore } from '@mastra/libsql';
|
|
1708
1551
|
${addExampleTool ? `import { weatherTool } from '../tools/weather-tool';` : ""}
|
|
1552
|
+
${addScorers ? `import { scorers } from '../scorers/weather-scorer';` : ""}
|
|
1709
1553
|
|
|
1710
1554
|
export const weatherAgent = new Agent({
|
|
1555
|
+
id: 'weather-agent',
|
|
1711
1556
|
name: 'Weather Agent',
|
|
1712
1557
|
instructions: \`${instructions}\`,
|
|
1713
|
-
model: ${modelString},
|
|
1558
|
+
model: '${modelString}',
|
|
1714
1559
|
${addExampleTool ? "tools: { weatherTool }," : ""}
|
|
1560
|
+
${addScorers ? `scorers: {
|
|
1561
|
+
toolCallAppropriateness: {
|
|
1562
|
+
scorer: scorers.toolCallAppropriatenessScorer,
|
|
1563
|
+
sampling: {
|
|
1564
|
+
type: 'ratio',
|
|
1565
|
+
rate: 1,
|
|
1566
|
+
},
|
|
1567
|
+
},
|
|
1568
|
+
completeness: {
|
|
1569
|
+
scorer: scorers.completenessScorer,
|
|
1570
|
+
sampling: {
|
|
1571
|
+
type: 'ratio',
|
|
1572
|
+
rate: 1,
|
|
1573
|
+
},
|
|
1574
|
+
},
|
|
1575
|
+
translation: {
|
|
1576
|
+
scorer: scorers.translationScorer,
|
|
1577
|
+
sampling: {
|
|
1578
|
+
type: 'ratio',
|
|
1579
|
+
rate: 1,
|
|
1580
|
+
},
|
|
1581
|
+
},
|
|
1582
|
+
},` : ""}
|
|
1715
1583
|
memory: new Memory({
|
|
1716
1584
|
storage: new LibSQLStore({
|
|
1585
|
+
id: "memory-storage",
|
|
1717
1586
|
url: "file:../mastra.db", // path is relative to the .mastra/output directory
|
|
1718
1587
|
})
|
|
1719
1588
|
})
|
|
@@ -1723,8 +1592,8 @@ export const weatherAgent = new Agent({
|
|
|
1723
1592
|
parser: "typescript",
|
|
1724
1593
|
singleQuote: true
|
|
1725
1594
|
});
|
|
1726
|
-
await
|
|
1727
|
-
await
|
|
1595
|
+
await fs4.writeFile(destPath, "");
|
|
1596
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1728
1597
|
}
|
|
1729
1598
|
async function writeWorkflowSample(destPath) {
|
|
1730
1599
|
const content = `import { createStep, createWorkflow } from '@mastra/core/workflows';
|
|
@@ -1917,20 +1786,115 @@ export { weatherWorkflow };`;
|
|
|
1917
1786
|
semi: true,
|
|
1918
1787
|
singleQuote: true
|
|
1919
1788
|
});
|
|
1920
|
-
await
|
|
1789
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1921
1790
|
}
|
|
1922
1791
|
async function writeToolSample(destPath) {
|
|
1923
1792
|
const fileService = new FileService();
|
|
1924
1793
|
await fileService.copyStarterFile("tools.ts", destPath);
|
|
1925
1794
|
}
|
|
1795
|
+
async function writeScorersSample(llmProvider, destPath) {
|
|
1796
|
+
const modelString = getModelIdentifier(llmProvider);
|
|
1797
|
+
const content = `import { z } from 'zod';
|
|
1798
|
+
import { createToolCallAccuracyScorerCode } from '@mastra/evals/scorers/prebuilt';
|
|
1799
|
+
import { createCompletenessScorer } from '@mastra/evals/scorers/prebuilt';
|
|
1800
|
+
import { getAssistantMessageFromRunOutput, getUserMessageFromRunInput } from '@mastra/evals/scorers/utils';
|
|
1801
|
+
import { createScorer } from '@mastra/core/evals';
|
|
1802
|
+
|
|
1803
|
+
export const toolCallAppropriatenessScorer = createToolCallAccuracyScorerCode({
|
|
1804
|
+
expectedTool: 'weatherTool',
|
|
1805
|
+
strictMode: false,
|
|
1806
|
+
});
|
|
1807
|
+
|
|
1808
|
+
export const completenessScorer = createCompletenessScorer();
|
|
1809
|
+
|
|
1810
|
+
// Custom LLM-judged scorer: evaluates if non-English locations are translated appropriately
|
|
1811
|
+
export const translationScorer = createScorer({
|
|
1812
|
+
id: 'translation-quality-scorer',
|
|
1813
|
+
name: 'Translation Quality',
|
|
1814
|
+
description: 'Checks that non-English location names are translated and used correctly',
|
|
1815
|
+
type: 'agent',
|
|
1816
|
+
judge: {
|
|
1817
|
+
model: '${modelString}',
|
|
1818
|
+
instructions:
|
|
1819
|
+
'You are an expert evaluator of translation quality for geographic locations. ' +
|
|
1820
|
+
'Determine whether the user text mentions a non-English location and whether the assistant correctly uses an English translation of that location. ' +
|
|
1821
|
+
'Be lenient with transliteration differences and diacritics. ' +
|
|
1822
|
+
'Return only the structured JSON matching the provided schema.',
|
|
1823
|
+
},
|
|
1824
|
+
})
|
|
1825
|
+
.preprocess(({ run }) => {
|
|
1826
|
+
const userText = getUserMessageFromRunInput(run.input) || '';
|
|
1827
|
+
const assistantText = getAssistantMessageFromRunOutput(run.output) || '';
|
|
1828
|
+
return { userText, assistantText };
|
|
1829
|
+
})
|
|
1830
|
+
.analyze({
|
|
1831
|
+
description: 'Extract location names and detect language/translation adequacy',
|
|
1832
|
+
outputSchema: z.object({
|
|
1833
|
+
nonEnglish: z.boolean(),
|
|
1834
|
+
translated: z.boolean(),
|
|
1835
|
+
confidence: z.number().min(0).max(1).default(1),
|
|
1836
|
+
explanation: z.string().default(''),
|
|
1837
|
+
}),
|
|
1838
|
+
createPrompt: ({ results }) => \`
|
|
1839
|
+
You are evaluating if a weather assistant correctly handled translation of a non-English location.
|
|
1840
|
+
User text:
|
|
1841
|
+
"""
|
|
1842
|
+
\${results.preprocessStepResult.userText}
|
|
1843
|
+
"""
|
|
1844
|
+
Assistant response:
|
|
1845
|
+
"""
|
|
1846
|
+
\${results.preprocessStepResult.assistantText}
|
|
1847
|
+
"""
|
|
1848
|
+
Tasks:
|
|
1849
|
+
1) Identify if the user mentioned a location that appears non-English.
|
|
1850
|
+
2) If non-English, check whether the assistant used a correct English translation of that location in its response.
|
|
1851
|
+
3) Be lenient with transliteration differences (e.g., accents/diacritics).
|
|
1852
|
+
Return JSON with fields:
|
|
1853
|
+
{
|
|
1854
|
+
"nonEnglish": boolean,
|
|
1855
|
+
"translated": boolean,
|
|
1856
|
+
"confidence": number, // 0-1
|
|
1857
|
+
"explanation": string
|
|
1858
|
+
}
|
|
1859
|
+
\`,
|
|
1860
|
+
})
|
|
1861
|
+
.generateScore(({ results }) => {
|
|
1862
|
+
const r = (results as any)?.analyzeStepResult || {};
|
|
1863
|
+
if (!r.nonEnglish) return 1; // If not applicable, full credit
|
|
1864
|
+
if (r.translated) return Math.max(0, Math.min(1, 0.7 + 0.3 * (r.confidence ?? 1)));
|
|
1865
|
+
return 0; // Non-English but not translated
|
|
1866
|
+
})
|
|
1867
|
+
.generateReason(({ results, score }) => {
|
|
1868
|
+
const r = (results as any)?.analyzeStepResult || {};
|
|
1869
|
+
return \`Translation scoring: nonEnglish=\${r.nonEnglish ?? false}, translated=\${r.translated ?? false}, confidence=\${r.confidence ?? 0}. Score=\${score}. \${r.explanation ?? ''}\`;
|
|
1870
|
+
});
|
|
1871
|
+
|
|
1872
|
+
export const scorers = {
|
|
1873
|
+
toolCallAppropriatenessScorer,
|
|
1874
|
+
completenessScorer,
|
|
1875
|
+
translationScorer,
|
|
1876
|
+
};`;
|
|
1877
|
+
const formattedContent = await prettier.format(content, {
|
|
1878
|
+
parser: "typescript",
|
|
1879
|
+
singleQuote: true
|
|
1880
|
+
});
|
|
1881
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1882
|
+
}
|
|
1926
1883
|
async function writeCodeSampleForComponents(llmprovider, component, destPath, importComponents) {
|
|
1927
1884
|
switch (component) {
|
|
1928
1885
|
case "agents":
|
|
1929
|
-
return writeAgentSample(
|
|
1886
|
+
return writeAgentSample(
|
|
1887
|
+
llmprovider,
|
|
1888
|
+
destPath,
|
|
1889
|
+
importComponents.includes("tools"),
|
|
1890
|
+
importComponents.includes("scorers")
|
|
1891
|
+
);
|
|
1930
1892
|
case "tools":
|
|
1931
1893
|
return writeToolSample(destPath);
|
|
1932
1894
|
case "workflows":
|
|
1933
1895
|
return writeWorkflowSample(destPath);
|
|
1896
|
+
case "scorers":
|
|
1897
|
+
return writeScorersSample(llmprovider, destPath);
|
|
1934
1898
|
default:
|
|
1935
1899
|
return "";
|
|
1936
1900
|
}
|
|
@@ -1943,39 +1907,44 @@ var writeIndexFile = async ({
|
|
|
1943
1907
|
dirPath,
|
|
1944
1908
|
addAgent,
|
|
1945
1909
|
addExample,
|
|
1946
|
-
addWorkflow
|
|
1910
|
+
addWorkflow,
|
|
1911
|
+
addScorers
|
|
1947
1912
|
}) => {
|
|
1948
1913
|
const indexPath = dirPath + "/index.ts";
|
|
1949
1914
|
const destPath = path3.join(indexPath);
|
|
1950
1915
|
try {
|
|
1951
|
-
await
|
|
1916
|
+
await fs4.writeFile(destPath, "");
|
|
1952
1917
|
const filteredExports = [
|
|
1953
1918
|
addWorkflow ? `workflows: { weatherWorkflow },` : "",
|
|
1954
|
-
addAgent ? `agents: { weatherAgent },` : ""
|
|
1919
|
+
addAgent ? `agents: { weatherAgent },` : "",
|
|
1920
|
+
addScorers ? `scorers: { toolCallAppropriatenessScorer, completenessScorer, translationScorer },` : ""
|
|
1955
1921
|
].filter(Boolean);
|
|
1956
1922
|
if (!addExample) {
|
|
1957
|
-
await
|
|
1923
|
+
await fs4.writeFile(
|
|
1958
1924
|
destPath,
|
|
1959
1925
|
`
|
|
1960
|
-
import { Mastra } from '@mastra/core';
|
|
1926
|
+
import { Mastra } from '@mastra/core/mastra';
|
|
1961
1927
|
|
|
1962
1928
|
export const mastra = new Mastra()
|
|
1963
1929
|
`
|
|
1964
1930
|
);
|
|
1965
1931
|
return;
|
|
1966
1932
|
}
|
|
1967
|
-
await
|
|
1933
|
+
await fs4.writeFile(
|
|
1968
1934
|
destPath,
|
|
1969
1935
|
`
|
|
1970
1936
|
import { Mastra } from '@mastra/core/mastra';
|
|
1971
1937
|
import { PinoLogger } from '@mastra/loggers';
|
|
1972
1938
|
import { LibSQLStore } from '@mastra/libsql';
|
|
1939
|
+
import { Observability } from '@mastra/observability';
|
|
1973
1940
|
${addWorkflow ? `import { weatherWorkflow } from './workflows/weather-workflow';` : ""}
|
|
1974
1941
|
${addAgent ? `import { weatherAgent } from './agents/weather-agent';` : ""}
|
|
1942
|
+
${addScorers ? `import { toolCallAppropriatenessScorer, completenessScorer, translationScorer } from './scorers/weather-scorer';` : ""}
|
|
1975
1943
|
|
|
1976
1944
|
export const mastra = new Mastra({
|
|
1977
1945
|
${filteredExports.join("\n ")}
|
|
1978
1946
|
storage: new LibSQLStore({
|
|
1947
|
+
id: "mastra-storage",
|
|
1979
1948
|
// stores observability, scores, ... into memory storage, if it needs to persist, change to file:../mastra.db
|
|
1980
1949
|
url: ":memory:",
|
|
1981
1950
|
}),
|
|
@@ -1983,14 +1952,10 @@ export const mastra = new Mastra({
|
|
|
1983
1952
|
name: 'Mastra',
|
|
1984
1953
|
level: 'info',
|
|
1985
1954
|
}),
|
|
1986
|
-
|
|
1987
|
-
//
|
|
1988
|
-
enabled:
|
|
1989
|
-
|
|
1990
|
-
observability: {
|
|
1991
|
-
// Enables DefaultExporter and CloudExporter for AI tracing
|
|
1992
|
-
default: { enabled: true },
|
|
1993
|
-
},
|
|
1955
|
+
observability: new Observability({
|
|
1956
|
+
// Enables DefaultExporter and CloudExporter for tracing
|
|
1957
|
+
default: { enabled: true },
|
|
1958
|
+
}),
|
|
1994
1959
|
});
|
|
1995
1960
|
`
|
|
1996
1961
|
);
|
|
@@ -1998,7 +1963,6 @@ export const mastra = new Mastra({
|
|
|
1998
1963
|
throw err;
|
|
1999
1964
|
}
|
|
2000
1965
|
};
|
|
2001
|
-
yoctoSpinner({ text: "Installing Mastra core dependencies\n" });
|
|
2002
1966
|
var getAPIKey = async (provider) => {
|
|
2003
1967
|
let key = "OPENAI_API_KEY";
|
|
2004
1968
|
switch (provider) {
|
|
@@ -2024,15 +1988,15 @@ var getAPIKey = async (provider) => {
|
|
|
2024
1988
|
var writeAPIKey = async ({ provider, apiKey }) => {
|
|
2025
1989
|
const envFileName = apiKey ? ".env" : ".env.example";
|
|
2026
1990
|
const key = await getAPIKey(provider);
|
|
2027
|
-
const escapedKey =
|
|
2028
|
-
const escapedApiKey =
|
|
2029
|
-
await
|
|
1991
|
+
const escapedKey = shellQuote2.quote([key]);
|
|
1992
|
+
const escapedApiKey = shellQuote2.quote([apiKey ? apiKey : "your-api-key"]);
|
|
1993
|
+
await exec(`echo ${escapedKey}=${escapedApiKey} >> ${envFileName}`);
|
|
2030
1994
|
};
|
|
2031
1995
|
var createMastraDir = async (directory) => {
|
|
2032
1996
|
let dir = directory.trim().split("/").filter((item) => item !== "");
|
|
2033
1997
|
const dirPath = path3.join(process.cwd(), ...dir, "mastra");
|
|
2034
1998
|
try {
|
|
2035
|
-
await
|
|
1999
|
+
await fs4.access(dirPath);
|
|
2036
2000
|
return { ok: false };
|
|
2037
2001
|
} catch {
|
|
2038
2002
|
await fsExtra.ensureDir(dirPath);
|
|
@@ -2055,8 +2019,8 @@ var LLM_PROVIDERS = [
|
|
|
2055
2019
|
{ value: "cerebras", label: "Cerebras" },
|
|
2056
2020
|
{ value: "mistral", label: "Mistral" }
|
|
2057
2021
|
];
|
|
2058
|
-
var interactivePrompt = async (
|
|
2059
|
-
const { skip = {}, options: { showBanner = true } = {} } =
|
|
2022
|
+
var interactivePrompt = async (args = {}) => {
|
|
2023
|
+
const { skip = {}, options: { showBanner = true } = {} } = args;
|
|
2060
2024
|
if (showBanner) {
|
|
2061
2025
|
Ie(color2.inverse(" Mastra Init "));
|
|
2062
2026
|
}
|
|
@@ -2094,46 +2058,29 @@ var interactivePrompt = async (args2 = {}) => {
|
|
|
2094
2058
|
return void 0;
|
|
2095
2059
|
},
|
|
2096
2060
|
configureEditorWithDocsMCP: async () => {
|
|
2097
|
-
const windsurfIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`windsurf`);
|
|
2098
|
-
const cursorIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`cursor`);
|
|
2099
|
-
const vscodeIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`vscode`);
|
|
2100
2061
|
const editor = await ve({
|
|
2101
2062
|
message: `Make your IDE into a Mastra expert? (Installs Mastra's MCP server)`,
|
|
2102
2063
|
options: [
|
|
2103
2064
|
{ value: "skip", label: "Skip for now", hint: "default" },
|
|
2104
2065
|
{
|
|
2105
2066
|
value: "cursor",
|
|
2106
|
-
label: "Cursor (project only)"
|
|
2107
|
-
hint: cursorIsAlreadyInstalled ? `Already installed globally` : void 0
|
|
2067
|
+
label: "Cursor (project only)"
|
|
2108
2068
|
},
|
|
2109
2069
|
{
|
|
2110
2070
|
value: "cursor-global",
|
|
2111
|
-
label: "Cursor (global, all projects)"
|
|
2112
|
-
hint: cursorIsAlreadyInstalled ? `Already installed` : void 0
|
|
2071
|
+
label: "Cursor (global, all projects)"
|
|
2113
2072
|
},
|
|
2114
2073
|
{
|
|
2115
2074
|
value: "windsurf",
|
|
2116
|
-
label: "Windsurf"
|
|
2117
|
-
hint: windsurfIsAlreadyInstalled ? `Already installed` : void 0
|
|
2075
|
+
label: "Windsurf"
|
|
2118
2076
|
},
|
|
2119
2077
|
{
|
|
2120
2078
|
value: "vscode",
|
|
2121
|
-
label: "VSCode"
|
|
2122
|
-
hint: vscodeIsAlreadyInstalled ? `Already installed` : void 0
|
|
2079
|
+
label: "VSCode"
|
|
2123
2080
|
}
|
|
2124
2081
|
]
|
|
2125
2082
|
});
|
|
2126
2083
|
if (editor === `skip`) return void 0;
|
|
2127
|
-
if (editor === `windsurf` && windsurfIsAlreadyInstalled) {
|
|
2128
|
-
M.message(`
|
|
2129
|
-
Windsurf is already installed, skipping.`);
|
|
2130
|
-
return void 0;
|
|
2131
|
-
}
|
|
2132
|
-
if (editor === `vscode` && vscodeIsAlreadyInstalled) {
|
|
2133
|
-
M.message(`
|
|
2134
|
-
VSCode is already installed, skipping.`);
|
|
2135
|
-
return void 0;
|
|
2136
|
-
}
|
|
2137
2084
|
if (editor === `cursor`) {
|
|
2138
2085
|
M.message(
|
|
2139
2086
|
`
|
|
@@ -2142,19 +2089,19 @@ Note: you will need to go into Cursor Settings -> MCP Settings and manually enab
|
|
|
2142
2089
|
);
|
|
2143
2090
|
}
|
|
2144
2091
|
if (editor === `cursor-global`) {
|
|
2145
|
-
const
|
|
2092
|
+
const confirm = await ve({
|
|
2146
2093
|
message: `Global install will add/update ${cursorGlobalMCPConfigPath} and make the Mastra docs MCP server available in all your Cursor projects. Continue?`,
|
|
2147
2094
|
options: [
|
|
2148
2095
|
{ value: "yes", label: "Yes, I understand" },
|
|
2149
2096
|
{ value: "skip", label: "No, skip for now" }
|
|
2150
2097
|
]
|
|
2151
2098
|
});
|
|
2152
|
-
if (
|
|
2099
|
+
if (confirm !== `yes`) {
|
|
2153
2100
|
return void 0;
|
|
2154
2101
|
}
|
|
2155
2102
|
}
|
|
2156
2103
|
if (editor === `windsurf`) {
|
|
2157
|
-
const
|
|
2104
|
+
const confirm = await ve({
|
|
2158
2105
|
message: `Windsurf only supports a global MCP config (at ${windsurfGlobalMCPConfigPath}) is it ok to add/update that global config?
|
|
2159
2106
|
This means the Mastra docs MCP server will be available in all your Windsurf projects.`,
|
|
2160
2107
|
options: [
|
|
@@ -2162,7 +2109,7 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2162
2109
|
{ value: "skip", label: "No, skip for now" }
|
|
2163
2110
|
]
|
|
2164
2111
|
});
|
|
2165
|
-
if (
|
|
2112
|
+
if (confirm !== `yes`) {
|
|
2166
2113
|
return void 0;
|
|
2167
2114
|
}
|
|
2168
2115
|
}
|
|
@@ -2178,16 +2125,230 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2178
2125
|
);
|
|
2179
2126
|
return mastraProject;
|
|
2180
2127
|
};
|
|
2128
|
+
function getPackageManager() {
|
|
2129
|
+
const userAgent = process.env.npm_config_user_agent || "";
|
|
2130
|
+
const execPath = process.env.npm_execpath || "";
|
|
2131
|
+
if (userAgent.includes("bun")) {
|
|
2132
|
+
return "bun";
|
|
2133
|
+
}
|
|
2134
|
+
if (userAgent.includes("yarn")) {
|
|
2135
|
+
return "yarn";
|
|
2136
|
+
}
|
|
2137
|
+
if (userAgent.includes("pnpm")) {
|
|
2138
|
+
return "pnpm";
|
|
2139
|
+
}
|
|
2140
|
+
if (userAgent.includes("npm")) {
|
|
2141
|
+
return "npm";
|
|
2142
|
+
}
|
|
2143
|
+
if (execPath.includes("bun")) {
|
|
2144
|
+
return "bun";
|
|
2145
|
+
}
|
|
2146
|
+
if (execPath.includes("yarn")) {
|
|
2147
|
+
return "yarn";
|
|
2148
|
+
}
|
|
2149
|
+
if (execPath.includes("pnpm")) {
|
|
2150
|
+
return "pnpm";
|
|
2151
|
+
}
|
|
2152
|
+
if (execPath.includes("npm")) {
|
|
2153
|
+
return "npm";
|
|
2154
|
+
}
|
|
2155
|
+
return "npm";
|
|
2156
|
+
}
|
|
2157
|
+
var logger = createLogger(false);
|
|
2158
|
+
function createLogger(debug = false) {
|
|
2159
|
+
return new PinoLogger({
|
|
2160
|
+
name: "Mastra CLI",
|
|
2161
|
+
level: debug ? "debug" : "info"
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2164
|
+
var exec2 = util.promisify(child_process.exec);
|
|
2165
|
+
async function cloneTemplate(options) {
|
|
2166
|
+
const { template, projectName, targetDir, branch, llmProvider } = options;
|
|
2167
|
+
const projectPath = targetDir ? path3.resolve(targetDir, projectName) : path3.resolve(projectName);
|
|
2168
|
+
const spinner4 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
|
|
2169
|
+
try {
|
|
2170
|
+
if (await directoryExists(projectPath)) {
|
|
2171
|
+
spinner4.error(`Directory ${projectName} already exists`);
|
|
2172
|
+
throw new Error(`Directory ${projectName} already exists`);
|
|
2173
|
+
}
|
|
2174
|
+
await cloneRepositoryWithoutGit(template.githubUrl, projectPath, branch);
|
|
2175
|
+
await updatePackageJson(projectPath, projectName);
|
|
2176
|
+
const envExamplePath = path3.join(projectPath, ".env.example");
|
|
2177
|
+
if (await fileExists(envExamplePath)) {
|
|
2178
|
+
const envPath = path3.join(projectPath, ".env");
|
|
2179
|
+
await fs4.copyFile(envExamplePath, envPath);
|
|
2180
|
+
if (llmProvider) {
|
|
2181
|
+
await updateEnvFile(envPath, llmProvider);
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
spinner4.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
2185
|
+
return projectPath;
|
|
2186
|
+
} catch (error) {
|
|
2187
|
+
spinner4.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2188
|
+
throw error;
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
async function directoryExists(dirPath) {
|
|
2192
|
+
try {
|
|
2193
|
+
const stat = await fs4.stat(dirPath);
|
|
2194
|
+
return stat.isDirectory();
|
|
2195
|
+
} catch {
|
|
2196
|
+
return false;
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
async function fileExists(filePath) {
|
|
2200
|
+
try {
|
|
2201
|
+
const stat = await fs4.stat(filePath);
|
|
2202
|
+
return stat.isFile();
|
|
2203
|
+
} catch {
|
|
2204
|
+
return false;
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
async function cloneRepositoryWithoutGit(repoUrl, targetPath, branch) {
|
|
2208
|
+
await fs4.mkdir(targetPath, { recursive: true });
|
|
2209
|
+
try {
|
|
2210
|
+
const degitRepo = repoUrl.replace("https://github.com/", "");
|
|
2211
|
+
const degitRepoWithBranch = branch ? `${degitRepo}#${branch}` : degitRepo;
|
|
2212
|
+
const degitCommand = shellQuote2.quote(["npx", "degit", degitRepoWithBranch, targetPath]);
|
|
2213
|
+
await exec2(degitCommand, {
|
|
2214
|
+
cwd: process.cwd()
|
|
2215
|
+
});
|
|
2216
|
+
} catch {
|
|
2217
|
+
try {
|
|
2218
|
+
const gitArgs = ["git", "clone"];
|
|
2219
|
+
if (branch) {
|
|
2220
|
+
gitArgs.push("--branch", branch);
|
|
2221
|
+
}
|
|
2222
|
+
gitArgs.push(repoUrl, targetPath);
|
|
2223
|
+
const gitCommand = shellQuote2.quote(gitArgs);
|
|
2224
|
+
await exec2(gitCommand, {
|
|
2225
|
+
cwd: process.cwd()
|
|
2226
|
+
});
|
|
2227
|
+
const gitDir = path3.join(targetPath, ".git");
|
|
2228
|
+
if (await directoryExists(gitDir)) {
|
|
2229
|
+
await fs4.rm(gitDir, { recursive: true, force: true });
|
|
2230
|
+
}
|
|
2231
|
+
} catch (gitError) {
|
|
2232
|
+
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
async function updatePackageJson(projectPath, projectName) {
|
|
2237
|
+
const packageJsonPath = path3.join(projectPath, "package.json");
|
|
2238
|
+
try {
|
|
2239
|
+
const packageJsonContent = await fs4.readFile(packageJsonPath, "utf-8");
|
|
2240
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
2241
|
+
packageJson.name = projectName;
|
|
2242
|
+
await fs4.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
2243
|
+
} catch (error) {
|
|
2244
|
+
logger.warn(`Could not update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
async function updateEnvFile(envPath, llmProvider) {
|
|
2248
|
+
try {
|
|
2249
|
+
const envContent = await fs4.readFile(envPath, "utf-8");
|
|
2250
|
+
const modelString = getModelIdentifier(llmProvider);
|
|
2251
|
+
if (!modelString) {
|
|
2252
|
+
logger.warn(`Could not get model identifier for provider: ${llmProvider}`);
|
|
2253
|
+
return;
|
|
2254
|
+
}
|
|
2255
|
+
const modelValue = modelString.replace(/'/g, "");
|
|
2256
|
+
const updatedContent = envContent.replace(/^MODEL=.*/m, `MODEL=${modelValue}`);
|
|
2257
|
+
await fs4.writeFile(envPath, updatedContent, "utf-8");
|
|
2258
|
+
logger.info(`Updated MODEL in .env to ${modelValue}`);
|
|
2259
|
+
} catch (error) {
|
|
2260
|
+
logger.warn(`Could not update .env file: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
async function installDependencies(projectPath, packageManager) {
|
|
2264
|
+
const spinner4 = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
2265
|
+
try {
|
|
2266
|
+
const pm = packageManager || getPackageManager();
|
|
2267
|
+
const installCommand = shellQuote2.quote([pm, "install"]);
|
|
2268
|
+
await exec2(installCommand, {
|
|
2269
|
+
cwd: projectPath
|
|
2270
|
+
});
|
|
2271
|
+
spinner4.success("Dependencies installed successfully");
|
|
2272
|
+
} catch (error) {
|
|
2273
|
+
spinner4.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2274
|
+
throw error;
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
|
|
2278
|
+
async function loadTemplates() {
|
|
2279
|
+
try {
|
|
2280
|
+
const response = await fetch(TEMPLATES_API_URL);
|
|
2281
|
+
if (!response.ok) {
|
|
2282
|
+
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
2283
|
+
}
|
|
2284
|
+
const templates = await response.json();
|
|
2285
|
+
return templates;
|
|
2286
|
+
} catch (error) {
|
|
2287
|
+
console.error("Error loading templates:", error);
|
|
2288
|
+
throw new Error("Failed to load templates. Please check your internet connection and try again.");
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
function pluralize(count, singular, plural) {
|
|
2292
|
+
return count === 1 ? singular : plural || `${singular}s`;
|
|
2293
|
+
}
|
|
2294
|
+
async function selectTemplate(templates) {
|
|
2295
|
+
const choices = templates.map((template) => {
|
|
2296
|
+
const parts = [];
|
|
2297
|
+
if (template.agents?.length) {
|
|
2298
|
+
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
|
|
2299
|
+
}
|
|
2300
|
+
if (template.tools?.length) {
|
|
2301
|
+
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
|
|
2302
|
+
}
|
|
2303
|
+
if (template.workflows?.length) {
|
|
2304
|
+
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
|
|
2305
|
+
}
|
|
2306
|
+
if (template.mcp?.length) {
|
|
2307
|
+
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
|
|
2308
|
+
}
|
|
2309
|
+
if (template.networks?.length) {
|
|
2310
|
+
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
|
|
2311
|
+
}
|
|
2312
|
+
return {
|
|
2313
|
+
value: template,
|
|
2314
|
+
label: template.title,
|
|
2315
|
+
hint: parts.join(", ") || "Template components"
|
|
2316
|
+
};
|
|
2317
|
+
});
|
|
2318
|
+
const selected = await ve({
|
|
2319
|
+
message: "Select a template:",
|
|
2320
|
+
options: choices
|
|
2321
|
+
});
|
|
2322
|
+
if (pD(selected)) {
|
|
2323
|
+
return null;
|
|
2324
|
+
}
|
|
2325
|
+
return selected;
|
|
2326
|
+
}
|
|
2327
|
+
function findTemplateByName(templates, templateName) {
|
|
2328
|
+
let template = templates.find((t) => t.slug === templateName);
|
|
2329
|
+
if (template) return template;
|
|
2330
|
+
const slugWithPrefix = `template-${templateName}`;
|
|
2331
|
+
template = templates.find((t) => t.slug === slugWithPrefix);
|
|
2332
|
+
if (template) return template;
|
|
2333
|
+
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
|
|
2334
|
+
if (template) return template;
|
|
2335
|
+
return null;
|
|
2336
|
+
}
|
|
2337
|
+
function getDefaultProjectName(template) {
|
|
2338
|
+
return template.slug.replace(/^template-/, "");
|
|
2339
|
+
}
|
|
2181
2340
|
var s = Y();
|
|
2182
2341
|
var init = async ({
|
|
2183
|
-
directory,
|
|
2184
|
-
addExample = false,
|
|
2342
|
+
directory = "src/",
|
|
2185
2343
|
components,
|
|
2186
2344
|
llmProvider = "openai",
|
|
2187
2345
|
llmApiKey,
|
|
2188
|
-
|
|
2346
|
+
addExample = false,
|
|
2347
|
+
configureEditorWithDocsMCP,
|
|
2348
|
+
versionTag
|
|
2189
2349
|
}) => {
|
|
2190
2350
|
s.start("Initializing Mastra");
|
|
2351
|
+
const packageVersionTag = versionTag ? `@${versionTag}` : "";
|
|
2191
2352
|
try {
|
|
2192
2353
|
const result = await createMastraDir(directory);
|
|
2193
2354
|
if (!result.ok) {
|
|
@@ -2200,7 +2361,8 @@ var init = async ({
|
|
|
2200
2361
|
dirPath,
|
|
2201
2362
|
addExample,
|
|
2202
2363
|
addWorkflow: components.includes("workflows"),
|
|
2203
|
-
addAgent: components.includes("agents")
|
|
2364
|
+
addAgent: components.includes("agents"),
|
|
2365
|
+
addScorers: components.includes("scorers")
|
|
2204
2366
|
}),
|
|
2205
2367
|
...components.map((component) => createComponentsDir(dirPath, component)),
|
|
2206
2368
|
writeAPIKey({ provider: llmProvider, apiKey: llmApiKey })
|
|
@@ -2214,22 +2376,31 @@ var init = async ({
|
|
|
2214
2376
|
const depService = new DepsService();
|
|
2215
2377
|
const needsLibsql = await depService.checkDependencies(["@mastra/libsql"]) !== `ok`;
|
|
2216
2378
|
if (needsLibsql) {
|
|
2217
|
-
await depService.installPackages([
|
|
2379
|
+
await depService.installPackages([`@mastra/libsql${packageVersionTag}`]);
|
|
2218
2380
|
}
|
|
2219
2381
|
const needsMemory = components.includes(`agents`) && await depService.checkDependencies(["@mastra/memory"]) !== `ok`;
|
|
2220
2382
|
if (needsMemory) {
|
|
2221
|
-
await depService.installPackages([
|
|
2383
|
+
await depService.installPackages([`@mastra/memory${packageVersionTag}`]);
|
|
2222
2384
|
}
|
|
2223
2385
|
const needsLoggers = await depService.checkDependencies(["@mastra/loggers"]) !== `ok`;
|
|
2224
2386
|
if (needsLoggers) {
|
|
2225
|
-
await depService.installPackages([
|
|
2387
|
+
await depService.installPackages([`@mastra/loggers${packageVersionTag}`]);
|
|
2388
|
+
}
|
|
2389
|
+
const needsObservability = await depService.checkDependencies(["@mastra/observability"]) !== `ok`;
|
|
2390
|
+
if (needsObservability) {
|
|
2391
|
+
await depService.installPackages([`@mastra/observability${packageVersionTag}`]);
|
|
2392
|
+
}
|
|
2393
|
+
const needsEvals = components.includes(`scorers`) && await depService.checkDependencies(["@mastra/evals"]) !== `ok`;
|
|
2394
|
+
if (needsEvals) {
|
|
2395
|
+
await depService.installPackages([`@mastra/evals${packageVersionTag}`]);
|
|
2226
2396
|
}
|
|
2227
2397
|
}
|
|
2228
2398
|
const key = await getAPIKey(llmProvider || "openai");
|
|
2229
2399
|
if (configureEditorWithDocsMCP) {
|
|
2230
2400
|
await installMastraDocsMCPServer({
|
|
2231
2401
|
editor: configureEditorWithDocsMCP,
|
|
2232
|
-
directory: process.cwd()
|
|
2402
|
+
directory: process.cwd(),
|
|
2403
|
+
versionTag
|
|
2233
2404
|
});
|
|
2234
2405
|
}
|
|
2235
2406
|
s.stop();
|
|
@@ -2278,6 +2449,32 @@ var execWithTimeout = async (command, timeoutMs) => {
|
|
|
2278
2449
|
throw error;
|
|
2279
2450
|
}
|
|
2280
2451
|
};
|
|
2452
|
+
async function getInitCommand(pm) {
|
|
2453
|
+
switch (pm) {
|
|
2454
|
+
case "npm":
|
|
2455
|
+
return "npm init -y";
|
|
2456
|
+
case "pnpm":
|
|
2457
|
+
return "pnpm init";
|
|
2458
|
+
case "yarn":
|
|
2459
|
+
return "yarn init -y";
|
|
2460
|
+
case "bun":
|
|
2461
|
+
return "bun init -y";
|
|
2462
|
+
default:
|
|
2463
|
+
return "npm init -y";
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
async function initializePackageJson(pm) {
|
|
2467
|
+
const initCommand = await getInitCommand(pm);
|
|
2468
|
+
await exec3(initCommand);
|
|
2469
|
+
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
2470
|
+
const packageJson = JSON.parse(await fs4.readFile(packageJsonPath, "utf-8"));
|
|
2471
|
+
packageJson.type = "module";
|
|
2472
|
+
packageJson.engines = {
|
|
2473
|
+
...packageJson.engines,
|
|
2474
|
+
node: ">=22.13.0"
|
|
2475
|
+
};
|
|
2476
|
+
await fs4.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
2477
|
+
}
|
|
2281
2478
|
async function installMastraDependency(pm, dependency, versionTag, isDev, timeout) {
|
|
2282
2479
|
let installCommand = getPackageManagerAddCommand(pm);
|
|
2283
2480
|
if (isDev) {
|
|
@@ -2315,7 +2512,7 @@ var createMastraProject = async ({
|
|
|
2315
2512
|
defaultValue: "my-mastra-app",
|
|
2316
2513
|
validate: (value) => {
|
|
2317
2514
|
if (value.length === 0) return "Project name cannot be empty";
|
|
2318
|
-
if (
|
|
2515
|
+
if (fs3__default__default.existsSync(value)) {
|
|
2319
2516
|
return `A directory named "${value}" already exists. Please choose a different name.`;
|
|
2320
2517
|
}
|
|
2321
2518
|
}
|
|
@@ -2332,10 +2529,13 @@ var createMastraProject = async ({
|
|
|
2332
2529
|
});
|
|
2333
2530
|
}
|
|
2334
2531
|
const s2 = Y();
|
|
2532
|
+
const originalCwd = process.cwd();
|
|
2533
|
+
let projectPath = null;
|
|
2335
2534
|
try {
|
|
2336
2535
|
s2.start("Creating project");
|
|
2337
2536
|
try {
|
|
2338
|
-
await
|
|
2537
|
+
await fs4.mkdir(projectName);
|
|
2538
|
+
projectPath = path3.resolve(originalCwd, projectName);
|
|
2339
2539
|
} catch (error) {
|
|
2340
2540
|
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
2341
2541
|
s2.stop(`A directory named "${projectName}" already exists. Please choose a different name.`);
|
|
@@ -2350,9 +2550,7 @@ var createMastraProject = async ({
|
|
|
2350
2550
|
const installCommand = getPackageManagerAddCommand(pm);
|
|
2351
2551
|
s2.message("Initializing project structure");
|
|
2352
2552
|
try {
|
|
2353
|
-
await
|
|
2354
|
-
await exec3(`npm pkg set type="module"`);
|
|
2355
|
-
await exec3(`npm pkg set engines.node=">=20.9.0"`);
|
|
2553
|
+
await initializePackageJson(pm);
|
|
2356
2554
|
const depsService = new DepsService();
|
|
2357
2555
|
await depsService.addScriptsToPackageJson({
|
|
2358
2556
|
dev: "mastra dev",
|
|
@@ -2367,8 +2565,8 @@ var createMastraProject = async ({
|
|
|
2367
2565
|
s2.stop("Project structure created");
|
|
2368
2566
|
s2.start(`Installing ${pm} dependencies`);
|
|
2369
2567
|
try {
|
|
2370
|
-
await exec3(`${pm} ${installCommand} zod@^
|
|
2371
|
-
await exec3(`${pm} ${installCommand} typescript @types/node
|
|
2568
|
+
await exec3(`${pm} ${installCommand} zod@^4`);
|
|
2569
|
+
await exec3(`${pm} ${installCommand} -D typescript @types/node`);
|
|
2372
2570
|
await exec3(`echo '{
|
|
2373
2571
|
"compilerOptions": {
|
|
2374
2572
|
"target": "ES2022",
|
|
@@ -2431,42 +2629,61 @@ var createMastraProject = async ({
|
|
|
2431
2629
|
s2.stop();
|
|
2432
2630
|
const errorMessage = error instanceof Error ? error.message : "An unexpected error occurred";
|
|
2433
2631
|
xe(`Project creation failed: ${errorMessage}`);
|
|
2632
|
+
if (projectPath && fs3__default__default.existsSync(projectPath)) {
|
|
2633
|
+
try {
|
|
2634
|
+
process.chdir(originalCwd);
|
|
2635
|
+
await fs4.rm(projectPath, { recursive: true, force: true });
|
|
2636
|
+
} catch (cleanupError) {
|
|
2637
|
+
console.error(
|
|
2638
|
+
`Warning: Failed to clean up project directory: ${cleanupError instanceof Error ? cleanupError.message : "Unknown error"}`
|
|
2639
|
+
);
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2434
2642
|
process.exit(1);
|
|
2435
2643
|
}
|
|
2436
2644
|
};
|
|
2437
|
-
var
|
|
2438
|
-
|
|
2439
|
-
|
|
2645
|
+
var version$1 = package_default.version;
|
|
2646
|
+
var create = async (args) => {
|
|
2647
|
+
if (args.template !== void 0) {
|
|
2648
|
+
await createFromTemplate({
|
|
2649
|
+
projectName: args.projectName,
|
|
2650
|
+
template: args.template,
|
|
2651
|
+
timeout: args.timeout,
|
|
2652
|
+
injectedAnalytics: args.analytics,
|
|
2653
|
+
llmProvider: args.llmProvider
|
|
2654
|
+
});
|
|
2440
2655
|
return;
|
|
2441
2656
|
}
|
|
2442
|
-
const needsInteractive =
|
|
2657
|
+
const needsInteractive = args.components === void 0 || args.llmProvider === void 0 || args.addExample === void 0;
|
|
2443
2658
|
const { projectName, result } = await createMastraProject({
|
|
2444
|
-
projectName:
|
|
2445
|
-
createVersionTag:
|
|
2446
|
-
timeout:
|
|
2447
|
-
llmProvider:
|
|
2448
|
-
llmApiKey:
|
|
2659
|
+
projectName: args?.projectName,
|
|
2660
|
+
createVersionTag: args?.createVersionTag,
|
|
2661
|
+
timeout: args?.timeout,
|
|
2662
|
+
llmProvider: args?.llmProvider,
|
|
2663
|
+
llmApiKey: args?.llmApiKey,
|
|
2449
2664
|
needsInteractive
|
|
2450
2665
|
});
|
|
2451
|
-
const directory =
|
|
2666
|
+
const directory = args.directory || "src/";
|
|
2452
2667
|
if (needsInteractive && result) {
|
|
2453
2668
|
await init({
|
|
2454
2669
|
...result,
|
|
2455
2670
|
llmApiKey: result?.llmApiKey,
|
|
2456
|
-
components: ["agents", "tools", "workflows"],
|
|
2457
|
-
addExample: true
|
|
2671
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2672
|
+
addExample: true,
|
|
2673
|
+
versionTag: args.createVersionTag
|
|
2458
2674
|
});
|
|
2459
2675
|
postCreate({ projectName });
|
|
2460
2676
|
return;
|
|
2461
2677
|
}
|
|
2462
|
-
const { components = [], llmProvider = "openai", addExample = false, llmApiKey } =
|
|
2678
|
+
const { components = [], llmProvider = "openai", addExample = false, llmApiKey } = args;
|
|
2463
2679
|
await init({
|
|
2464
2680
|
directory,
|
|
2465
2681
|
components,
|
|
2466
2682
|
llmProvider,
|
|
2467
2683
|
addExample,
|
|
2468
2684
|
llmApiKey,
|
|
2469
|
-
configureEditorWithDocsMCP:
|
|
2685
|
+
configureEditorWithDocsMCP: args.mcpServer,
|
|
2686
|
+
versionTag: args.createVersionTag
|
|
2470
2687
|
});
|
|
2471
2688
|
postCreate({ projectName });
|
|
2472
2689
|
};
|
|
@@ -2557,9 +2774,9 @@ async function createFromGitHubUrl(url) {
|
|
|
2557
2774
|
workflows: []
|
|
2558
2775
|
};
|
|
2559
2776
|
}
|
|
2560
|
-
async function createFromTemplate(
|
|
2777
|
+
async function createFromTemplate(args) {
|
|
2561
2778
|
let selectedTemplate;
|
|
2562
|
-
if (
|
|
2779
|
+
if (args.template === true) {
|
|
2563
2780
|
const templates = await loadTemplates();
|
|
2564
2781
|
const selected = await selectTemplate(templates);
|
|
2565
2782
|
if (!selected) {
|
|
@@ -2567,26 +2784,26 @@ async function createFromTemplate(args2) {
|
|
|
2567
2784
|
return;
|
|
2568
2785
|
}
|
|
2569
2786
|
selectedTemplate = selected;
|
|
2570
|
-
} else if (
|
|
2571
|
-
if (isGitHubUrl(
|
|
2572
|
-
const
|
|
2573
|
-
|
|
2574
|
-
const validation = await validateGitHubProject(
|
|
2787
|
+
} else if (args.template && typeof args.template === "string") {
|
|
2788
|
+
if (isGitHubUrl(args.template)) {
|
|
2789
|
+
const spinner4 = Y();
|
|
2790
|
+
spinner4.start("Validating GitHub repository...");
|
|
2791
|
+
const validation = await validateGitHubProject(args.template);
|
|
2575
2792
|
if (!validation.isValid) {
|
|
2576
|
-
|
|
2793
|
+
spinner4.stop("Validation failed");
|
|
2577
2794
|
M.error("This does not appear to be a valid Mastra project:");
|
|
2578
2795
|
validation.errors.forEach((error) => M.error(` - ${error}`));
|
|
2579
2796
|
throw new Error("Invalid Mastra project");
|
|
2580
2797
|
}
|
|
2581
|
-
|
|
2582
|
-
selectedTemplate = await createFromGitHubUrl(
|
|
2798
|
+
spinner4.stop("Valid Mastra project \u2713");
|
|
2799
|
+
selectedTemplate = await createFromGitHubUrl(args.template);
|
|
2583
2800
|
} else {
|
|
2584
2801
|
const templates = await loadTemplates();
|
|
2585
|
-
const found = findTemplateByName(templates,
|
|
2802
|
+
const found = findTemplateByName(templates, args.template);
|
|
2586
2803
|
if (!found) {
|
|
2587
|
-
M.error(`Template "${
|
|
2804
|
+
M.error(`Template "${args.template}" not found. Available templates:`);
|
|
2588
2805
|
templates.forEach((t) => M.info(` - ${t.title} (use: ${t.slug.replace("template-", "")})`));
|
|
2589
|
-
throw new Error(`Template "${
|
|
2806
|
+
throw new Error(`Template "${args.template}" not found`);
|
|
2590
2807
|
}
|
|
2591
2808
|
selectedTemplate = found;
|
|
2592
2809
|
}
|
|
@@ -2594,7 +2811,7 @@ async function createFromTemplate(args2) {
|
|
|
2594
2811
|
if (!selectedTemplate) {
|
|
2595
2812
|
throw new Error("No template selected");
|
|
2596
2813
|
}
|
|
2597
|
-
let projectName =
|
|
2814
|
+
let projectName = args.projectName;
|
|
2598
2815
|
if (!projectName) {
|
|
2599
2816
|
const defaultName = getDefaultProjectName(selectedTemplate);
|
|
2600
2817
|
const response = await he({
|
|
@@ -2608,17 +2825,41 @@ async function createFromTemplate(args2) {
|
|
|
2608
2825
|
}
|
|
2609
2826
|
projectName = response;
|
|
2610
2827
|
}
|
|
2828
|
+
let llmProvider = args.llmProvider;
|
|
2829
|
+
if (!llmProvider) {
|
|
2830
|
+
const providerResponse = await ve({
|
|
2831
|
+
message: "Select a default provider:",
|
|
2832
|
+
options: LLM_PROVIDERS
|
|
2833
|
+
});
|
|
2834
|
+
if (pD(providerResponse)) {
|
|
2835
|
+
M.info("Project creation cancelled.");
|
|
2836
|
+
return;
|
|
2837
|
+
}
|
|
2838
|
+
llmProvider = providerResponse;
|
|
2839
|
+
}
|
|
2840
|
+
let projectPath = null;
|
|
2611
2841
|
try {
|
|
2612
|
-
const analytics =
|
|
2842
|
+
const analytics = args.injectedAnalytics || getAnalytics();
|
|
2613
2843
|
if (analytics) {
|
|
2614
2844
|
analytics.trackEvent("cli_template_used", {
|
|
2615
2845
|
template_slug: selectedTemplate.slug,
|
|
2616
2846
|
template_title: selectedTemplate.title
|
|
2617
2847
|
});
|
|
2848
|
+
if (llmProvider) {
|
|
2849
|
+
analytics.trackEvent("cli_model_provider_selected", {
|
|
2850
|
+
provider: llmProvider,
|
|
2851
|
+
selection_method: args.llmProvider ? "cli_args" : "interactive"
|
|
2852
|
+
});
|
|
2853
|
+
}
|
|
2618
2854
|
}
|
|
2619
|
-
const
|
|
2855
|
+
const isBeta = version$1?.includes("beta") ?? false;
|
|
2856
|
+
const isMastraTemplate = selectedTemplate.githubUrl.includes("github.com/mastra-ai/");
|
|
2857
|
+
const branch = isBeta && isMastraTemplate ? "beta" : void 0;
|
|
2858
|
+
projectPath = await cloneTemplate({
|
|
2620
2859
|
template: selectedTemplate,
|
|
2621
|
-
projectName
|
|
2860
|
+
projectName,
|
|
2861
|
+
branch,
|
|
2862
|
+
llmProvider
|
|
2622
2863
|
});
|
|
2623
2864
|
await installDependencies(projectPath);
|
|
2624
2865
|
Me(`
|
|
@@ -2629,6 +2870,17 @@ async function createFromTemplate(args2) {
|
|
|
2629
2870
|
`);
|
|
2630
2871
|
postCreate({ projectName });
|
|
2631
2872
|
} catch (error) {
|
|
2873
|
+
if (projectPath) {
|
|
2874
|
+
try {
|
|
2875
|
+
if (fs3__default__default.existsSync(projectPath)) {
|
|
2876
|
+
await fs4.rm(projectPath, { recursive: true, force: true });
|
|
2877
|
+
}
|
|
2878
|
+
} catch (cleanupError) {
|
|
2879
|
+
console.error(
|
|
2880
|
+
`Warning: Failed to clean up project directory: ${cleanupError instanceof Error ? cleanupError.message : "Unknown error"}`
|
|
2881
|
+
);
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2632
2884
|
M.error(`Failed to create project from template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2633
2885
|
throw error;
|
|
2634
2886
|
}
|
|
@@ -2675,7 +2927,7 @@ program.version(`${version}`, "-v, --version").description(`create-mastra ${vers
|
|
|
2675
2927
|
program.name("create-mastra").description("Create a new Mastra project").argument("[project-name]", "Directory name of the project").option(
|
|
2676
2928
|
"-p, --project-name <string>",
|
|
2677
2929
|
"Project name that will be used in package.json and as the project directory name."
|
|
2678
|
-
).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(
|
|
2930
|
+
).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(
|
|
2679
2931
|
"--template [template-name]",
|
|
2680
2932
|
"Create project from a template (use template name, public GitHub URL, or leave blank to select from list)"
|
|
2681
2933
|
).action(async (projectNameArg, args) => {
|
|
@@ -2683,7 +2935,7 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2683
2935
|
const timeout = args?.timeout ? args?.timeout === true ? 6e4 : parseInt(args?.timeout, 10) : void 0;
|
|
2684
2936
|
if (args.default) {
|
|
2685
2937
|
await create({
|
|
2686
|
-
components: ["agents", "tools", "workflows"],
|
|
2938
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2687
2939
|
llmProvider: "openai",
|
|
2688
2940
|
addExample: true,
|
|
2689
2941
|
createVersionTag,
|