create-mastra 0.0.0-pgvector-index-fix-20250905222058 → 0.0.0-playground-studio-again-20251114100107
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 +477 -1
- package/README.md +10 -32
- package/dist/index.js +707 -514
- package/dist/index.js.map +1 -1
- package/dist/starter-files/tools.ts +2 -2
- package/dist/templates/dev.entry.js +4 -42
- package/package.json +12 -12
- package/dist/templates/scorers/answer-relevancy-scorer.ts +0 -15
- package/dist/templates/scorers/bias-detection-scorer.ts +0 -16
- package/dist/templates/scorers/completeness-scorer.ts +0 -16
- package/dist/templates/scorers/content-similarity-scorer.ts +0 -15
- package/dist/templates/scorers/faithfulness-scorer.ts +0 -21
- package/dist/templates/scorers/hallucination-scorer.ts +0 -21
- package/dist/templates/scorers/keyword-coverage-scorer.ts +0 -15
- package/dist/templates/scorers/textual-difference-scorer.ts +0 -16
- package/dist/templates/scorers/tone-consistency-scorer.ts +0 -16
- package/dist/templates/scorers/toxicity-detection-scorer.ts +0 -16
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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';
|
|
@@ -12,15 +12,15 @@ import y$1, { stdout, stdin } from 'node:process';
|
|
|
12
12
|
import * as g from 'node:readline';
|
|
13
13
|
import g__default from 'node:readline';
|
|
14
14
|
import { Writable } from 'node:stream';
|
|
15
|
-
import
|
|
15
|
+
import fs4 from 'node:fs/promises';
|
|
16
16
|
import child_process from 'node:child_process';
|
|
17
17
|
import tty from 'node:tty';
|
|
18
|
+
import fsExtra, { readJSON, ensureFile, writeJSON } from 'fs-extra/esm';
|
|
19
|
+
import prettier from 'prettier';
|
|
20
|
+
import { execa } from 'execa';
|
|
18
21
|
import pino from 'pino';
|
|
19
22
|
import pretty from 'pino-pretty';
|
|
20
|
-
import
|
|
21
|
-
import fsExtra2, { readJSON, ensureFile, writeJSON } from 'fs-extra/esm';
|
|
22
|
-
import prettier from 'prettier';
|
|
23
|
-
import fsExtra from 'fs-extra';
|
|
23
|
+
import fsExtra$1 from 'fs-extra';
|
|
24
24
|
|
|
25
25
|
var __filename = fileURLToPath(import.meta.url);
|
|
26
26
|
var __dirname = path3.dirname(__filename);
|
|
@@ -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
|
}
|
|
@@ -882,6 +887,7 @@ class YoctoSpinner {
|
|
|
882
887
|
#exitHandlerBound;
|
|
883
888
|
#isInteractive;
|
|
884
889
|
#lastSpinnerFrameTime = 0;
|
|
890
|
+
#isSpinning = false;
|
|
885
891
|
|
|
886
892
|
constructor(options = {}) {
|
|
887
893
|
const spinner = options.spinner ?? defaultSpinner;
|
|
@@ -903,13 +909,17 @@ class YoctoSpinner {
|
|
|
903
909
|
return this;
|
|
904
910
|
}
|
|
905
911
|
|
|
912
|
+
this.#isSpinning = true;
|
|
906
913
|
this.#hideCursor();
|
|
907
914
|
this.#render();
|
|
908
915
|
this.#subscribeToProcessEvents();
|
|
909
916
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
917
|
+
// Only start the timer in interactive mode
|
|
918
|
+
if (this.#isInteractive) {
|
|
919
|
+
this.#timer = setInterval(() => {
|
|
920
|
+
this.#render();
|
|
921
|
+
}, this.#interval);
|
|
922
|
+
}
|
|
913
923
|
|
|
914
924
|
return this;
|
|
915
925
|
}
|
|
@@ -919,8 +929,12 @@ class YoctoSpinner {
|
|
|
919
929
|
return this;
|
|
920
930
|
}
|
|
921
931
|
|
|
922
|
-
|
|
923
|
-
this.#timer
|
|
932
|
+
this.#isSpinning = false;
|
|
933
|
+
if (this.#timer) {
|
|
934
|
+
clearInterval(this.#timer);
|
|
935
|
+
this.#timer = undefined;
|
|
936
|
+
}
|
|
937
|
+
|
|
924
938
|
this.#showCursor();
|
|
925
939
|
this.clear();
|
|
926
940
|
this.#unsubscribeFromProcessEvents();
|
|
@@ -953,7 +967,7 @@ class YoctoSpinner {
|
|
|
953
967
|
}
|
|
954
968
|
|
|
955
969
|
get isSpinning() {
|
|
956
|
-
return this.#
|
|
970
|
+
return this.#isSpinning;
|
|
957
971
|
}
|
|
958
972
|
|
|
959
973
|
get text() {
|
|
@@ -1090,11 +1104,11 @@ var MastraLogger = class {
|
|
|
1090
1104
|
}
|
|
1091
1105
|
trackException(_error) {
|
|
1092
1106
|
}
|
|
1093
|
-
async
|
|
1107
|
+
async listLogs(transportId, params) {
|
|
1094
1108
|
if (!transportId || !this.transports.has(transportId)) {
|
|
1095
1109
|
return { logs: [], total: 0, page: params?.page ?? 1, perPage: params?.perPage ?? 100, hasMore: false };
|
|
1096
1110
|
}
|
|
1097
|
-
return this.transports.get(transportId).
|
|
1111
|
+
return this.transports.get(transportId).listLogs(params) ?? {
|
|
1098
1112
|
logs: [],
|
|
1099
1113
|
total: 0,
|
|
1100
1114
|
page: params?.page ?? 1,
|
|
@@ -1102,7 +1116,7 @@ var MastraLogger = class {
|
|
|
1102
1116
|
hasMore: false
|
|
1103
1117
|
};
|
|
1104
1118
|
}
|
|
1105
|
-
async
|
|
1119
|
+
async listLogsByRunId({
|
|
1106
1120
|
transportId,
|
|
1107
1121
|
runId,
|
|
1108
1122
|
fromDate,
|
|
@@ -1115,7 +1129,7 @@ var MastraLogger = class {
|
|
|
1115
1129
|
if (!transportId || !this.transports.has(transportId) || !runId) {
|
|
1116
1130
|
return { logs: [], total: 0, page: page ?? 1, perPage: perPage ?? 100, hasMore: false };
|
|
1117
1131
|
}
|
|
1118
|
-
return this.transports.get(transportId).
|
|
1132
|
+
return this.transports.get(transportId).listLogsByRunId({ runId, fromDate, toDate, logLevel, filters, page, perPage }) ?? {
|
|
1119
1133
|
logs: [],
|
|
1120
1134
|
total: 0,
|
|
1121
1135
|
page: page ?? 1,
|
|
@@ -1173,183 +1187,8 @@ var PinoLogger = class extends MastraLogger {
|
|
|
1173
1187
|
}
|
|
1174
1188
|
};
|
|
1175
1189
|
|
|
1176
|
-
|
|
1177
|
-
|
|
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 fs.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 fs.stat(dirPath);
|
|
1229
|
-
return stat.isDirectory();
|
|
1230
|
-
} catch {
|
|
1231
|
-
return false;
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
async function fileExists(filePath) {
|
|
1235
|
-
try {
|
|
1236
|
-
const stat = await fs.stat(filePath);
|
|
1237
|
-
return stat.isFile();
|
|
1238
|
-
} catch {
|
|
1239
|
-
return false;
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
async function cloneRepositoryWithoutGit(repoUrl, targetPath) {
|
|
1243
|
-
await fs.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 fs.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 fs.readFile(packageJsonPath, "utf-8");
|
|
1269
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
1270
|
-
packageJson.name = projectName;
|
|
1271
|
-
await fs.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
|
-
}
|
|
1190
|
+
var package_default = {
|
|
1191
|
+
version: "1.0.0-beta.1"};
|
|
1353
1192
|
function getPackageManagerAddCommand(pm) {
|
|
1354
1193
|
switch (pm) {
|
|
1355
1194
|
case "npm":
|
|
@@ -1372,7 +1211,7 @@ var DepsService = class {
|
|
|
1372
1211
|
findLockFile(dir) {
|
|
1373
1212
|
const lockFiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock"];
|
|
1374
1213
|
for (const file of lockFiles) {
|
|
1375
|
-
if (
|
|
1214
|
+
if (fs3__default__default.existsSync(path3.join(dir, file))) {
|
|
1376
1215
|
return file;
|
|
1377
1216
|
}
|
|
1378
1217
|
}
|
|
@@ -1411,11 +1250,11 @@ var DepsService = class {
|
|
|
1411
1250
|
try {
|
|
1412
1251
|
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1413
1252
|
try {
|
|
1414
|
-
await
|
|
1253
|
+
await fs4.access(packageJsonPath);
|
|
1415
1254
|
} catch {
|
|
1416
1255
|
return "No package.json file found in the current directory";
|
|
1417
1256
|
}
|
|
1418
|
-
const packageJson = JSON.parse(await
|
|
1257
|
+
const packageJson = JSON.parse(await fs4.readFile(packageJsonPath, "utf-8"));
|
|
1419
1258
|
for (const dependency of dependencies) {
|
|
1420
1259
|
if (!packageJson.dependencies || !packageJson.dependencies[dependency]) {
|
|
1421
1260
|
return `Please install ${dependency} before running this command (${this.packageManager} install ${dependency})`;
|
|
@@ -1430,7 +1269,7 @@ var DepsService = class {
|
|
|
1430
1269
|
async getProjectName() {
|
|
1431
1270
|
try {
|
|
1432
1271
|
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1433
|
-
const packageJson = await
|
|
1272
|
+
const packageJson = await fs4.readFile(packageJsonPath, "utf-8");
|
|
1434
1273
|
const pkg = JSON.parse(packageJson);
|
|
1435
1274
|
return pkg.name;
|
|
1436
1275
|
} catch (err) {
|
|
@@ -1438,126 +1277,14 @@ var DepsService = class {
|
|
|
1438
1277
|
}
|
|
1439
1278
|
}
|
|
1440
1279
|
async addScriptsToPackageJson(scripts) {
|
|
1441
|
-
const packageJson = JSON.parse(await
|
|
1280
|
+
const packageJson = JSON.parse(await fs4.readFile("package.json", "utf-8"));
|
|
1442
1281
|
packageJson.scripts = {
|
|
1443
1282
|
...packageJson.scripts,
|
|
1444
1283
|
...scripts
|
|
1445
1284
|
};
|
|
1446
|
-
await
|
|
1285
|
+
await fs4.writeFile("package.json", JSON.stringify(packageJson, null, 2));
|
|
1447
1286
|
}
|
|
1448
1287
|
};
|
|
1449
|
-
var args = ["-y", "@mastra/mcp-docs-server"];
|
|
1450
|
-
var createMcpConfig = (editor) => {
|
|
1451
|
-
if (editor === "vscode") {
|
|
1452
|
-
return {
|
|
1453
|
-
servers: {
|
|
1454
|
-
mastra: process.platform === `win32` ? {
|
|
1455
|
-
command: "cmd",
|
|
1456
|
-
args: ["/c", "npx", ...args],
|
|
1457
|
-
type: "stdio"
|
|
1458
|
-
} : {
|
|
1459
|
-
command: "npx",
|
|
1460
|
-
args,
|
|
1461
|
-
type: "stdio"
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
};
|
|
1465
|
-
}
|
|
1466
|
-
return {
|
|
1467
|
-
mcpServers: {
|
|
1468
|
-
mastra: {
|
|
1469
|
-
command: "npx",
|
|
1470
|
-
args
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
};
|
|
1474
|
-
};
|
|
1475
|
-
function makeConfig(original, editor) {
|
|
1476
|
-
if (editor === "vscode") {
|
|
1477
|
-
return {
|
|
1478
|
-
...original,
|
|
1479
|
-
servers: {
|
|
1480
|
-
...original?.servers || {},
|
|
1481
|
-
...createMcpConfig(editor).servers
|
|
1482
|
-
}
|
|
1483
|
-
};
|
|
1484
|
-
}
|
|
1485
|
-
return {
|
|
1486
|
-
...original,
|
|
1487
|
-
mcpServers: {
|
|
1488
|
-
...original?.mcpServers || {},
|
|
1489
|
-
...createMcpConfig(editor).mcpServers
|
|
1490
|
-
}
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
async function writeMergedConfig(configPath, editor) {
|
|
1494
|
-
const configExists = existsSync(configPath);
|
|
1495
|
-
const config = makeConfig(configExists ? await readJSON(configPath) : {}, editor);
|
|
1496
|
-
await ensureFile(configPath);
|
|
1497
|
-
await writeJSON(configPath, config, {
|
|
1498
|
-
spaces: 2
|
|
1499
|
-
});
|
|
1500
|
-
}
|
|
1501
|
-
var windsurfGlobalMCPConfigPath = path3.join(os.homedir(), ".codeium", "windsurf", "mcp_config.json");
|
|
1502
|
-
var cursorGlobalMCPConfigPath = path3.join(os.homedir(), ".cursor", "mcp.json");
|
|
1503
|
-
path3.join(process.cwd(), ".vscode", "mcp.json");
|
|
1504
|
-
var vscodeGlobalMCPConfigPath = path3.join(
|
|
1505
|
-
os.homedir(),
|
|
1506
|
-
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")
|
|
1507
|
-
);
|
|
1508
|
-
async function installMastraDocsMCPServer({ editor, directory }) {
|
|
1509
|
-
if (editor === `cursor`) {
|
|
1510
|
-
await writeMergedConfig(path3.join(directory, ".cursor", "mcp.json"), "cursor");
|
|
1511
|
-
}
|
|
1512
|
-
if (editor === `vscode`) {
|
|
1513
|
-
await writeMergedConfig(path3.join(directory, ".vscode", "mcp.json"), "vscode");
|
|
1514
|
-
}
|
|
1515
|
-
if (editor === `cursor-global`) {
|
|
1516
|
-
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor);
|
|
1517
|
-
if (alreadyInstalled) {
|
|
1518
|
-
return;
|
|
1519
|
-
}
|
|
1520
|
-
await writeMergedConfig(cursorGlobalMCPConfigPath, "cursor-global");
|
|
1521
|
-
}
|
|
1522
|
-
if (editor === `windsurf`) {
|
|
1523
|
-
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor);
|
|
1524
|
-
if (alreadyInstalled) {
|
|
1525
|
-
return;
|
|
1526
|
-
}
|
|
1527
|
-
await writeMergedConfig(windsurfGlobalMCPConfigPath, editor);
|
|
1528
|
-
}
|
|
1529
|
-
}
|
|
1530
|
-
async function globalMCPIsAlreadyInstalled(editor) {
|
|
1531
|
-
let configPath = ``;
|
|
1532
|
-
if (editor === "windsurf") {
|
|
1533
|
-
configPath = windsurfGlobalMCPConfigPath;
|
|
1534
|
-
} else if (editor === "cursor-global") {
|
|
1535
|
-
configPath = cursorGlobalMCPConfigPath;
|
|
1536
|
-
} else if (editor === "vscode") {
|
|
1537
|
-
configPath = vscodeGlobalMCPConfigPath;
|
|
1538
|
-
}
|
|
1539
|
-
if (!configPath || !existsSync(configPath)) {
|
|
1540
|
-
return false;
|
|
1541
|
-
}
|
|
1542
|
-
try {
|
|
1543
|
-
const configContents = await readJSON(configPath);
|
|
1544
|
-
if (!configContents) return false;
|
|
1545
|
-
if (editor === "vscode") {
|
|
1546
|
-
if (!configContents.servers) return false;
|
|
1547
|
-
const hasMastraMCP2 = Object.values(configContents.servers).some(
|
|
1548
|
-
(server) => server?.args?.find((arg) => arg?.includes(`@mastra/mcp-docs-server`))
|
|
1549
|
-
);
|
|
1550
|
-
return hasMastraMCP2;
|
|
1551
|
-
}
|
|
1552
|
-
if (!configContents?.mcpServers) return false;
|
|
1553
|
-
const hasMastraMCP = Object.values(configContents.mcpServers).some(
|
|
1554
|
-
(server) => server?.args?.find((arg) => arg?.includes(`@mastra/mcp-docs-server`))
|
|
1555
|
-
);
|
|
1556
|
-
return hasMastraMCP;
|
|
1557
|
-
} catch {
|
|
1558
|
-
return false;
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
1288
|
var EnvService = class {
|
|
1562
1289
|
};
|
|
1563
1290
|
var FileEnvService = class extends EnvService {
|
|
@@ -1568,7 +1295,7 @@ var FileEnvService = class extends EnvService {
|
|
|
1568
1295
|
}
|
|
1569
1296
|
readFile(filePath) {
|
|
1570
1297
|
return new Promise((resolve, reject) => {
|
|
1571
|
-
|
|
1298
|
+
fs3__default.readFile(filePath, "utf8", (err, data) => {
|
|
1572
1299
|
if (err) reject(err);
|
|
1573
1300
|
else resolve(data);
|
|
1574
1301
|
});
|
|
@@ -1576,7 +1303,7 @@ var FileEnvService = class extends EnvService {
|
|
|
1576
1303
|
}
|
|
1577
1304
|
writeFile({ filePath, data }) {
|
|
1578
1305
|
return new Promise((resolve, reject) => {
|
|
1579
|
-
|
|
1306
|
+
fs3__default.writeFile(filePath, data, "utf8", (err) => {
|
|
1580
1307
|
if (err) reject(err);
|
|
1581
1308
|
else resolve();
|
|
1582
1309
|
});
|
|
@@ -1596,7 +1323,7 @@ var FileEnvService = class extends EnvService {
|
|
|
1596
1323
|
${key}=${value}`;
|
|
1597
1324
|
}
|
|
1598
1325
|
await this.writeFile({ filePath, data });
|
|
1599
|
-
console.
|
|
1326
|
+
console.info(`${key} set to ${value} in ENV file.`);
|
|
1600
1327
|
return data;
|
|
1601
1328
|
}
|
|
1602
1329
|
async getEnvValue(key) {
|
|
@@ -1631,23 +1358,23 @@ var FileService = class {
|
|
|
1631
1358
|
const __filename = fileURLToPath(import.meta.url);
|
|
1632
1359
|
const __dirname = path3.dirname(__filename);
|
|
1633
1360
|
const filePath = path3.resolve(__dirname, "starter-files", inputFile);
|
|
1634
|
-
const fileString =
|
|
1635
|
-
if (
|
|
1636
|
-
console.
|
|
1361
|
+
const fileString = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1362
|
+
if (fs3__default__default.existsSync(outputFilePath) && !replaceIfExists) {
|
|
1363
|
+
console.info(`${outputFilePath} already exists`);
|
|
1637
1364
|
return false;
|
|
1638
1365
|
}
|
|
1639
|
-
await
|
|
1366
|
+
await fsExtra.outputFile(outputFilePath, fileString);
|
|
1640
1367
|
return true;
|
|
1641
1368
|
}
|
|
1642
1369
|
async setupEnvFile({ dbUrl }) {
|
|
1643
1370
|
const envPath = path3.join(process.cwd(), ".env.development");
|
|
1644
|
-
await
|
|
1371
|
+
await fsExtra.ensureFile(envPath);
|
|
1645
1372
|
const fileEnvService = new FileEnvService(envPath);
|
|
1646
1373
|
await fileEnvService.setEnvValue("DB_URL", dbUrl);
|
|
1647
1374
|
}
|
|
1648
1375
|
getFirstExistingFile(files) {
|
|
1649
1376
|
for (const f of files) {
|
|
1650
|
-
if (
|
|
1377
|
+
if (fs3__default__default.existsSync(f)) {
|
|
1651
1378
|
return f;
|
|
1652
1379
|
}
|
|
1653
1380
|
}
|
|
@@ -1657,66 +1384,152 @@ var FileService = class {
|
|
|
1657
1384
|
filePath,
|
|
1658
1385
|
replacements
|
|
1659
1386
|
}) {
|
|
1660
|
-
let fileContent =
|
|
1387
|
+
let fileContent = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1661
1388
|
replacements.forEach(({ search, replace }) => {
|
|
1662
1389
|
fileContent = fileContent.replaceAll(search, replace);
|
|
1663
1390
|
});
|
|
1664
|
-
|
|
1391
|
+
fs3__default__default.writeFileSync(filePath, fileContent);
|
|
1665
1392
|
}
|
|
1666
1393
|
};
|
|
1667
|
-
var
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
case "cerebras":
|
|
1671
|
-
return "^0.2.14";
|
|
1672
|
-
default:
|
|
1673
|
-
return "^1.0.0";
|
|
1674
|
-
}
|
|
1394
|
+
var createArgs = (versionTag) => {
|
|
1395
|
+
const packageName = versionTag ? `@mastra/mcp-docs-server@${versionTag}` : "@mastra/mcp-docs-server";
|
|
1396
|
+
return ["-y", packageName];
|
|
1675
1397
|
};
|
|
1676
|
-
var
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
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
|
+
};
|
|
1692
1414
|
}
|
|
1415
|
+
return {
|
|
1416
|
+
mcpServers: {
|
|
1417
|
+
mastra: {
|
|
1418
|
+
command: "npx",
|
|
1419
|
+
args
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1693
1423
|
};
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
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);
|
|
1516
|
+
var getModelIdentifier = (llmProvider) => {
|
|
1517
|
+
let model = "openai/gpt-4o";
|
|
1518
|
+
if (llmProvider === "anthropic") {
|
|
1519
|
+
model = "anthropic/claude-sonnet-4-5";
|
|
1703
1520
|
} else if (llmProvider === "groq") {
|
|
1704
|
-
|
|
1705
|
-
modelItem = `groq('llama-3.3-70b-versatile')`;
|
|
1521
|
+
model = "groq/llama-3.3-70b-versatile";
|
|
1706
1522
|
} else if (llmProvider === "google") {
|
|
1707
|
-
|
|
1708
|
-
modelItem = `google('gemini-2.5-pro')`;
|
|
1523
|
+
model = "google/gemini-2.5-pro";
|
|
1709
1524
|
} else if (llmProvider === "cerebras") {
|
|
1710
|
-
|
|
1711
|
-
modelItem = `cerebras('llama-3.3-70b')`;
|
|
1525
|
+
model = "cerebras/llama-3.3-70b";
|
|
1712
1526
|
} else if (llmProvider === "mistral") {
|
|
1713
|
-
|
|
1714
|
-
modelItem = `mistral('mistral-medium-2508')`;
|
|
1527
|
+
model = "mistral/mistral-medium-2508";
|
|
1715
1528
|
}
|
|
1716
|
-
return
|
|
1529
|
+
return model;
|
|
1717
1530
|
};
|
|
1718
|
-
async function writeAgentSample(llmProvider, destPath, addExampleTool) {
|
|
1719
|
-
const
|
|
1531
|
+
async function writeAgentSample(llmProvider, destPath, addExampleTool, addScorers) {
|
|
1532
|
+
const modelString = getModelIdentifier(llmProvider);
|
|
1720
1533
|
const instructions = `
|
|
1721
1534
|
You are a helpful weather assistant that provides accurate weather information and can help planning activities based on the weather.
|
|
1722
1535
|
|
|
@@ -1732,19 +1545,44 @@ async function writeAgentSample(llmProvider, destPath, addExampleTool) {
|
|
|
1732
1545
|
${addExampleTool ? "Use the weatherTool to fetch current weather data." : ""}
|
|
1733
1546
|
`;
|
|
1734
1547
|
const content = `
|
|
1735
|
-
${providerImport}
|
|
1736
1548
|
import { Agent } from '@mastra/core/agent';
|
|
1737
1549
|
import { Memory } from '@mastra/memory';
|
|
1738
1550
|
import { LibSQLStore } from '@mastra/libsql';
|
|
1739
1551
|
${addExampleTool ? `import { weatherTool } from '../tools/weather-tool';` : ""}
|
|
1552
|
+
${addScorers ? `import { scorers } from '../scorers/weather-scorer';` : ""}
|
|
1740
1553
|
|
|
1741
1554
|
export const weatherAgent = new Agent({
|
|
1555
|
+
id: 'weather-agent',
|
|
1742
1556
|
name: 'Weather Agent',
|
|
1743
1557
|
instructions: \`${instructions}\`,
|
|
1744
|
-
model: ${
|
|
1558
|
+
model: '${modelString}',
|
|
1745
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
|
+
},` : ""}
|
|
1746
1583
|
memory: new Memory({
|
|
1747
1584
|
storage: new LibSQLStore({
|
|
1585
|
+
id: "memory-storage",
|
|
1748
1586
|
url: "file:../mastra.db", // path is relative to the .mastra/output directory
|
|
1749
1587
|
})
|
|
1750
1588
|
})
|
|
@@ -1754,8 +1592,8 @@ export const weatherAgent = new Agent({
|
|
|
1754
1592
|
parser: "typescript",
|
|
1755
1593
|
singleQuote: true
|
|
1756
1594
|
});
|
|
1757
|
-
await
|
|
1758
|
-
await
|
|
1595
|
+
await fs4.writeFile(destPath, "");
|
|
1596
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1759
1597
|
}
|
|
1760
1598
|
async function writeWorkflowSample(destPath) {
|
|
1761
1599
|
const content = `import { createStep, createWorkflow } from '@mastra/core/workflows';
|
|
@@ -1948,72 +1786,176 @@ export { weatherWorkflow };`;
|
|
|
1948
1786
|
semi: true,
|
|
1949
1787
|
singleQuote: true
|
|
1950
1788
|
});
|
|
1951
|
-
await
|
|
1789
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1952
1790
|
}
|
|
1953
1791
|
async function writeToolSample(destPath) {
|
|
1954
1792
|
const fileService = new FileService();
|
|
1955
1793
|
await fileService.copyStarterFile("tools.ts", destPath);
|
|
1956
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
|
+
}
|
|
1957
1883
|
async function writeCodeSampleForComponents(llmprovider, component, destPath, importComponents) {
|
|
1958
1884
|
switch (component) {
|
|
1959
1885
|
case "agents":
|
|
1960
|
-
return writeAgentSample(
|
|
1886
|
+
return writeAgentSample(
|
|
1887
|
+
llmprovider,
|
|
1888
|
+
destPath,
|
|
1889
|
+
importComponents.includes("tools"),
|
|
1890
|
+
importComponents.includes("scorers")
|
|
1891
|
+
);
|
|
1961
1892
|
case "tools":
|
|
1962
1893
|
return writeToolSample(destPath);
|
|
1963
1894
|
case "workflows":
|
|
1964
1895
|
return writeWorkflowSample(destPath);
|
|
1896
|
+
case "scorers":
|
|
1897
|
+
return writeScorersSample(llmprovider, destPath);
|
|
1965
1898
|
default:
|
|
1966
1899
|
return "";
|
|
1967
1900
|
}
|
|
1968
1901
|
}
|
|
1969
1902
|
var createComponentsDir = async (dirPath, component) => {
|
|
1970
1903
|
const componentPath = dirPath + `/${component}`;
|
|
1971
|
-
await
|
|
1904
|
+
await fsExtra.ensureDir(componentPath);
|
|
1972
1905
|
};
|
|
1973
1906
|
var writeIndexFile = async ({
|
|
1974
1907
|
dirPath,
|
|
1975
1908
|
addAgent,
|
|
1976
1909
|
addExample,
|
|
1977
|
-
addWorkflow
|
|
1910
|
+
addWorkflow,
|
|
1911
|
+
addScorers
|
|
1978
1912
|
}) => {
|
|
1979
1913
|
const indexPath = dirPath + "/index.ts";
|
|
1980
1914
|
const destPath = path3.join(indexPath);
|
|
1981
1915
|
try {
|
|
1982
|
-
await
|
|
1916
|
+
await fs4.writeFile(destPath, "");
|
|
1983
1917
|
const filteredExports = [
|
|
1984
1918
|
addWorkflow ? `workflows: { weatherWorkflow },` : "",
|
|
1985
|
-
addAgent ? `agents: { weatherAgent },` : ""
|
|
1919
|
+
addAgent ? `agents: { weatherAgent },` : "",
|
|
1920
|
+
addScorers ? `scorers: { toolCallAppropriatenessScorer, completenessScorer, translationScorer },` : ""
|
|
1986
1921
|
].filter(Boolean);
|
|
1987
1922
|
if (!addExample) {
|
|
1988
|
-
await
|
|
1923
|
+
await fs4.writeFile(
|
|
1989
1924
|
destPath,
|
|
1990
1925
|
`
|
|
1991
|
-
import { Mastra } from '@mastra/core';
|
|
1926
|
+
import { Mastra } from '@mastra/core/mastra';
|
|
1992
1927
|
|
|
1993
1928
|
export const mastra = new Mastra()
|
|
1994
1929
|
`
|
|
1995
1930
|
);
|
|
1996
1931
|
return;
|
|
1997
1932
|
}
|
|
1998
|
-
await
|
|
1933
|
+
await fs4.writeFile(
|
|
1999
1934
|
destPath,
|
|
2000
1935
|
`
|
|
2001
1936
|
import { Mastra } from '@mastra/core/mastra';
|
|
2002
1937
|
import { PinoLogger } from '@mastra/loggers';
|
|
2003
1938
|
import { LibSQLStore } from '@mastra/libsql';
|
|
1939
|
+
import { Observability } from '@mastra/observability';
|
|
2004
1940
|
${addWorkflow ? `import { weatherWorkflow } from './workflows/weather-workflow';` : ""}
|
|
2005
1941
|
${addAgent ? `import { weatherAgent } from './agents/weather-agent';` : ""}
|
|
1942
|
+
${addScorers ? `import { toolCallAppropriatenessScorer, completenessScorer, translationScorer } from './scorers/weather-scorer';` : ""}
|
|
2006
1943
|
|
|
2007
1944
|
export const mastra = new Mastra({
|
|
2008
1945
|
${filteredExports.join("\n ")}
|
|
2009
1946
|
storage: new LibSQLStore({
|
|
2010
|
-
|
|
1947
|
+
id: "mastra-storage",
|
|
1948
|
+
// stores observability, scores, ... into memory storage, if it needs to persist, change to file:../mastra.db
|
|
2011
1949
|
url: ":memory:",
|
|
2012
1950
|
}),
|
|
2013
1951
|
logger: new PinoLogger({
|
|
2014
1952
|
name: 'Mastra',
|
|
2015
1953
|
level: 'info',
|
|
2016
1954
|
}),
|
|
1955
|
+
observability: new Observability({
|
|
1956
|
+
// Enables DefaultExporter and CloudExporter for tracing
|
|
1957
|
+
default: { enabled: true },
|
|
1958
|
+
}),
|
|
2017
1959
|
});
|
|
2018
1960
|
`
|
|
2019
1961
|
);
|
|
@@ -2021,7 +1963,6 @@ export const mastra = new Mastra({
|
|
|
2021
1963
|
throw err;
|
|
2022
1964
|
}
|
|
2023
1965
|
};
|
|
2024
|
-
yoctoSpinner({ text: "Installing Mastra core dependencies\n" });
|
|
2025
1966
|
var getAPIKey = async (provider) => {
|
|
2026
1967
|
let key = "OPENAI_API_KEY";
|
|
2027
1968
|
switch (provider) {
|
|
@@ -2044,23 +1985,21 @@ var getAPIKey = async (provider) => {
|
|
|
2044
1985
|
return key;
|
|
2045
1986
|
}
|
|
2046
1987
|
};
|
|
2047
|
-
var writeAPIKey = async ({
|
|
2048
|
-
|
|
2049
|
-
apiKey = "your-api-key"
|
|
2050
|
-
}) => {
|
|
1988
|
+
var writeAPIKey = async ({ provider, apiKey }) => {
|
|
1989
|
+
const envFileName = apiKey ? ".env" : ".env.example";
|
|
2051
1990
|
const key = await getAPIKey(provider);
|
|
2052
|
-
const escapedKey =
|
|
2053
|
-
const escapedApiKey =
|
|
2054
|
-
await
|
|
1991
|
+
const escapedKey = shellQuote2.quote([key]);
|
|
1992
|
+
const escapedApiKey = shellQuote2.quote([apiKey ? apiKey : "your-api-key"]);
|
|
1993
|
+
await exec(`echo ${escapedKey}=${escapedApiKey} >> ${envFileName}`);
|
|
2055
1994
|
};
|
|
2056
1995
|
var createMastraDir = async (directory) => {
|
|
2057
1996
|
let dir = directory.trim().split("/").filter((item) => item !== "");
|
|
2058
1997
|
const dirPath = path3.join(process.cwd(), ...dir, "mastra");
|
|
2059
1998
|
try {
|
|
2060
|
-
await
|
|
1999
|
+
await fs4.access(dirPath);
|
|
2061
2000
|
return { ok: false };
|
|
2062
2001
|
} catch {
|
|
2063
|
-
await
|
|
2002
|
+
await fsExtra.ensureDir(dirPath);
|
|
2064
2003
|
return { ok: true, dirPath };
|
|
2065
2004
|
}
|
|
2066
2005
|
};
|
|
@@ -2072,8 +2011,19 @@ var writeCodeSample = async (dirPath, component, llmProvider, importComponents)
|
|
|
2072
2011
|
throw err;
|
|
2073
2012
|
}
|
|
2074
2013
|
};
|
|
2075
|
-
var
|
|
2076
|
-
|
|
2014
|
+
var LLM_PROVIDERS = [
|
|
2015
|
+
{ value: "openai", label: "OpenAI", hint: "recommended" },
|
|
2016
|
+
{ value: "anthropic", label: "Anthropic" },
|
|
2017
|
+
{ value: "groq", label: "Groq" },
|
|
2018
|
+
{ value: "google", label: "Google" },
|
|
2019
|
+
{ value: "cerebras", label: "Cerebras" },
|
|
2020
|
+
{ value: "mistral", label: "Mistral" }
|
|
2021
|
+
];
|
|
2022
|
+
var interactivePrompt = async (args = {}) => {
|
|
2023
|
+
const { skip = {}, options: { showBanner = true } = {} } = args;
|
|
2024
|
+
if (showBanner) {
|
|
2025
|
+
Ie(color2.inverse(" Mastra Init "));
|
|
2026
|
+
}
|
|
2077
2027
|
const mastraProject = await Ce(
|
|
2078
2028
|
{
|
|
2079
2029
|
directory: () => he({
|
|
@@ -2081,20 +2031,15 @@ var interactivePrompt = async () => {
|
|
|
2081
2031
|
placeholder: "src/",
|
|
2082
2032
|
defaultValue: "src/"
|
|
2083
2033
|
}),
|
|
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
|
-
]
|
|
2034
|
+
llmProvider: () => skip?.llmProvider ? void 0 : ve({
|
|
2035
|
+
message: "Select a default provider:",
|
|
2036
|
+
options: LLM_PROVIDERS
|
|
2094
2037
|
}),
|
|
2095
2038
|
llmApiKey: async ({ results: { llmProvider } }) => {
|
|
2039
|
+
if (skip?.llmApiKey) return void 0;
|
|
2040
|
+
const llmName = LLM_PROVIDERS.find((p6) => p6.value === llmProvider)?.label || "provider";
|
|
2096
2041
|
const keyChoice = await ve({
|
|
2097
|
-
message: `Enter your ${
|
|
2042
|
+
message: `Enter your ${llmName} API key?`,
|
|
2098
2043
|
options: [
|
|
2099
2044
|
{ value: "skip", label: "Skip for now", hint: "default" },
|
|
2100
2045
|
{ value: "enter", label: "Enter API key" }
|
|
@@ -2104,52 +2049,38 @@ var interactivePrompt = async () => {
|
|
|
2104
2049
|
if (keyChoice === "enter") {
|
|
2105
2050
|
return he({
|
|
2106
2051
|
message: "Enter your API key:",
|
|
2107
|
-
placeholder: "sk-..."
|
|
2052
|
+
placeholder: "sk-...",
|
|
2053
|
+
validate: (value) => {
|
|
2054
|
+
if (value.length === 0) return "API key cannot be empty";
|
|
2055
|
+
}
|
|
2108
2056
|
});
|
|
2109
2057
|
}
|
|
2110
2058
|
return void 0;
|
|
2111
2059
|
},
|
|
2112
2060
|
configureEditorWithDocsMCP: async () => {
|
|
2113
|
-
const windsurfIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`windsurf`);
|
|
2114
|
-
const cursorIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`cursor`);
|
|
2115
|
-
const vscodeIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`vscode`);
|
|
2116
2061
|
const editor = await ve({
|
|
2117
|
-
message: `Make your
|
|
2062
|
+
message: `Make your IDE into a Mastra expert? (Installs Mastra's MCP server)`,
|
|
2118
2063
|
options: [
|
|
2119
2064
|
{ value: "skip", label: "Skip for now", hint: "default" },
|
|
2120
2065
|
{
|
|
2121
2066
|
value: "cursor",
|
|
2122
|
-
label: "Cursor (project only)"
|
|
2123
|
-
hint: cursorIsAlreadyInstalled ? `Already installed globally` : void 0
|
|
2067
|
+
label: "Cursor (project only)"
|
|
2124
2068
|
},
|
|
2125
2069
|
{
|
|
2126
2070
|
value: "cursor-global",
|
|
2127
|
-
label: "Cursor (global, all projects)"
|
|
2128
|
-
hint: cursorIsAlreadyInstalled ? `Already installed` : void 0
|
|
2071
|
+
label: "Cursor (global, all projects)"
|
|
2129
2072
|
},
|
|
2130
2073
|
{
|
|
2131
2074
|
value: "windsurf",
|
|
2132
|
-
label: "Windsurf"
|
|
2133
|
-
hint: windsurfIsAlreadyInstalled ? `Already installed` : void 0
|
|
2075
|
+
label: "Windsurf"
|
|
2134
2076
|
},
|
|
2135
2077
|
{
|
|
2136
2078
|
value: "vscode",
|
|
2137
|
-
label: "VSCode"
|
|
2138
|
-
hint: vscodeIsAlreadyInstalled ? `Already installed` : void 0
|
|
2079
|
+
label: "VSCode"
|
|
2139
2080
|
}
|
|
2140
2081
|
]
|
|
2141
2082
|
});
|
|
2142
2083
|
if (editor === `skip`) return void 0;
|
|
2143
|
-
if (editor === `windsurf` && windsurfIsAlreadyInstalled) {
|
|
2144
|
-
M.message(`
|
|
2145
|
-
Windsurf is already installed, skipping.`);
|
|
2146
|
-
return void 0;
|
|
2147
|
-
}
|
|
2148
|
-
if (editor === `vscode` && vscodeIsAlreadyInstalled) {
|
|
2149
|
-
M.message(`
|
|
2150
|
-
VSCode is already installed, skipping.`);
|
|
2151
|
-
return void 0;
|
|
2152
|
-
}
|
|
2153
2084
|
if (editor === `cursor`) {
|
|
2154
2085
|
M.message(
|
|
2155
2086
|
`
|
|
@@ -2158,19 +2089,19 @@ Note: you will need to go into Cursor Settings -> MCP Settings and manually enab
|
|
|
2158
2089
|
);
|
|
2159
2090
|
}
|
|
2160
2091
|
if (editor === `cursor-global`) {
|
|
2161
|
-
const
|
|
2092
|
+
const confirm = await ve({
|
|
2162
2093
|
message: `Global install will add/update ${cursorGlobalMCPConfigPath} and make the Mastra docs MCP server available in all your Cursor projects. Continue?`,
|
|
2163
2094
|
options: [
|
|
2164
2095
|
{ value: "yes", label: "Yes, I understand" },
|
|
2165
2096
|
{ value: "skip", label: "No, skip for now" }
|
|
2166
2097
|
]
|
|
2167
2098
|
});
|
|
2168
|
-
if (
|
|
2099
|
+
if (confirm !== `yes`) {
|
|
2169
2100
|
return void 0;
|
|
2170
2101
|
}
|
|
2171
2102
|
}
|
|
2172
2103
|
if (editor === `windsurf`) {
|
|
2173
|
-
const
|
|
2104
|
+
const confirm = await ve({
|
|
2174
2105
|
message: `Windsurf only supports a global MCP config (at ${windsurfGlobalMCPConfigPath}) is it ok to add/update that global config?
|
|
2175
2106
|
This means the Mastra docs MCP server will be available in all your Windsurf projects.`,
|
|
2176
2107
|
options: [
|
|
@@ -2178,7 +2109,7 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2178
2109
|
{ value: "skip", label: "No, skip for now" }
|
|
2179
2110
|
]
|
|
2180
2111
|
});
|
|
2181
|
-
if (
|
|
2112
|
+
if (confirm !== `yes`) {
|
|
2182
2113
|
return void 0;
|
|
2183
2114
|
}
|
|
2184
2115
|
}
|
|
@@ -2194,17 +2125,224 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2194
2125
|
);
|
|
2195
2126
|
return mastraProject;
|
|
2196
2127
|
};
|
|
2128
|
+
function getPackageManager() {
|
|
2129
|
+
const userAgent = process.env.npm_config_user_agent || "";
|
|
2130
|
+
const execPath = process.env.npm_execpath || "";
|
|
2131
|
+
if (userAgent.includes("yarn")) {
|
|
2132
|
+
return "yarn";
|
|
2133
|
+
}
|
|
2134
|
+
if (userAgent.includes("pnpm")) {
|
|
2135
|
+
return "pnpm";
|
|
2136
|
+
}
|
|
2137
|
+
if (userAgent.includes("npm")) {
|
|
2138
|
+
return "npm";
|
|
2139
|
+
}
|
|
2140
|
+
if (execPath.includes("yarn")) {
|
|
2141
|
+
return "yarn";
|
|
2142
|
+
}
|
|
2143
|
+
if (execPath.includes("pnpm")) {
|
|
2144
|
+
return "pnpm";
|
|
2145
|
+
}
|
|
2146
|
+
if (execPath.includes("npm")) {
|
|
2147
|
+
return "npm";
|
|
2148
|
+
}
|
|
2149
|
+
return "npm";
|
|
2150
|
+
}
|
|
2151
|
+
var logger = createLogger(false);
|
|
2152
|
+
function createLogger(debug = false) {
|
|
2153
|
+
return new PinoLogger({
|
|
2154
|
+
name: "Mastra CLI",
|
|
2155
|
+
level: debug ? "debug" : "info"
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
var exec2 = util.promisify(child_process.exec);
|
|
2159
|
+
async function cloneTemplate(options) {
|
|
2160
|
+
const { template, projectName, targetDir, branch, llmProvider } = options;
|
|
2161
|
+
const projectPath = targetDir ? path3.resolve(targetDir, projectName) : path3.resolve(projectName);
|
|
2162
|
+
const spinner4 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
|
|
2163
|
+
try {
|
|
2164
|
+
if (await directoryExists(projectPath)) {
|
|
2165
|
+
spinner4.error(`Directory ${projectName} already exists`);
|
|
2166
|
+
throw new Error(`Directory ${projectName} already exists`);
|
|
2167
|
+
}
|
|
2168
|
+
await cloneRepositoryWithoutGit(template.githubUrl, projectPath, branch);
|
|
2169
|
+
await updatePackageJson(projectPath, projectName);
|
|
2170
|
+
const envExamplePath = path3.join(projectPath, ".env.example");
|
|
2171
|
+
if (await fileExists(envExamplePath)) {
|
|
2172
|
+
const envPath = path3.join(projectPath, ".env");
|
|
2173
|
+
await fs4.copyFile(envExamplePath, envPath);
|
|
2174
|
+
if (llmProvider) {
|
|
2175
|
+
await updateEnvFile(envPath, llmProvider);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
spinner4.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
2179
|
+
return projectPath;
|
|
2180
|
+
} catch (error) {
|
|
2181
|
+
spinner4.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2182
|
+
throw error;
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
async function directoryExists(dirPath) {
|
|
2186
|
+
try {
|
|
2187
|
+
const stat = await fs4.stat(dirPath);
|
|
2188
|
+
return stat.isDirectory();
|
|
2189
|
+
} catch {
|
|
2190
|
+
return false;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
async function fileExists(filePath) {
|
|
2194
|
+
try {
|
|
2195
|
+
const stat = await fs4.stat(filePath);
|
|
2196
|
+
return stat.isFile();
|
|
2197
|
+
} catch {
|
|
2198
|
+
return false;
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
async function cloneRepositoryWithoutGit(repoUrl, targetPath, branch) {
|
|
2202
|
+
await fs4.mkdir(targetPath, { recursive: true });
|
|
2203
|
+
try {
|
|
2204
|
+
const degitRepo = repoUrl.replace("https://github.com/", "");
|
|
2205
|
+
const degitRepoWithBranch = branch ? `${degitRepo}#${branch}` : degitRepo;
|
|
2206
|
+
const degitCommand = shellQuote2.quote(["npx", "degit", degitRepoWithBranch, targetPath]);
|
|
2207
|
+
await exec2(degitCommand, {
|
|
2208
|
+
cwd: process.cwd()
|
|
2209
|
+
});
|
|
2210
|
+
} catch {
|
|
2211
|
+
try {
|
|
2212
|
+
const gitArgs = ["git", "clone"];
|
|
2213
|
+
if (branch) {
|
|
2214
|
+
gitArgs.push("--branch", branch);
|
|
2215
|
+
}
|
|
2216
|
+
gitArgs.push(repoUrl, targetPath);
|
|
2217
|
+
const gitCommand = shellQuote2.quote(gitArgs);
|
|
2218
|
+
await exec2(gitCommand, {
|
|
2219
|
+
cwd: process.cwd()
|
|
2220
|
+
});
|
|
2221
|
+
const gitDir = path3.join(targetPath, ".git");
|
|
2222
|
+
if (await directoryExists(gitDir)) {
|
|
2223
|
+
await fs4.rm(gitDir, { recursive: true, force: true });
|
|
2224
|
+
}
|
|
2225
|
+
} catch (gitError) {
|
|
2226
|
+
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
async function updatePackageJson(projectPath, projectName) {
|
|
2231
|
+
const packageJsonPath = path3.join(projectPath, "package.json");
|
|
2232
|
+
try {
|
|
2233
|
+
const packageJsonContent = await fs4.readFile(packageJsonPath, "utf-8");
|
|
2234
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
2235
|
+
packageJson.name = projectName;
|
|
2236
|
+
await fs4.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
2237
|
+
} catch (error) {
|
|
2238
|
+
logger.warn(`Could not update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
async function updateEnvFile(envPath, llmProvider) {
|
|
2242
|
+
try {
|
|
2243
|
+
const envContent = await fs4.readFile(envPath, "utf-8");
|
|
2244
|
+
const modelString = getModelIdentifier(llmProvider);
|
|
2245
|
+
if (!modelString) {
|
|
2246
|
+
logger.warn(`Could not get model identifier for provider: ${llmProvider}`);
|
|
2247
|
+
return;
|
|
2248
|
+
}
|
|
2249
|
+
const modelValue = modelString.replace(/'/g, "");
|
|
2250
|
+
const updatedContent = envContent.replace(/^MODEL=.*/m, `MODEL=${modelValue}`);
|
|
2251
|
+
await fs4.writeFile(envPath, updatedContent, "utf-8");
|
|
2252
|
+
logger.info(`Updated MODEL in .env to ${modelValue}`);
|
|
2253
|
+
} catch (error) {
|
|
2254
|
+
logger.warn(`Could not update .env file: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
async function installDependencies(projectPath, packageManager) {
|
|
2258
|
+
const spinner4 = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
2259
|
+
try {
|
|
2260
|
+
const pm = packageManager || getPackageManager();
|
|
2261
|
+
const installCommand = shellQuote2.quote([pm, "install"]);
|
|
2262
|
+
await exec2(installCommand, {
|
|
2263
|
+
cwd: projectPath
|
|
2264
|
+
});
|
|
2265
|
+
spinner4.success("Dependencies installed successfully");
|
|
2266
|
+
} catch (error) {
|
|
2267
|
+
spinner4.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2268
|
+
throw error;
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
|
|
2272
|
+
async function loadTemplates() {
|
|
2273
|
+
try {
|
|
2274
|
+
const response = await fetch(TEMPLATES_API_URL);
|
|
2275
|
+
if (!response.ok) {
|
|
2276
|
+
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
2277
|
+
}
|
|
2278
|
+
const templates = await response.json();
|
|
2279
|
+
return templates;
|
|
2280
|
+
} catch (error) {
|
|
2281
|
+
console.error("Error loading templates:", error);
|
|
2282
|
+
throw new Error("Failed to load templates. Please check your internet connection and try again.");
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
function pluralize(count, singular, plural) {
|
|
2286
|
+
return count === 1 ? singular : plural || `${singular}s`;
|
|
2287
|
+
}
|
|
2288
|
+
async function selectTemplate(templates) {
|
|
2289
|
+
const choices = templates.map((template) => {
|
|
2290
|
+
const parts = [];
|
|
2291
|
+
if (template.agents?.length) {
|
|
2292
|
+
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
|
|
2293
|
+
}
|
|
2294
|
+
if (template.tools?.length) {
|
|
2295
|
+
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
|
|
2296
|
+
}
|
|
2297
|
+
if (template.workflows?.length) {
|
|
2298
|
+
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
|
|
2299
|
+
}
|
|
2300
|
+
if (template.mcp?.length) {
|
|
2301
|
+
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
|
|
2302
|
+
}
|
|
2303
|
+
if (template.networks?.length) {
|
|
2304
|
+
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
|
|
2305
|
+
}
|
|
2306
|
+
return {
|
|
2307
|
+
value: template,
|
|
2308
|
+
label: template.title,
|
|
2309
|
+
hint: parts.join(", ") || "Template components"
|
|
2310
|
+
};
|
|
2311
|
+
});
|
|
2312
|
+
const selected = await ve({
|
|
2313
|
+
message: "Select a template:",
|
|
2314
|
+
options: choices
|
|
2315
|
+
});
|
|
2316
|
+
if (pD(selected)) {
|
|
2317
|
+
return null;
|
|
2318
|
+
}
|
|
2319
|
+
return selected;
|
|
2320
|
+
}
|
|
2321
|
+
function findTemplateByName(templates, templateName) {
|
|
2322
|
+
let template = templates.find((t) => t.slug === templateName);
|
|
2323
|
+
if (template) return template;
|
|
2324
|
+
const slugWithPrefix = `template-${templateName}`;
|
|
2325
|
+
template = templates.find((t) => t.slug === slugWithPrefix);
|
|
2326
|
+
if (template) return template;
|
|
2327
|
+
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
|
|
2328
|
+
if (template) return template;
|
|
2329
|
+
return null;
|
|
2330
|
+
}
|
|
2331
|
+
function getDefaultProjectName(template) {
|
|
2332
|
+
return template.slug.replace(/^template-/, "");
|
|
2333
|
+
}
|
|
2197
2334
|
var s = Y();
|
|
2198
|
-
var exec3 = util.promisify(child_process.exec);
|
|
2199
2335
|
var init = async ({
|
|
2200
|
-
directory,
|
|
2201
|
-
addExample = false,
|
|
2336
|
+
directory = "src/",
|
|
2202
2337
|
components,
|
|
2203
2338
|
llmProvider = "openai",
|
|
2204
2339
|
llmApiKey,
|
|
2205
|
-
|
|
2340
|
+
addExample = false,
|
|
2341
|
+
configureEditorWithDocsMCP,
|
|
2342
|
+
versionTag
|
|
2206
2343
|
}) => {
|
|
2207
2344
|
s.start("Initializing Mastra");
|
|
2345
|
+
const packageVersionTag = versionTag ? `@${versionTag}` : "";
|
|
2208
2346
|
try {
|
|
2209
2347
|
const result = await createMastraDir(directory);
|
|
2210
2348
|
if (!result.ok) {
|
|
@@ -2217,7 +2355,8 @@ var init = async ({
|
|
|
2217
2355
|
dirPath,
|
|
2218
2356
|
addExample,
|
|
2219
2357
|
addWorkflow: components.includes("workflows"),
|
|
2220
|
-
addAgent: components.includes("agents")
|
|
2358
|
+
addAgent: components.includes("agents"),
|
|
2359
|
+
addScorers: components.includes("scorers")
|
|
2221
2360
|
}),
|
|
2222
2361
|
...components.map((component) => createComponentsDir(dirPath, component)),
|
|
2223
2362
|
writeAPIKey({ provider: llmProvider, apiKey: llmApiKey })
|
|
@@ -2231,28 +2370,31 @@ var init = async ({
|
|
|
2231
2370
|
const depService = new DepsService();
|
|
2232
2371
|
const needsLibsql = await depService.checkDependencies(["@mastra/libsql"]) !== `ok`;
|
|
2233
2372
|
if (needsLibsql) {
|
|
2234
|
-
await depService.installPackages([
|
|
2373
|
+
await depService.installPackages([`@mastra/libsql${packageVersionTag}`]);
|
|
2235
2374
|
}
|
|
2236
2375
|
const needsMemory = components.includes(`agents`) && await depService.checkDependencies(["@mastra/memory"]) !== `ok`;
|
|
2237
2376
|
if (needsMemory) {
|
|
2238
|
-
await depService.installPackages([
|
|
2377
|
+
await depService.installPackages([`@mastra/memory${packageVersionTag}`]);
|
|
2239
2378
|
}
|
|
2240
2379
|
const needsLoggers = await depService.checkDependencies(["@mastra/loggers"]) !== `ok`;
|
|
2241
2380
|
if (needsLoggers) {
|
|
2242
|
-
await depService.installPackages([
|
|
2381
|
+
await depService.installPackages([`@mastra/loggers${packageVersionTag}`]);
|
|
2382
|
+
}
|
|
2383
|
+
const needsObservability = await depService.checkDependencies(["@mastra/observability"]) !== `ok`;
|
|
2384
|
+
if (needsObservability) {
|
|
2385
|
+
await depService.installPackages([`@mastra/observability${packageVersionTag}`]);
|
|
2386
|
+
}
|
|
2387
|
+
const needsEvals = components.includes(`scorers`) && await depService.checkDependencies(["@mastra/evals"]) !== `ok`;
|
|
2388
|
+
if (needsEvals) {
|
|
2389
|
+
await depService.installPackages([`@mastra/evals${packageVersionTag}`]);
|
|
2243
2390
|
}
|
|
2244
2391
|
}
|
|
2245
2392
|
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
2393
|
if (configureEditorWithDocsMCP) {
|
|
2253
2394
|
await installMastraDocsMCPServer({
|
|
2254
2395
|
editor: configureEditorWithDocsMCP,
|
|
2255
|
-
directory: process.cwd()
|
|
2396
|
+
directory: process.cwd(),
|
|
2397
|
+
versionTag
|
|
2256
2398
|
});
|
|
2257
2399
|
}
|
|
2258
2400
|
s.stop();
|
|
@@ -2275,10 +2417,10 @@ var init = async ({
|
|
|
2275
2417
|
return { success: false };
|
|
2276
2418
|
}
|
|
2277
2419
|
};
|
|
2278
|
-
var
|
|
2420
|
+
var exec3 = util.promisify(child_process.exec);
|
|
2279
2421
|
var execWithTimeout = async (command, timeoutMs) => {
|
|
2280
2422
|
try {
|
|
2281
|
-
const promise =
|
|
2423
|
+
const promise = exec3(command, { killSignal: "SIGTERM" });
|
|
2282
2424
|
if (!timeoutMs) {
|
|
2283
2425
|
return await promise;
|
|
2284
2426
|
}
|
|
@@ -2326,23 +2468,39 @@ async function installMastraDependency(pm, dependency, versionTag, isDev, timeou
|
|
|
2326
2468
|
var createMastraProject = async ({
|
|
2327
2469
|
projectName: name,
|
|
2328
2470
|
createVersionTag,
|
|
2329
|
-
timeout
|
|
2471
|
+
timeout,
|
|
2472
|
+
llmProvider,
|
|
2473
|
+
llmApiKey,
|
|
2474
|
+
needsInteractive
|
|
2330
2475
|
}) => {
|
|
2331
2476
|
Ie(color2.inverse(" Mastra Create "));
|
|
2332
2477
|
const projectName = name ?? await he({
|
|
2333
2478
|
message: "What do you want to name your project?",
|
|
2334
2479
|
placeholder: "my-mastra-app",
|
|
2335
|
-
defaultValue: "my-mastra-app"
|
|
2480
|
+
defaultValue: "my-mastra-app",
|
|
2481
|
+
validate: (value) => {
|
|
2482
|
+
if (value.length === 0) return "Project name cannot be empty";
|
|
2483
|
+
if (fs3__default__default.existsSync(value)) {
|
|
2484
|
+
return `A directory named "${value}" already exists. Please choose a different name.`;
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2336
2487
|
});
|
|
2337
2488
|
if (pD(projectName)) {
|
|
2338
2489
|
xe("Operation cancelled");
|
|
2339
2490
|
process.exit(0);
|
|
2340
2491
|
}
|
|
2492
|
+
let result;
|
|
2493
|
+
if (needsInteractive) {
|
|
2494
|
+
result = await interactivePrompt({
|
|
2495
|
+
options: { showBanner: false },
|
|
2496
|
+
skip: { llmProvider: llmProvider !== void 0, llmApiKey: llmApiKey !== void 0 }
|
|
2497
|
+
});
|
|
2498
|
+
}
|
|
2341
2499
|
const s2 = Y();
|
|
2342
2500
|
try {
|
|
2343
2501
|
s2.start("Creating project");
|
|
2344
2502
|
try {
|
|
2345
|
-
await
|
|
2503
|
+
await fs4.mkdir(projectName);
|
|
2346
2504
|
} catch (error) {
|
|
2347
2505
|
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
2348
2506
|
s2.stop(`A directory named "${projectName}" already exists. Please choose a different name.`);
|
|
@@ -2357,9 +2515,9 @@ var createMastraProject = async ({
|
|
|
2357
2515
|
const installCommand = getPackageManagerAddCommand(pm);
|
|
2358
2516
|
s2.message("Initializing project structure");
|
|
2359
2517
|
try {
|
|
2360
|
-
await
|
|
2361
|
-
await
|
|
2362
|
-
await
|
|
2518
|
+
await exec3(`npm init -y`);
|
|
2519
|
+
await exec3(`npm pkg set type="module"`);
|
|
2520
|
+
await exec3(`npm pkg set engines.node=">=20.9.0"`);
|
|
2363
2521
|
const depsService = new DepsService();
|
|
2364
2522
|
await depsService.addScriptsToPackageJson({
|
|
2365
2523
|
dev: "mastra dev",
|
|
@@ -2374,9 +2532,9 @@ var createMastraProject = async ({
|
|
|
2374
2532
|
s2.stop("Project structure created");
|
|
2375
2533
|
s2.start(`Installing ${pm} dependencies`);
|
|
2376
2534
|
try {
|
|
2377
|
-
await
|
|
2378
|
-
await
|
|
2379
|
-
await
|
|
2535
|
+
await exec3(`${pm} ${installCommand} zod@^4`);
|
|
2536
|
+
await exec3(`${pm} ${installCommand} -D typescript @types/node`);
|
|
2537
|
+
await exec3(`echo '{
|
|
2380
2538
|
"compilerOptions": {
|
|
2381
2539
|
"target": "ES2022",
|
|
2382
2540
|
"module": "ES2022",
|
|
@@ -2398,15 +2556,15 @@ var createMastraProject = async ({
|
|
|
2398
2556
|
);
|
|
2399
2557
|
}
|
|
2400
2558
|
s2.stop(`${pm} dependencies installed`);
|
|
2401
|
-
s2.start("Installing
|
|
2559
|
+
s2.start("Installing Mastra CLI");
|
|
2402
2560
|
const versionTag = createVersionTag ? `@${createVersionTag}` : "@latest";
|
|
2403
2561
|
try {
|
|
2404
2562
|
await installMastraDependency(pm, "mastra", versionTag, true, timeout);
|
|
2405
2563
|
} catch (error) {
|
|
2406
2564
|
throw new Error(`Failed to install Mastra CLI: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2407
2565
|
}
|
|
2408
|
-
s2.stop("
|
|
2409
|
-
s2.start("Installing dependencies");
|
|
2566
|
+
s2.stop("Mastra CLI installed");
|
|
2567
|
+
s2.start("Installing Mastra dependencies");
|
|
2410
2568
|
try {
|
|
2411
2569
|
await installMastraDependency(pm, "@mastra/core", versionTag, false, timeout);
|
|
2412
2570
|
await installMastraDependency(pm, "@mastra/libsql", versionTag, false, timeout);
|
|
@@ -2419,21 +2577,21 @@ var createMastraProject = async ({
|
|
|
2419
2577
|
s2.stop("Mastra dependencies installed");
|
|
2420
2578
|
s2.start("Adding .gitignore");
|
|
2421
2579
|
try {
|
|
2422
|
-
await
|
|
2423
|
-
await
|
|
2424
|
-
await
|
|
2425
|
-
await
|
|
2426
|
-
await
|
|
2427
|
-
await
|
|
2428
|
-
await
|
|
2429
|
-
await
|
|
2580
|
+
await exec3(`echo output.txt >> .gitignore`);
|
|
2581
|
+
await exec3(`echo node_modules >> .gitignore`);
|
|
2582
|
+
await exec3(`echo dist >> .gitignore`);
|
|
2583
|
+
await exec3(`echo .mastra >> .gitignore`);
|
|
2584
|
+
await exec3(`echo .env.development >> .gitignore`);
|
|
2585
|
+
await exec3(`echo .env >> .gitignore`);
|
|
2586
|
+
await exec3(`echo *.db >> .gitignore`);
|
|
2587
|
+
await exec3(`echo *.db-* >> .gitignore`);
|
|
2430
2588
|
} catch (error) {
|
|
2431
2589
|
throw new Error(`Failed to create .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2432
2590
|
}
|
|
2433
2591
|
s2.stop(".gitignore added");
|
|
2434
2592
|
Se("Project created successfully");
|
|
2435
|
-
console.
|
|
2436
|
-
return { projectName };
|
|
2593
|
+
console.info("");
|
|
2594
|
+
return { projectName, result };
|
|
2437
2595
|
} catch (error) {
|
|
2438
2596
|
s2.stop();
|
|
2439
2597
|
const errorMessage = error instanceof Error ? error.message : "An unexpected error occurred";
|
|
@@ -2441,36 +2599,48 @@ var createMastraProject = async ({
|
|
|
2441
2599
|
process.exit(1);
|
|
2442
2600
|
}
|
|
2443
2601
|
};
|
|
2444
|
-
var
|
|
2445
|
-
|
|
2446
|
-
|
|
2602
|
+
var version$1 = package_default.version;
|
|
2603
|
+
var create = async (args) => {
|
|
2604
|
+
if (args.template !== void 0) {
|
|
2605
|
+
await createFromTemplate({
|
|
2606
|
+
projectName: args.projectName,
|
|
2607
|
+
template: args.template,
|
|
2608
|
+
timeout: args.timeout,
|
|
2609
|
+
injectedAnalytics: args.analytics,
|
|
2610
|
+
llmProvider: args.llmProvider
|
|
2611
|
+
});
|
|
2447
2612
|
return;
|
|
2448
2613
|
}
|
|
2449
|
-
const
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2614
|
+
const needsInteractive = args.components === void 0 || args.llmProvider === void 0 || args.addExample === void 0;
|
|
2615
|
+
const { projectName, result } = await createMastraProject({
|
|
2616
|
+
projectName: args?.projectName,
|
|
2617
|
+
createVersionTag: args?.createVersionTag,
|
|
2618
|
+
timeout: args?.timeout,
|
|
2619
|
+
llmProvider: args?.llmProvider,
|
|
2620
|
+
llmApiKey: args?.llmApiKey,
|
|
2621
|
+
needsInteractive
|
|
2453
2622
|
});
|
|
2454
|
-
const directory =
|
|
2455
|
-
if (
|
|
2456
|
-
const result = await interactivePrompt();
|
|
2623
|
+
const directory = args.directory || "src/";
|
|
2624
|
+
if (needsInteractive && result) {
|
|
2457
2625
|
await init({
|
|
2458
2626
|
...result,
|
|
2459
2627
|
llmApiKey: result?.llmApiKey,
|
|
2460
|
-
components: ["agents", "tools", "workflows"],
|
|
2461
|
-
addExample: true
|
|
2628
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2629
|
+
addExample: true,
|
|
2630
|
+
versionTag: args.createVersionTag
|
|
2462
2631
|
});
|
|
2463
2632
|
postCreate({ projectName });
|
|
2464
2633
|
return;
|
|
2465
2634
|
}
|
|
2466
|
-
const { components = [], llmProvider = "openai", addExample = false, llmApiKey } =
|
|
2635
|
+
const { components = [], llmProvider = "openai", addExample = false, llmApiKey } = args;
|
|
2467
2636
|
await init({
|
|
2468
2637
|
directory,
|
|
2469
2638
|
components,
|
|
2470
2639
|
llmProvider,
|
|
2471
2640
|
addExample,
|
|
2472
2641
|
llmApiKey,
|
|
2473
|
-
configureEditorWithDocsMCP:
|
|
2642
|
+
configureEditorWithDocsMCP: args.mcpServer,
|
|
2643
|
+
versionTag: args.createVersionTag
|
|
2474
2644
|
});
|
|
2475
2645
|
postCreate({ projectName });
|
|
2476
2646
|
};
|
|
@@ -2561,9 +2731,9 @@ async function createFromGitHubUrl(url) {
|
|
|
2561
2731
|
workflows: []
|
|
2562
2732
|
};
|
|
2563
2733
|
}
|
|
2564
|
-
async function createFromTemplate(
|
|
2734
|
+
async function createFromTemplate(args) {
|
|
2565
2735
|
let selectedTemplate;
|
|
2566
|
-
if (
|
|
2736
|
+
if (args.template === true) {
|
|
2567
2737
|
const templates = await loadTemplates();
|
|
2568
2738
|
const selected = await selectTemplate(templates);
|
|
2569
2739
|
if (!selected) {
|
|
@@ -2571,26 +2741,26 @@ async function createFromTemplate(args2) {
|
|
|
2571
2741
|
return;
|
|
2572
2742
|
}
|
|
2573
2743
|
selectedTemplate = selected;
|
|
2574
|
-
} else if (
|
|
2575
|
-
if (isGitHubUrl(
|
|
2576
|
-
const
|
|
2577
|
-
|
|
2578
|
-
const validation = await validateGitHubProject(
|
|
2744
|
+
} else if (args.template && typeof args.template === "string") {
|
|
2745
|
+
if (isGitHubUrl(args.template)) {
|
|
2746
|
+
const spinner4 = Y();
|
|
2747
|
+
spinner4.start("Validating GitHub repository...");
|
|
2748
|
+
const validation = await validateGitHubProject(args.template);
|
|
2579
2749
|
if (!validation.isValid) {
|
|
2580
|
-
|
|
2750
|
+
spinner4.stop("Validation failed");
|
|
2581
2751
|
M.error("This does not appear to be a valid Mastra project:");
|
|
2582
2752
|
validation.errors.forEach((error) => M.error(` - ${error}`));
|
|
2583
2753
|
throw new Error("Invalid Mastra project");
|
|
2584
2754
|
}
|
|
2585
|
-
|
|
2586
|
-
selectedTemplate = await createFromGitHubUrl(
|
|
2755
|
+
spinner4.stop("Valid Mastra project \u2713");
|
|
2756
|
+
selectedTemplate = await createFromGitHubUrl(args.template);
|
|
2587
2757
|
} else {
|
|
2588
2758
|
const templates = await loadTemplates();
|
|
2589
|
-
const found = findTemplateByName(templates,
|
|
2759
|
+
const found = findTemplateByName(templates, args.template);
|
|
2590
2760
|
if (!found) {
|
|
2591
|
-
M.error(`Template "${
|
|
2761
|
+
M.error(`Template "${args.template}" not found. Available templates:`);
|
|
2592
2762
|
templates.forEach((t) => M.info(` - ${t.title} (use: ${t.slug.replace("template-", "")})`));
|
|
2593
|
-
throw new Error(`Template "${
|
|
2763
|
+
throw new Error(`Template "${args.template}" not found`);
|
|
2594
2764
|
}
|
|
2595
2765
|
selectedTemplate = found;
|
|
2596
2766
|
}
|
|
@@ -2598,7 +2768,7 @@ async function createFromTemplate(args2) {
|
|
|
2598
2768
|
if (!selectedTemplate) {
|
|
2599
2769
|
throw new Error("No template selected");
|
|
2600
2770
|
}
|
|
2601
|
-
let projectName =
|
|
2771
|
+
let projectName = args.projectName;
|
|
2602
2772
|
if (!projectName) {
|
|
2603
2773
|
const defaultName = getDefaultProjectName(selectedTemplate);
|
|
2604
2774
|
const response = await he({
|
|
@@ -2612,17 +2782,40 @@ async function createFromTemplate(args2) {
|
|
|
2612
2782
|
}
|
|
2613
2783
|
projectName = response;
|
|
2614
2784
|
}
|
|
2785
|
+
let llmProvider = args.llmProvider;
|
|
2786
|
+
if (!llmProvider) {
|
|
2787
|
+
const providerResponse = await ve({
|
|
2788
|
+
message: "Select a default provider:",
|
|
2789
|
+
options: LLM_PROVIDERS
|
|
2790
|
+
});
|
|
2791
|
+
if (pD(providerResponse)) {
|
|
2792
|
+
M.info("Project creation cancelled.");
|
|
2793
|
+
return;
|
|
2794
|
+
}
|
|
2795
|
+
llmProvider = providerResponse;
|
|
2796
|
+
}
|
|
2615
2797
|
try {
|
|
2616
|
-
const analytics =
|
|
2798
|
+
const analytics = args.injectedAnalytics || getAnalytics();
|
|
2617
2799
|
if (analytics) {
|
|
2618
2800
|
analytics.trackEvent("cli_template_used", {
|
|
2619
2801
|
template_slug: selectedTemplate.slug,
|
|
2620
2802
|
template_title: selectedTemplate.title
|
|
2621
2803
|
});
|
|
2804
|
+
if (llmProvider) {
|
|
2805
|
+
analytics.trackEvent("cli_model_provider_selected", {
|
|
2806
|
+
provider: llmProvider,
|
|
2807
|
+
selection_method: args.llmProvider ? "cli_args" : "interactive"
|
|
2808
|
+
});
|
|
2809
|
+
}
|
|
2622
2810
|
}
|
|
2811
|
+
const isBeta = version$1?.includes("beta") ?? false;
|
|
2812
|
+
const isMastraTemplate = selectedTemplate.githubUrl.includes("github.com/mastra-ai/");
|
|
2813
|
+
const branch = isBeta && isMastraTemplate ? "beta" : void 0;
|
|
2623
2814
|
const projectPath = await cloneTemplate({
|
|
2624
2815
|
template: selectedTemplate,
|
|
2625
|
-
projectName
|
|
2816
|
+
projectName,
|
|
2817
|
+
branch,
|
|
2818
|
+
llmProvider
|
|
2626
2819
|
});
|
|
2627
2820
|
await installDependencies(projectPath);
|
|
2628
2821
|
Me(`
|
|
@@ -2642,13 +2835,13 @@ async function getPackageVersion() {
|
|
|
2642
2835
|
const __filename = fileURLToPath(import.meta.url);
|
|
2643
2836
|
const __dirname = dirname(__filename);
|
|
2644
2837
|
const pkgJsonPath = path3.join(__dirname, "..", "package.json");
|
|
2645
|
-
const content = await fsExtra.readJSON(pkgJsonPath);
|
|
2838
|
+
const content = await fsExtra$1.readJSON(pkgJsonPath);
|
|
2646
2839
|
return content.version;
|
|
2647
2840
|
}
|
|
2648
2841
|
async function getCreateVersionTag() {
|
|
2649
2842
|
try {
|
|
2650
2843
|
const pkgPath = fileURLToPath(import.meta.resolve("create-mastra/package.json"));
|
|
2651
|
-
const json = await fsExtra.readJSON(pkgPath);
|
|
2844
|
+
const json = await fsExtra$1.readJSON(pkgPath);
|
|
2652
2845
|
const { stdout } = await execa("npm", ["dist-tag", "create-mastra"]);
|
|
2653
2846
|
const tagLine = stdout.split("\n").find((distLine) => distLine.endsWith(`: ${json.version}`));
|
|
2654
2847
|
const tag = tagLine ? tagLine.split(":")[0].trim() : "latest";
|
|
@@ -2672,14 +2865,14 @@ program.version(`${version}`, "-v, --version").description(`create-mastra ${vers
|
|
|
2672
2865
|
analytics.trackCommand({
|
|
2673
2866
|
command: "version"
|
|
2674
2867
|
});
|
|
2675
|
-
console.
|
|
2868
|
+
console.info(`create-mastra ${version}`);
|
|
2676
2869
|
} catch {
|
|
2677
2870
|
}
|
|
2678
2871
|
});
|
|
2679
2872
|
program.name("create-mastra").description("Create a new Mastra project").argument("[project-name]", "Directory name of the project").option(
|
|
2680
2873
|
"-p, --project-name <string>",
|
|
2681
2874
|
"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(
|
|
2875
|
+
).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
2876
|
"--template [template-name]",
|
|
2684
2877
|
"Create project from a template (use template name, public GitHub URL, or leave blank to select from list)"
|
|
2685
2878
|
).action(async (projectNameArg, args) => {
|
|
@@ -2687,7 +2880,7 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2687
2880
|
const timeout = args?.timeout ? args?.timeout === true ? 6e4 : parseInt(args?.timeout, 10) : void 0;
|
|
2688
2881
|
if (args.default) {
|
|
2689
2882
|
await create({
|
|
2690
|
-
components: ["agents", "tools", "workflows"],
|
|
2883
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2691
2884
|
llmProvider: "openai",
|
|
2692
2885
|
addExample: true,
|
|
2693
2886
|
createVersionTag,
|
|
@@ -2703,7 +2896,7 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2703
2896
|
components: args.components ? args.components.split(",") : [],
|
|
2704
2897
|
llmProvider: args.llm,
|
|
2705
2898
|
addExample: args.example,
|
|
2706
|
-
llmApiKey: args
|
|
2899
|
+
llmApiKey: args.llmApiKey,
|
|
2707
2900
|
createVersionTag,
|
|
2708
2901
|
timeout,
|
|
2709
2902
|
projectName,
|