create-mastra 0.0.0-toolOptionTypes-20250917085558 → 0.0.0-trace-timeline-update-20251121092347
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 +427 -1
- package/README.md +10 -32
- package/dist/index.js +788 -540
- 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 +13 -13
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)
|
|
@@ -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 fs5.copyFile(envExamplePath, path3.join(projectPath, ".env"));
|
|
1218
|
-
}
|
|
1219
|
-
spinner5.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
1220
|
-
return projectPath;
|
|
1221
|
-
} catch (error) {
|
|
1222
|
-
spinner5.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1223
|
-
throw error;
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
async function directoryExists(dirPath) {
|
|
1227
|
-
try {
|
|
1228
|
-
const stat = await fs5.stat(dirPath);
|
|
1229
|
-
return stat.isDirectory();
|
|
1230
|
-
} catch {
|
|
1231
|
-
return false;
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
async function fileExists(filePath) {
|
|
1235
|
-
try {
|
|
1236
|
-
const stat = await fs5.stat(filePath);
|
|
1237
|
-
return stat.isFile();
|
|
1238
|
-
} catch {
|
|
1239
|
-
return false;
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
async function cloneRepositoryWithoutGit(repoUrl, targetPath) {
|
|
1243
|
-
await fs5.mkdir(targetPath, { recursive: true });
|
|
1244
|
-
try {
|
|
1245
|
-
const degitRepo = repoUrl.replace("https://github.com/", "");
|
|
1246
|
-
const degitCommand = shellQuote.quote(["npx", "degit", degitRepo, targetPath]);
|
|
1247
|
-
await exec(degitCommand, {
|
|
1248
|
-
cwd: process.cwd()
|
|
1249
|
-
});
|
|
1250
|
-
} catch {
|
|
1251
|
-
try {
|
|
1252
|
-
const gitCommand = shellQuote.quote(["git", "clone", repoUrl, targetPath]);
|
|
1253
|
-
await exec(gitCommand, {
|
|
1254
|
-
cwd: process.cwd()
|
|
1255
|
-
});
|
|
1256
|
-
const gitDir = path3.join(targetPath, ".git");
|
|
1257
|
-
if (await directoryExists(gitDir)) {
|
|
1258
|
-
await fs5.rm(gitDir, { recursive: true, force: true });
|
|
1259
|
-
}
|
|
1260
|
-
} catch (gitError) {
|
|
1261
|
-
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
async function updatePackageJson(projectPath, projectName) {
|
|
1266
|
-
const packageJsonPath = path3.join(projectPath, "package.json");
|
|
1267
|
-
try {
|
|
1268
|
-
const packageJsonContent = await fs5.readFile(packageJsonPath, "utf-8");
|
|
1269
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
1270
|
-
packageJson.name = projectName;
|
|
1271
|
-
await fs5.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
1272
|
-
} catch (error) {
|
|
1273
|
-
logger.warn(`Could not update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
async function installDependencies(projectPath, packageManager) {
|
|
1277
|
-
const spinner5 = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
1278
|
-
try {
|
|
1279
|
-
const pm = packageManager || getPackageManager();
|
|
1280
|
-
const installCommand = shellQuote.quote([pm, "install"]);
|
|
1281
|
-
await exec(installCommand, {
|
|
1282
|
-
cwd: projectPath
|
|
1283
|
-
});
|
|
1284
|
-
spinner5.success("Dependencies installed successfully");
|
|
1285
|
-
} catch (error) {
|
|
1286
|
-
spinner5.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1287
|
-
throw error;
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
|
|
1291
|
-
async function loadTemplates() {
|
|
1292
|
-
try {
|
|
1293
|
-
const response = await fetch(TEMPLATES_API_URL);
|
|
1294
|
-
if (!response.ok) {
|
|
1295
|
-
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
1296
|
-
}
|
|
1297
|
-
const templates = await response.json();
|
|
1298
|
-
return templates;
|
|
1299
|
-
} catch (error) {
|
|
1300
|
-
console.error("Error loading templates:", error);
|
|
1301
|
-
throw new Error("Failed to load templates. Please check your internet connection and try again.");
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
function pluralize(count, singular, plural) {
|
|
1305
|
-
return count === 1 ? singular : plural || `${singular}s`;
|
|
1306
|
-
}
|
|
1307
|
-
async function selectTemplate(templates) {
|
|
1308
|
-
const choices = templates.map((template) => {
|
|
1309
|
-
const parts = [];
|
|
1310
|
-
if (template.agents?.length) {
|
|
1311
|
-
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
|
|
1312
|
-
}
|
|
1313
|
-
if (template.tools?.length) {
|
|
1314
|
-
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
|
|
1315
|
-
}
|
|
1316
|
-
if (template.workflows?.length) {
|
|
1317
|
-
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
|
|
1318
|
-
}
|
|
1319
|
-
if (template.mcp?.length) {
|
|
1320
|
-
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
|
|
1321
|
-
}
|
|
1322
|
-
if (template.networks?.length) {
|
|
1323
|
-
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
|
|
1324
|
-
}
|
|
1325
|
-
return {
|
|
1326
|
-
value: template,
|
|
1327
|
-
label: template.title,
|
|
1328
|
-
hint: parts.join(", ") || "Template components"
|
|
1329
|
-
};
|
|
1330
|
-
});
|
|
1331
|
-
const selected = await ve({
|
|
1332
|
-
message: "Select a template:",
|
|
1333
|
-
options: choices
|
|
1334
|
-
});
|
|
1335
|
-
if (pD(selected)) {
|
|
1336
|
-
return null;
|
|
1337
|
-
}
|
|
1338
|
-
return selected;
|
|
1339
|
-
}
|
|
1340
|
-
function findTemplateByName(templates, templateName) {
|
|
1341
|
-
let template = templates.find((t) => t.slug === templateName);
|
|
1342
|
-
if (template) return template;
|
|
1343
|
-
const slugWithPrefix = `template-${templateName}`;
|
|
1344
|
-
template = templates.find((t) => t.slug === slugWithPrefix);
|
|
1345
|
-
if (template) return template;
|
|
1346
|
-
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
|
|
1347
|
-
if (template) return template;
|
|
1348
|
-
return null;
|
|
1349
|
-
}
|
|
1350
|
-
function getDefaultProjectName(template) {
|
|
1351
|
-
return template.slug.replace(/^template-/, "");
|
|
1352
|
-
}
|
|
1190
|
+
var package_default = {
|
|
1191
|
+
version: "1.0.0-beta.3"};
|
|
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,166 +1277,54 @@ 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
|
|
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
|
-
};
|
|
1288
|
+
var EnvService = class {
|
|
1474
1289
|
};
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
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");
|
|
1290
|
+
var FileEnvService = class extends EnvService {
|
|
1291
|
+
filePath;
|
|
1292
|
+
constructor(filePath) {
|
|
1293
|
+
super();
|
|
1294
|
+
this.filePath = filePath;
|
|
1511
1295
|
}
|
|
1512
|
-
|
|
1513
|
-
|
|
1296
|
+
readFile(filePath) {
|
|
1297
|
+
return new Promise((resolve, reject) => {
|
|
1298
|
+
fs3__default.readFile(filePath, "utf8", (err, data) => {
|
|
1299
|
+
if (err) reject(err);
|
|
1300
|
+
else resolve(data);
|
|
1301
|
+
});
|
|
1302
|
+
});
|
|
1514
1303
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1304
|
+
writeFile({ filePath, data }) {
|
|
1305
|
+
return new Promise((resolve, reject) => {
|
|
1306
|
+
fs3__default.writeFile(filePath, data, "utf8", (err) => {
|
|
1307
|
+
if (err) reject(err);
|
|
1308
|
+
else resolve();
|
|
1309
|
+
});
|
|
1310
|
+
});
|
|
1521
1311
|
}
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1312
|
+
async updateEnvData({
|
|
1313
|
+
key,
|
|
1314
|
+
value,
|
|
1315
|
+
filePath = this.filePath,
|
|
1316
|
+
data
|
|
1317
|
+
}) {
|
|
1318
|
+
const regex = new RegExp(`^${key}=.*$`, "m");
|
|
1319
|
+
if (data.match(regex)) {
|
|
1320
|
+
data = data.replace(regex, `${key}=${value}`);
|
|
1321
|
+
} else {
|
|
1322
|
+
data += `
|
|
1323
|
+
${key}=${value}`;
|
|
1526
1324
|
}
|
|
1527
|
-
await
|
|
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
|
-
var EnvService = class {
|
|
1562
|
-
};
|
|
1563
|
-
var FileEnvService = class extends EnvService {
|
|
1564
|
-
filePath;
|
|
1565
|
-
constructor(filePath) {
|
|
1566
|
-
super();
|
|
1567
|
-
this.filePath = filePath;
|
|
1568
|
-
}
|
|
1569
|
-
readFile(filePath) {
|
|
1570
|
-
return new Promise((resolve, reject) => {
|
|
1571
|
-
fs4__default.readFile(filePath, "utf8", (err, data) => {
|
|
1572
|
-
if (err) reject(err);
|
|
1573
|
-
else resolve(data);
|
|
1574
|
-
});
|
|
1575
|
-
});
|
|
1576
|
-
}
|
|
1577
|
-
writeFile({ filePath, data }) {
|
|
1578
|
-
return new Promise((resolve, reject) => {
|
|
1579
|
-
fs4__default.writeFile(filePath, data, "utf8", (err) => {
|
|
1580
|
-
if (err) reject(err);
|
|
1581
|
-
else resolve();
|
|
1582
|
-
});
|
|
1583
|
-
});
|
|
1584
|
-
}
|
|
1585
|
-
async updateEnvData({
|
|
1586
|
-
key,
|
|
1587
|
-
value,
|
|
1588
|
-
filePath = this.filePath,
|
|
1589
|
-
data
|
|
1590
|
-
}) {
|
|
1591
|
-
const regex = new RegExp(`^${key}=.*$`, "m");
|
|
1592
|
-
if (data.match(regex)) {
|
|
1593
|
-
data = data.replace(regex, `${key}=${value}`);
|
|
1594
|
-
} else {
|
|
1595
|
-
data += `
|
|
1596
|
-
${key}=${value}`;
|
|
1597
|
-
}
|
|
1598
|
-
await this.writeFile({ filePath, data });
|
|
1599
|
-
console.log(`${key} set to ${value} in ENV file.`);
|
|
1600
|
-
return data;
|
|
1325
|
+
await this.writeFile({ filePath, data });
|
|
1326
|
+
console.info(`${key} set to ${value} in ENV file.`);
|
|
1327
|
+
return data;
|
|
1601
1328
|
}
|
|
1602
1329
|
async getEnvValue(key) {
|
|
1603
1330
|
try {
|
|
@@ -1631,9 +1358,9 @@ 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
1366
|
await fsExtra.outputFile(outputFilePath, fileString);
|
|
@@ -1647,7 +1374,7 @@ var FileService = class {
|
|
|
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,20 +1786,115 @@ 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
|
}
|
|
@@ -1974,46 +1907,55 @@ 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,20 +1985,18 @@ 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
2002
|
await fsExtra.ensureDir(dirPath);
|
|
@@ -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,230 @@ 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("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
|
+
}
|
|
2197
2340
|
var s = Y();
|
|
2198
|
-
var exec3 = util.promisify(child_process.exec);
|
|
2199
2341
|
var init = async ({
|
|
2200
|
-
directory,
|
|
2201
|
-
addExample = false,
|
|
2342
|
+
directory = "src/",
|
|
2202
2343
|
components,
|
|
2203
2344
|
llmProvider = "openai",
|
|
2204
2345
|
llmApiKey,
|
|
2205
|
-
|
|
2346
|
+
addExample = false,
|
|
2347
|
+
configureEditorWithDocsMCP,
|
|
2348
|
+
versionTag
|
|
2206
2349
|
}) => {
|
|
2207
2350
|
s.start("Initializing Mastra");
|
|
2351
|
+
const packageVersionTag = versionTag ? `@${versionTag}` : "";
|
|
2208
2352
|
try {
|
|
2209
2353
|
const result = await createMastraDir(directory);
|
|
2210
2354
|
if (!result.ok) {
|
|
@@ -2217,7 +2361,8 @@ var init = async ({
|
|
|
2217
2361
|
dirPath,
|
|
2218
2362
|
addExample,
|
|
2219
2363
|
addWorkflow: components.includes("workflows"),
|
|
2220
|
-
addAgent: components.includes("agents")
|
|
2364
|
+
addAgent: components.includes("agents"),
|
|
2365
|
+
addScorers: components.includes("scorers")
|
|
2221
2366
|
}),
|
|
2222
2367
|
...components.map((component) => createComponentsDir(dirPath, component)),
|
|
2223
2368
|
writeAPIKey({ provider: llmProvider, apiKey: llmApiKey })
|
|
@@ -2231,28 +2376,31 @@ var init = async ({
|
|
|
2231
2376
|
const depService = new DepsService();
|
|
2232
2377
|
const needsLibsql = await depService.checkDependencies(["@mastra/libsql"]) !== `ok`;
|
|
2233
2378
|
if (needsLibsql) {
|
|
2234
|
-
await depService.installPackages([
|
|
2379
|
+
await depService.installPackages([`@mastra/libsql${packageVersionTag}`]);
|
|
2235
2380
|
}
|
|
2236
2381
|
const needsMemory = components.includes(`agents`) && await depService.checkDependencies(["@mastra/memory"]) !== `ok`;
|
|
2237
2382
|
if (needsMemory) {
|
|
2238
|
-
await depService.installPackages([
|
|
2383
|
+
await depService.installPackages([`@mastra/memory${packageVersionTag}`]);
|
|
2239
2384
|
}
|
|
2240
2385
|
const needsLoggers = await depService.checkDependencies(["@mastra/loggers"]) !== `ok`;
|
|
2241
2386
|
if (needsLoggers) {
|
|
2242
|
-
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}`]);
|
|
2243
2396
|
}
|
|
2244
2397
|
}
|
|
2245
2398
|
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
2399
|
if (configureEditorWithDocsMCP) {
|
|
2253
2400
|
await installMastraDocsMCPServer({
|
|
2254
2401
|
editor: configureEditorWithDocsMCP,
|
|
2255
|
-
directory: process.cwd()
|
|
2402
|
+
directory: process.cwd(),
|
|
2403
|
+
versionTag
|
|
2256
2404
|
});
|
|
2257
2405
|
}
|
|
2258
2406
|
s.stop();
|
|
@@ -2275,10 +2423,10 @@ var init = async ({
|
|
|
2275
2423
|
return { success: false };
|
|
2276
2424
|
}
|
|
2277
2425
|
};
|
|
2278
|
-
var
|
|
2426
|
+
var exec3 = util.promisify(child_process.exec);
|
|
2279
2427
|
var execWithTimeout = async (command, timeoutMs) => {
|
|
2280
2428
|
try {
|
|
2281
|
-
const promise =
|
|
2429
|
+
const promise = exec3(command, { killSignal: "SIGTERM" });
|
|
2282
2430
|
if (!timeoutMs) {
|
|
2283
2431
|
return await promise;
|
|
2284
2432
|
}
|
|
@@ -2301,6 +2449,32 @@ var execWithTimeout = async (command, timeoutMs) => {
|
|
|
2301
2449
|
throw error;
|
|
2302
2450
|
}
|
|
2303
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
|
+
}
|
|
2304
2478
|
async function installMastraDependency(pm, dependency, versionTag, isDev, timeout) {
|
|
2305
2479
|
let installCommand = getPackageManagerAddCommand(pm);
|
|
2306
2480
|
if (isDev) {
|
|
@@ -2326,23 +2500,42 @@ async function installMastraDependency(pm, dependency, versionTag, isDev, timeou
|
|
|
2326
2500
|
var createMastraProject = async ({
|
|
2327
2501
|
projectName: name,
|
|
2328
2502
|
createVersionTag,
|
|
2329
|
-
timeout
|
|
2503
|
+
timeout,
|
|
2504
|
+
llmProvider,
|
|
2505
|
+
llmApiKey,
|
|
2506
|
+
needsInteractive
|
|
2330
2507
|
}) => {
|
|
2331
2508
|
Ie(color2.inverse(" Mastra Create "));
|
|
2332
2509
|
const projectName = name ?? await he({
|
|
2333
2510
|
message: "What do you want to name your project?",
|
|
2334
2511
|
placeholder: "my-mastra-app",
|
|
2335
|
-
defaultValue: "my-mastra-app"
|
|
2512
|
+
defaultValue: "my-mastra-app",
|
|
2513
|
+
validate: (value) => {
|
|
2514
|
+
if (value.length === 0) return "Project name cannot be empty";
|
|
2515
|
+
if (fs3__default__default.existsSync(value)) {
|
|
2516
|
+
return `A directory named "${value}" already exists. Please choose a different name.`;
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2336
2519
|
});
|
|
2337
2520
|
if (pD(projectName)) {
|
|
2338
2521
|
xe("Operation cancelled");
|
|
2339
2522
|
process.exit(0);
|
|
2340
2523
|
}
|
|
2524
|
+
let result;
|
|
2525
|
+
if (needsInteractive) {
|
|
2526
|
+
result = await interactivePrompt({
|
|
2527
|
+
options: { showBanner: false },
|
|
2528
|
+
skip: { llmProvider: llmProvider !== void 0, llmApiKey: llmApiKey !== void 0 }
|
|
2529
|
+
});
|
|
2530
|
+
}
|
|
2341
2531
|
const s2 = Y();
|
|
2532
|
+
const originalCwd = process.cwd();
|
|
2533
|
+
let projectPath = null;
|
|
2342
2534
|
try {
|
|
2343
2535
|
s2.start("Creating project");
|
|
2344
2536
|
try {
|
|
2345
|
-
await
|
|
2537
|
+
await fs4.mkdir(projectName);
|
|
2538
|
+
projectPath = path3.resolve(originalCwd, projectName);
|
|
2346
2539
|
} catch (error) {
|
|
2347
2540
|
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
2348
2541
|
s2.stop(`A directory named "${projectName}" already exists. Please choose a different name.`);
|
|
@@ -2357,9 +2550,7 @@ var createMastraProject = async ({
|
|
|
2357
2550
|
const installCommand = getPackageManagerAddCommand(pm);
|
|
2358
2551
|
s2.message("Initializing project structure");
|
|
2359
2552
|
try {
|
|
2360
|
-
await
|
|
2361
|
-
await exec4(`npm pkg set type="module"`);
|
|
2362
|
-
await exec4(`npm pkg set engines.node=">=20.9.0"`);
|
|
2553
|
+
await initializePackageJson(pm);
|
|
2363
2554
|
const depsService = new DepsService();
|
|
2364
2555
|
await depsService.addScriptsToPackageJson({
|
|
2365
2556
|
dev: "mastra dev",
|
|
@@ -2374,9 +2565,9 @@ var createMastraProject = async ({
|
|
|
2374
2565
|
s2.stop("Project structure created");
|
|
2375
2566
|
s2.start(`Installing ${pm} dependencies`);
|
|
2376
2567
|
try {
|
|
2377
|
-
await
|
|
2378
|
-
await
|
|
2379
|
-
await
|
|
2568
|
+
await exec3(`${pm} ${installCommand} zod@^4`);
|
|
2569
|
+
await exec3(`${pm} ${installCommand} -D typescript @types/node`);
|
|
2570
|
+
await exec3(`echo '{
|
|
2380
2571
|
"compilerOptions": {
|
|
2381
2572
|
"target": "ES2022",
|
|
2382
2573
|
"module": "ES2022",
|
|
@@ -2398,15 +2589,15 @@ var createMastraProject = async ({
|
|
|
2398
2589
|
);
|
|
2399
2590
|
}
|
|
2400
2591
|
s2.stop(`${pm} dependencies installed`);
|
|
2401
|
-
s2.start("Installing
|
|
2592
|
+
s2.start("Installing Mastra CLI");
|
|
2402
2593
|
const versionTag = createVersionTag ? `@${createVersionTag}` : "@latest";
|
|
2403
2594
|
try {
|
|
2404
2595
|
await installMastraDependency(pm, "mastra", versionTag, true, timeout);
|
|
2405
2596
|
} catch (error) {
|
|
2406
2597
|
throw new Error(`Failed to install Mastra CLI: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2407
2598
|
}
|
|
2408
|
-
s2.stop("
|
|
2409
|
-
s2.start("Installing dependencies");
|
|
2599
|
+
s2.stop("Mastra CLI installed");
|
|
2600
|
+
s2.start("Installing Mastra dependencies");
|
|
2410
2601
|
try {
|
|
2411
2602
|
await installMastraDependency(pm, "@mastra/core", versionTag, false, timeout);
|
|
2412
2603
|
await installMastraDependency(pm, "@mastra/libsql", versionTag, false, timeout);
|
|
@@ -2419,58 +2610,80 @@ var createMastraProject = async ({
|
|
|
2419
2610
|
s2.stop("Mastra dependencies installed");
|
|
2420
2611
|
s2.start("Adding .gitignore");
|
|
2421
2612
|
try {
|
|
2422
|
-
await
|
|
2423
|
-
await
|
|
2424
|
-
await
|
|
2425
|
-
await
|
|
2426
|
-
await
|
|
2427
|
-
await
|
|
2428
|
-
await
|
|
2429
|
-
await
|
|
2613
|
+
await exec3(`echo output.txt >> .gitignore`);
|
|
2614
|
+
await exec3(`echo node_modules >> .gitignore`);
|
|
2615
|
+
await exec3(`echo dist >> .gitignore`);
|
|
2616
|
+
await exec3(`echo .mastra >> .gitignore`);
|
|
2617
|
+
await exec3(`echo .env.development >> .gitignore`);
|
|
2618
|
+
await exec3(`echo .env >> .gitignore`);
|
|
2619
|
+
await exec3(`echo *.db >> .gitignore`);
|
|
2620
|
+
await exec3(`echo *.db-* >> .gitignore`);
|
|
2430
2621
|
} catch (error) {
|
|
2431
2622
|
throw new Error(`Failed to create .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2432
2623
|
}
|
|
2433
2624
|
s2.stop(".gitignore added");
|
|
2434
2625
|
Se("Project created successfully");
|
|
2435
|
-
console.
|
|
2436
|
-
return { projectName };
|
|
2626
|
+
console.info("");
|
|
2627
|
+
return { projectName, result };
|
|
2437
2628
|
} catch (error) {
|
|
2438
2629
|
s2.stop();
|
|
2439
2630
|
const errorMessage = error instanceof Error ? error.message : "An unexpected error occurred";
|
|
2440
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
|
+
}
|
|
2441
2642
|
process.exit(1);
|
|
2442
2643
|
}
|
|
2443
2644
|
};
|
|
2444
|
-
var
|
|
2445
|
-
|
|
2446
|
-
|
|
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
|
+
});
|
|
2447
2655
|
return;
|
|
2448
2656
|
}
|
|
2449
|
-
const
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2657
|
+
const needsInteractive = args.components === void 0 || args.llmProvider === void 0 || args.addExample === void 0;
|
|
2658
|
+
const { projectName, result } = await createMastraProject({
|
|
2659
|
+
projectName: args?.projectName,
|
|
2660
|
+
createVersionTag: args?.createVersionTag,
|
|
2661
|
+
timeout: args?.timeout,
|
|
2662
|
+
llmProvider: args?.llmProvider,
|
|
2663
|
+
llmApiKey: args?.llmApiKey,
|
|
2664
|
+
needsInteractive
|
|
2453
2665
|
});
|
|
2454
|
-
const directory =
|
|
2455
|
-
if (
|
|
2456
|
-
const result = await interactivePrompt();
|
|
2666
|
+
const directory = args.directory || "src/";
|
|
2667
|
+
if (needsInteractive && result) {
|
|
2457
2668
|
await init({
|
|
2458
2669
|
...result,
|
|
2459
2670
|
llmApiKey: result?.llmApiKey,
|
|
2460
|
-
components: ["agents", "tools", "workflows"],
|
|
2461
|
-
addExample: true
|
|
2671
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2672
|
+
addExample: true,
|
|
2673
|
+
versionTag: args.createVersionTag
|
|
2462
2674
|
});
|
|
2463
2675
|
postCreate({ projectName });
|
|
2464
2676
|
return;
|
|
2465
2677
|
}
|
|
2466
|
-
const { components = [], llmProvider = "openai", addExample = false, llmApiKey } =
|
|
2678
|
+
const { components = [], llmProvider = "openai", addExample = false, llmApiKey } = args;
|
|
2467
2679
|
await init({
|
|
2468
2680
|
directory,
|
|
2469
2681
|
components,
|
|
2470
2682
|
llmProvider,
|
|
2471
2683
|
addExample,
|
|
2472
2684
|
llmApiKey,
|
|
2473
|
-
configureEditorWithDocsMCP:
|
|
2685
|
+
configureEditorWithDocsMCP: args.mcpServer,
|
|
2686
|
+
versionTag: args.createVersionTag
|
|
2474
2687
|
});
|
|
2475
2688
|
postCreate({ projectName });
|
|
2476
2689
|
};
|
|
@@ -2561,9 +2774,9 @@ async function createFromGitHubUrl(url) {
|
|
|
2561
2774
|
workflows: []
|
|
2562
2775
|
};
|
|
2563
2776
|
}
|
|
2564
|
-
async function createFromTemplate(
|
|
2777
|
+
async function createFromTemplate(args) {
|
|
2565
2778
|
let selectedTemplate;
|
|
2566
|
-
if (
|
|
2779
|
+
if (args.template === true) {
|
|
2567
2780
|
const templates = await loadTemplates();
|
|
2568
2781
|
const selected = await selectTemplate(templates);
|
|
2569
2782
|
if (!selected) {
|
|
@@ -2571,26 +2784,26 @@ async function createFromTemplate(args2) {
|
|
|
2571
2784
|
return;
|
|
2572
2785
|
}
|
|
2573
2786
|
selectedTemplate = selected;
|
|
2574
|
-
} else if (
|
|
2575
|
-
if (isGitHubUrl(
|
|
2576
|
-
const
|
|
2577
|
-
|
|
2578
|
-
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);
|
|
2579
2792
|
if (!validation.isValid) {
|
|
2580
|
-
|
|
2793
|
+
spinner4.stop("Validation failed");
|
|
2581
2794
|
M.error("This does not appear to be a valid Mastra project:");
|
|
2582
2795
|
validation.errors.forEach((error) => M.error(` - ${error}`));
|
|
2583
2796
|
throw new Error("Invalid Mastra project");
|
|
2584
2797
|
}
|
|
2585
|
-
|
|
2586
|
-
selectedTemplate = await createFromGitHubUrl(
|
|
2798
|
+
spinner4.stop("Valid Mastra project \u2713");
|
|
2799
|
+
selectedTemplate = await createFromGitHubUrl(args.template);
|
|
2587
2800
|
} else {
|
|
2588
2801
|
const templates = await loadTemplates();
|
|
2589
|
-
const found = findTemplateByName(templates,
|
|
2802
|
+
const found = findTemplateByName(templates, args.template);
|
|
2590
2803
|
if (!found) {
|
|
2591
|
-
M.error(`Template "${
|
|
2804
|
+
M.error(`Template "${args.template}" not found. Available templates:`);
|
|
2592
2805
|
templates.forEach((t) => M.info(` - ${t.title} (use: ${t.slug.replace("template-", "")})`));
|
|
2593
|
-
throw new Error(`Template "${
|
|
2806
|
+
throw new Error(`Template "${args.template}" not found`);
|
|
2594
2807
|
}
|
|
2595
2808
|
selectedTemplate = found;
|
|
2596
2809
|
}
|
|
@@ -2598,7 +2811,7 @@ async function createFromTemplate(args2) {
|
|
|
2598
2811
|
if (!selectedTemplate) {
|
|
2599
2812
|
throw new Error("No template selected");
|
|
2600
2813
|
}
|
|
2601
|
-
let projectName =
|
|
2814
|
+
let projectName = args.projectName;
|
|
2602
2815
|
if (!projectName) {
|
|
2603
2816
|
const defaultName = getDefaultProjectName(selectedTemplate);
|
|
2604
2817
|
const response = await he({
|
|
@@ -2612,17 +2825,41 @@ async function createFromTemplate(args2) {
|
|
|
2612
2825
|
}
|
|
2613
2826
|
projectName = response;
|
|
2614
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;
|
|
2615
2841
|
try {
|
|
2616
|
-
const analytics =
|
|
2842
|
+
const analytics = args.injectedAnalytics || getAnalytics();
|
|
2617
2843
|
if (analytics) {
|
|
2618
2844
|
analytics.trackEvent("cli_template_used", {
|
|
2619
2845
|
template_slug: selectedTemplate.slug,
|
|
2620
2846
|
template_title: selectedTemplate.title
|
|
2621
2847
|
});
|
|
2848
|
+
if (llmProvider) {
|
|
2849
|
+
analytics.trackEvent("cli_model_provider_selected", {
|
|
2850
|
+
provider: llmProvider,
|
|
2851
|
+
selection_method: args.llmProvider ? "cli_args" : "interactive"
|
|
2852
|
+
});
|
|
2853
|
+
}
|
|
2622
2854
|
}
|
|
2623
|
-
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({
|
|
2624
2859
|
template: selectedTemplate,
|
|
2625
|
-
projectName
|
|
2860
|
+
projectName,
|
|
2861
|
+
branch,
|
|
2862
|
+
llmProvider
|
|
2626
2863
|
});
|
|
2627
2864
|
await installDependencies(projectPath);
|
|
2628
2865
|
Me(`
|
|
@@ -2633,6 +2870,17 @@ async function createFromTemplate(args2) {
|
|
|
2633
2870
|
`);
|
|
2634
2871
|
postCreate({ projectName });
|
|
2635
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
|
+
}
|
|
2636
2884
|
M.error(`Failed to create project from template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2637
2885
|
throw error;
|
|
2638
2886
|
}
|
|
@@ -2672,14 +2920,14 @@ program.version(`${version}`, "-v, --version").description(`create-mastra ${vers
|
|
|
2672
2920
|
analytics.trackCommand({
|
|
2673
2921
|
command: "version"
|
|
2674
2922
|
});
|
|
2675
|
-
console.
|
|
2923
|
+
console.info(`create-mastra ${version}`);
|
|
2676
2924
|
} catch {
|
|
2677
2925
|
}
|
|
2678
2926
|
});
|
|
2679
2927
|
program.name("create-mastra").description("Create a new Mastra project").argument("[project-name]", "Directory name of the project").option(
|
|
2680
2928
|
"-p, --project-name <string>",
|
|
2681
2929
|
"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(
|
|
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(
|
|
2683
2931
|
"--template [template-name]",
|
|
2684
2932
|
"Create project from a template (use template name, public GitHub URL, or leave blank to select from list)"
|
|
2685
2933
|
).action(async (projectNameArg, args) => {
|
|
@@ -2687,7 +2935,7 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2687
2935
|
const timeout = args?.timeout ? args?.timeout === true ? 6e4 : parseInt(args?.timeout, 10) : void 0;
|
|
2688
2936
|
if (args.default) {
|
|
2689
2937
|
await create({
|
|
2690
|
-
components: ["agents", "tools", "workflows"],
|
|
2938
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2691
2939
|
llmProvider: "openai",
|
|
2692
2940
|
addExample: true,
|
|
2693
2941
|
createVersionTag,
|
|
@@ -2703,7 +2951,7 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2703
2951
|
components: args.components ? args.components.split(",") : [],
|
|
2704
2952
|
llmProvider: args.llm,
|
|
2705
2953
|
addExample: args.example,
|
|
2706
|
-
llmApiKey: args
|
|
2954
|
+
llmApiKey: args.llmApiKey,
|
|
2707
2955
|
createVersionTag,
|
|
2708
2956
|
timeout,
|
|
2709
2957
|
projectName,
|