create-mastra 0.0.0-share-agent-metadata-with-cloud-20250718123411 → 0.0.0-span-scorring-test-20251124132129
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 +2143 -0
- package/README.md +11 -39
- package/dist/index.js +902 -543
- package/dist/index.js.map +1 -1
- package/dist/starter-files/tools.ts +2 -2
- package/dist/templates/dev.entry.js +10 -43
- package/package.json +24 -16
- package/dist/starter-files/config.ts +0 -25
- package/dist/starter-files/mastra-pg.docker-compose.yaml +0 -15
package/dist/index.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
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 fs 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 fsExtra3, { 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,194 +1187,21 @@ var PinoLogger = class extends MastraLogger {
|
|
|
1173
1187
|
}
|
|
1174
1188
|
};
|
|
1175
1189
|
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
if (userAgent.includes("yarn")) {
|
|
1180
|
-
return "yarn";
|
|
1181
|
-
}
|
|
1182
|
-
if (userAgent.includes("pnpm")) {
|
|
1183
|
-
return "pnpm";
|
|
1184
|
-
}
|
|
1185
|
-
if (userAgent.includes("npm")) {
|
|
1186
|
-
return "npm";
|
|
1187
|
-
}
|
|
1188
|
-
if (execPath.includes("yarn")) {
|
|
1189
|
-
return "yarn";
|
|
1190
|
-
}
|
|
1191
|
-
if (execPath.includes("pnpm")) {
|
|
1192
|
-
return "pnpm";
|
|
1193
|
-
}
|
|
1194
|
-
if (execPath.includes("npm")) {
|
|
1195
|
-
return "npm";
|
|
1196
|
-
}
|
|
1197
|
-
return "npm";
|
|
1198
|
-
}
|
|
1199
|
-
function getPackageManagerInstallCommand(pm) {
|
|
1190
|
+
var package_default = {
|
|
1191
|
+
version: "1.0.0-beta.3"};
|
|
1192
|
+
function getPackageManagerAddCommand(pm) {
|
|
1200
1193
|
switch (pm) {
|
|
1201
1194
|
case "npm":
|
|
1202
|
-
return "install";
|
|
1195
|
+
return "install --audit=false --fund=false --loglevel=error --progress=false --update-notifier=false";
|
|
1203
1196
|
case "yarn":
|
|
1204
1197
|
return "add";
|
|
1205
1198
|
case "pnpm":
|
|
1199
|
+
return "add --loglevel=error";
|
|
1200
|
+
case "bun":
|
|
1206
1201
|
return "add";
|
|
1207
1202
|
default:
|
|
1208
|
-
return "
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
var logger = new PinoLogger({
|
|
1212
|
-
name: "Mastra CLI",
|
|
1213
|
-
level: "info"
|
|
1214
|
-
});
|
|
1215
|
-
var exec = util.promisify(child_process.exec);
|
|
1216
|
-
async function cloneTemplate(options) {
|
|
1217
|
-
const { template, projectName, targetDir } = options;
|
|
1218
|
-
const projectPath = targetDir ? path3.resolve(targetDir, projectName) : path3.resolve(projectName);
|
|
1219
|
-
const spinner4 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
|
|
1220
|
-
try {
|
|
1221
|
-
if (await directoryExists(projectPath)) {
|
|
1222
|
-
spinner4.error(`Directory ${projectName} already exists`);
|
|
1223
|
-
throw new Error(`Directory ${projectName} already exists`);
|
|
1224
|
-
}
|
|
1225
|
-
await cloneRepositoryWithoutGit(template.githubUrl, projectPath);
|
|
1226
|
-
await updatePackageJson(projectPath, projectName);
|
|
1227
|
-
const envExamplePath = path3.join(projectPath, ".env.example");
|
|
1228
|
-
if (await fileExists(envExamplePath)) {
|
|
1229
|
-
await fs.copyFile(envExamplePath, path3.join(projectPath, ".env"));
|
|
1230
|
-
}
|
|
1231
|
-
spinner4.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
1232
|
-
return projectPath;
|
|
1233
|
-
} catch (error) {
|
|
1234
|
-
spinner4.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1235
|
-
throw error;
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
async function directoryExists(dirPath) {
|
|
1239
|
-
try {
|
|
1240
|
-
const stat = await fs.stat(dirPath);
|
|
1241
|
-
return stat.isDirectory();
|
|
1242
|
-
} catch {
|
|
1243
|
-
return false;
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
async function fileExists(filePath) {
|
|
1247
|
-
try {
|
|
1248
|
-
const stat = await fs.stat(filePath);
|
|
1249
|
-
return stat.isFile();
|
|
1250
|
-
} catch {
|
|
1251
|
-
return false;
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
async function cloneRepositoryWithoutGit(repoUrl, targetPath) {
|
|
1255
|
-
await fs.mkdir(targetPath, { recursive: true });
|
|
1256
|
-
try {
|
|
1257
|
-
const degitRepo = repoUrl.replace("https://github.com/", "");
|
|
1258
|
-
const degitCommand = shellQuote.quote(["npx", "degit", degitRepo, targetPath]);
|
|
1259
|
-
await exec(degitCommand, {
|
|
1260
|
-
cwd: process.cwd()
|
|
1261
|
-
});
|
|
1262
|
-
} catch {
|
|
1263
|
-
try {
|
|
1264
|
-
const gitCommand = shellQuote.quote(["git", "clone", repoUrl, targetPath]);
|
|
1265
|
-
await exec(gitCommand, {
|
|
1266
|
-
cwd: process.cwd()
|
|
1267
|
-
});
|
|
1268
|
-
const gitDir = path3.join(targetPath, ".git");
|
|
1269
|
-
if (await directoryExists(gitDir)) {
|
|
1270
|
-
await fs.rm(gitDir, { recursive: true, force: true });
|
|
1271
|
-
}
|
|
1272
|
-
} catch (gitError) {
|
|
1273
|
-
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
async function updatePackageJson(projectPath, projectName) {
|
|
1278
|
-
const packageJsonPath = path3.join(projectPath, "package.json");
|
|
1279
|
-
try {
|
|
1280
|
-
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
1281
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
1282
|
-
packageJson.name = projectName;
|
|
1283
|
-
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
1284
|
-
} catch (error) {
|
|
1285
|
-
logger.warn(`Could not update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
async function installDependencies(projectPath, packageManager) {
|
|
1289
|
-
const spinner4 = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
1290
|
-
try {
|
|
1291
|
-
const pm = packageManager || getPackageManager();
|
|
1292
|
-
const installCommand = shellQuote.quote([pm, "install"]);
|
|
1293
|
-
await exec(installCommand, {
|
|
1294
|
-
cwd: projectPath
|
|
1295
|
-
});
|
|
1296
|
-
spinner4.success("Dependencies installed successfully");
|
|
1297
|
-
} catch (error) {
|
|
1298
|
-
spinner4.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1299
|
-
throw error;
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
|
|
1303
|
-
async function loadTemplates() {
|
|
1304
|
-
try {
|
|
1305
|
-
const response = await fetch(TEMPLATES_API_URL);
|
|
1306
|
-
if (!response.ok) {
|
|
1307
|
-
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
1308
|
-
}
|
|
1309
|
-
const templates = await response.json();
|
|
1310
|
-
return templates;
|
|
1311
|
-
} catch (error) {
|
|
1312
|
-
console.error("Error loading templates:", error);
|
|
1313
|
-
throw new Error("Failed to load templates. Please check your internet connection and try again.");
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
function pluralize(count, singular, plural) {
|
|
1317
|
-
return count === 1 ? singular : plural || `${singular}s`;
|
|
1318
|
-
}
|
|
1319
|
-
async function selectTemplate(templates) {
|
|
1320
|
-
const choices = templates.map((template) => {
|
|
1321
|
-
const parts = [];
|
|
1322
|
-
if (template.agents?.length) {
|
|
1323
|
-
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
|
|
1324
|
-
}
|
|
1325
|
-
if (template.tools?.length) {
|
|
1326
|
-
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
|
|
1327
|
-
}
|
|
1328
|
-
if (template.workflows?.length) {
|
|
1329
|
-
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
|
|
1330
|
-
}
|
|
1331
|
-
if (template.mcp?.length) {
|
|
1332
|
-
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
|
|
1333
|
-
}
|
|
1334
|
-
if (template.networks?.length) {
|
|
1335
|
-
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
|
|
1336
|
-
}
|
|
1337
|
-
return {
|
|
1338
|
-
value: template,
|
|
1339
|
-
label: template.title,
|
|
1340
|
-
hint: parts.join(", ") || "Template components"
|
|
1341
|
-
};
|
|
1342
|
-
});
|
|
1343
|
-
const selected = await ve({
|
|
1344
|
-
message: "Select a template:",
|
|
1345
|
-
options: choices
|
|
1346
|
-
});
|
|
1347
|
-
if (pD(selected)) {
|
|
1348
|
-
return null;
|
|
1203
|
+
return "add";
|
|
1349
1204
|
}
|
|
1350
|
-
return selected;
|
|
1351
|
-
}
|
|
1352
|
-
function findTemplateByName(templates, templateName) {
|
|
1353
|
-
let template = templates.find((t) => t.slug === templateName);
|
|
1354
|
-
if (template) return template;
|
|
1355
|
-
const slugWithPrefix = `template-${templateName}`;
|
|
1356
|
-
template = templates.find((t) => t.slug === slugWithPrefix);
|
|
1357
|
-
if (template) return template;
|
|
1358
|
-
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
|
|
1359
|
-
if (template) return template;
|
|
1360
|
-
return null;
|
|
1361
|
-
}
|
|
1362
|
-
function getDefaultProjectName(template) {
|
|
1363
|
-
return template.slug.replace(/^template-/, "");
|
|
1364
1205
|
}
|
|
1365
1206
|
var DepsService = class {
|
|
1366
1207
|
packageManager;
|
|
@@ -1370,7 +1211,7 @@ var DepsService = class {
|
|
|
1370
1211
|
findLockFile(dir) {
|
|
1371
1212
|
const lockFiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock"];
|
|
1372
1213
|
for (const file of lockFiles) {
|
|
1373
|
-
if (
|
|
1214
|
+
if (fs3__default__default.existsSync(path3.join(dir, file))) {
|
|
1374
1215
|
return file;
|
|
1375
1216
|
}
|
|
1376
1217
|
}
|
|
@@ -1396,14 +1237,10 @@ var DepsService = class {
|
|
|
1396
1237
|
}
|
|
1397
1238
|
}
|
|
1398
1239
|
async installPackages(packages) {
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
runCommand = `${this.packageManager} i`;
|
|
1402
|
-
} else {
|
|
1403
|
-
runCommand = `${this.packageManager} add`;
|
|
1404
|
-
}
|
|
1240
|
+
const pm = this.packageManager;
|
|
1241
|
+
const installCommand = getPackageManagerAddCommand(pm);
|
|
1405
1242
|
const packageList = packages.join(" ");
|
|
1406
|
-
return execa(`${
|
|
1243
|
+
return execa(`${pm} ${installCommand} ${packageList}`, {
|
|
1407
1244
|
all: true,
|
|
1408
1245
|
shell: true,
|
|
1409
1246
|
stdio: "inherit"
|
|
@@ -1413,11 +1250,11 @@ var DepsService = class {
|
|
|
1413
1250
|
try {
|
|
1414
1251
|
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1415
1252
|
try {
|
|
1416
|
-
await
|
|
1253
|
+
await fs4.access(packageJsonPath);
|
|
1417
1254
|
} catch {
|
|
1418
1255
|
return "No package.json file found in the current directory";
|
|
1419
1256
|
}
|
|
1420
|
-
const packageJson = JSON.parse(await
|
|
1257
|
+
const packageJson = JSON.parse(await fs4.readFile(packageJsonPath, "utf-8"));
|
|
1421
1258
|
for (const dependency of dependencies) {
|
|
1422
1259
|
if (!packageJson.dependencies || !packageJson.dependencies[dependency]) {
|
|
1423
1260
|
return `Please install ${dependency} before running this command (${this.packageManager} install ${dependency})`;
|
|
@@ -1432,164 +1269,45 @@ var DepsService = class {
|
|
|
1432
1269
|
async getProjectName() {
|
|
1433
1270
|
try {
|
|
1434
1271
|
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1435
|
-
const packageJson = await
|
|
1272
|
+
const packageJson = await fs4.readFile(packageJsonPath, "utf-8");
|
|
1436
1273
|
const pkg = JSON.parse(packageJson);
|
|
1437
1274
|
return pkg.name;
|
|
1438
1275
|
} catch (err) {
|
|
1439
1276
|
throw err;
|
|
1440
1277
|
}
|
|
1441
1278
|
}
|
|
1442
|
-
async getPackageVersion() {
|
|
1443
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
1444
|
-
const __dirname = dirname(__filename);
|
|
1445
|
-
const pkgJsonPath = path3.join(__dirname, "..", "package.json");
|
|
1446
|
-
const content = await fsExtra3.readJSON(pkgJsonPath);
|
|
1447
|
-
return content.version;
|
|
1448
|
-
}
|
|
1449
1279
|
async addScriptsToPackageJson(scripts) {
|
|
1450
|
-
const packageJson = JSON.parse(await
|
|
1280
|
+
const packageJson = JSON.parse(await fs4.readFile("package.json", "utf-8"));
|
|
1451
1281
|
packageJson.scripts = {
|
|
1452
1282
|
...packageJson.scripts,
|
|
1453
1283
|
...scripts
|
|
1454
1284
|
};
|
|
1455
|
-
await
|
|
1285
|
+
await fs4.writeFile("package.json", JSON.stringify(packageJson, null, 2));
|
|
1456
1286
|
}
|
|
1457
1287
|
};
|
|
1458
|
-
var
|
|
1459
|
-
var createMcpConfig = (editor) => {
|
|
1460
|
-
if (editor === "vscode") {
|
|
1461
|
-
return {
|
|
1462
|
-
servers: {
|
|
1463
|
-
mastra: process.platform === `win32` ? {
|
|
1464
|
-
command: "cmd",
|
|
1465
|
-
args: ["/c", "npx", ...args],
|
|
1466
|
-
type: "stdio"
|
|
1467
|
-
} : {
|
|
1468
|
-
command: "npx",
|
|
1469
|
-
args,
|
|
1470
|
-
type: "stdio"
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
};
|
|
1474
|
-
}
|
|
1475
|
-
return {
|
|
1476
|
-
mcpServers: {
|
|
1477
|
-
mastra: {
|
|
1478
|
-
command: "npx",
|
|
1479
|
-
args
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
};
|
|
1288
|
+
var EnvService = class {
|
|
1483
1289
|
};
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
...original?.servers || {},
|
|
1490
|
-
...createMcpConfig(editor).servers
|
|
1491
|
-
}
|
|
1492
|
-
};
|
|
1493
|
-
}
|
|
1494
|
-
return {
|
|
1495
|
-
...original,
|
|
1496
|
-
mcpServers: {
|
|
1497
|
-
...original?.mcpServers || {},
|
|
1498
|
-
...createMcpConfig(editor).mcpServers
|
|
1499
|
-
}
|
|
1500
|
-
};
|
|
1501
|
-
}
|
|
1502
|
-
async function writeMergedConfig(configPath, editor) {
|
|
1503
|
-
const configExists = existsSync(configPath);
|
|
1504
|
-
const config = makeConfig(configExists ? await readJSON(configPath) : {}, editor);
|
|
1505
|
-
await ensureFile(configPath);
|
|
1506
|
-
await writeJSON(configPath, config, {
|
|
1507
|
-
spaces: 2
|
|
1508
|
-
});
|
|
1509
|
-
}
|
|
1510
|
-
var windsurfGlobalMCPConfigPath = path3.join(os.homedir(), ".codeium", "windsurf", "mcp_config.json");
|
|
1511
|
-
var cursorGlobalMCPConfigPath = path3.join(os.homedir(), ".cursor", "mcp.json");
|
|
1512
|
-
path3.join(process.cwd(), ".vscode", "mcp.json");
|
|
1513
|
-
var vscodeGlobalMCPConfigPath = path3.join(
|
|
1514
|
-
os.homedir(),
|
|
1515
|
-
process.platform === "win32" ? path3.join("AppData", "Roaming", "Code", "User", "settings.json") : process.platform === "darwin" ? path3.join("Library", "Application Support", "Code", "User", "settings.json") : path3.join(".config", "Code", "User", "settings.json")
|
|
1516
|
-
);
|
|
1517
|
-
async function installMastraDocsMCPServer({ editor, directory }) {
|
|
1518
|
-
if (editor === `cursor`) {
|
|
1519
|
-
await writeMergedConfig(path3.join(directory, ".cursor", "mcp.json"), "cursor");
|
|
1520
|
-
}
|
|
1521
|
-
if (editor === `vscode`) {
|
|
1522
|
-
await writeMergedConfig(path3.join(directory, ".vscode", "mcp.json"), "vscode");
|
|
1290
|
+
var FileEnvService = class extends EnvService {
|
|
1291
|
+
filePath;
|
|
1292
|
+
constructor(filePath) {
|
|
1293
|
+
super();
|
|
1294
|
+
this.filePath = filePath;
|
|
1523
1295
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
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
|
+
});
|
|
1530
1303
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
}
|
|
1539
|
-
async function globalMCPIsAlreadyInstalled(editor) {
|
|
1540
|
-
let configPath = ``;
|
|
1541
|
-
if (editor === "windsurf") {
|
|
1542
|
-
configPath = windsurfGlobalMCPConfigPath;
|
|
1543
|
-
} else if (editor === "cursor-global") {
|
|
1544
|
-
configPath = cursorGlobalMCPConfigPath;
|
|
1545
|
-
} else if (editor === "vscode") {
|
|
1546
|
-
configPath = vscodeGlobalMCPConfigPath;
|
|
1547
|
-
}
|
|
1548
|
-
if (!configPath || !existsSync(configPath)) {
|
|
1549
|
-
return false;
|
|
1550
|
-
}
|
|
1551
|
-
try {
|
|
1552
|
-
const configContents = await readJSON(configPath);
|
|
1553
|
-
if (!configContents) return false;
|
|
1554
|
-
if (editor === "vscode") {
|
|
1555
|
-
if (!configContents.servers) return false;
|
|
1556
|
-
const hasMastraMCP2 = Object.values(configContents.servers).some(
|
|
1557
|
-
(server) => server?.args?.find((arg) => arg?.includes(`@mastra/mcp-docs-server`))
|
|
1558
|
-
);
|
|
1559
|
-
return hasMastraMCP2;
|
|
1560
|
-
}
|
|
1561
|
-
if (!configContents?.mcpServers) return false;
|
|
1562
|
-
const hasMastraMCP = Object.values(configContents.mcpServers).some(
|
|
1563
|
-
(server) => server?.args?.find((arg) => arg?.includes(`@mastra/mcp-docs-server`))
|
|
1564
|
-
);
|
|
1565
|
-
return hasMastraMCP;
|
|
1566
|
-
} catch {
|
|
1567
|
-
return false;
|
|
1568
|
-
}
|
|
1569
|
-
}
|
|
1570
|
-
var EnvService = class {
|
|
1571
|
-
};
|
|
1572
|
-
var FileEnvService = class extends EnvService {
|
|
1573
|
-
filePath;
|
|
1574
|
-
constructor(filePath) {
|
|
1575
|
-
super();
|
|
1576
|
-
this.filePath = filePath;
|
|
1577
|
-
}
|
|
1578
|
-
readFile(filePath) {
|
|
1579
|
-
return new Promise((resolve, reject) => {
|
|
1580
|
-
fs4__default.readFile(filePath, "utf8", (err, data) => {
|
|
1581
|
-
if (err) reject(err);
|
|
1582
|
-
else resolve(data);
|
|
1583
|
-
});
|
|
1584
|
-
});
|
|
1585
|
-
}
|
|
1586
|
-
writeFile({ filePath, data }) {
|
|
1587
|
-
return new Promise((resolve, reject) => {
|
|
1588
|
-
fs4__default.writeFile(filePath, data, "utf8", (err) => {
|
|
1589
|
-
if (err) reject(err);
|
|
1590
|
-
else resolve();
|
|
1591
|
-
});
|
|
1592
|
-
});
|
|
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
|
+
});
|
|
1593
1311
|
}
|
|
1594
1312
|
async updateEnvData({
|
|
1595
1313
|
key,
|
|
@@ -1605,7 +1323,7 @@ var FileEnvService = class extends EnvService {
|
|
|
1605
1323
|
${key}=${value}`;
|
|
1606
1324
|
}
|
|
1607
1325
|
await this.writeFile({ filePath, data });
|
|
1608
|
-
console.
|
|
1326
|
+
console.info(`${key} set to ${value} in ENV file.`);
|
|
1609
1327
|
return data;
|
|
1610
1328
|
}
|
|
1611
1329
|
async getEnvValue(key) {
|
|
@@ -1640,23 +1358,23 @@ var FileService = class {
|
|
|
1640
1358
|
const __filename = fileURLToPath(import.meta.url);
|
|
1641
1359
|
const __dirname = path3.dirname(__filename);
|
|
1642
1360
|
const filePath = path3.resolve(__dirname, "starter-files", inputFile);
|
|
1643
|
-
const fileString =
|
|
1644
|
-
if (
|
|
1645
|
-
console.
|
|
1361
|
+
const fileString = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1362
|
+
if (fs3__default__default.existsSync(outputFilePath) && !replaceIfExists) {
|
|
1363
|
+
console.info(`${outputFilePath} already exists`);
|
|
1646
1364
|
return false;
|
|
1647
1365
|
}
|
|
1648
|
-
await
|
|
1366
|
+
await fsExtra.outputFile(outputFilePath, fileString);
|
|
1649
1367
|
return true;
|
|
1650
1368
|
}
|
|
1651
1369
|
async setupEnvFile({ dbUrl }) {
|
|
1652
1370
|
const envPath = path3.join(process.cwd(), ".env.development");
|
|
1653
|
-
await
|
|
1371
|
+
await fsExtra.ensureFile(envPath);
|
|
1654
1372
|
const fileEnvService = new FileEnvService(envPath);
|
|
1655
1373
|
await fileEnvService.setEnvValue("DB_URL", dbUrl);
|
|
1656
1374
|
}
|
|
1657
1375
|
getFirstExistingFile(files) {
|
|
1658
1376
|
for (const f of files) {
|
|
1659
|
-
if (
|
|
1377
|
+
if (fs3__default__default.existsSync(f)) {
|
|
1660
1378
|
return f;
|
|
1661
1379
|
}
|
|
1662
1380
|
}
|
|
@@ -1666,53 +1384,152 @@ var FileService = class {
|
|
|
1666
1384
|
filePath,
|
|
1667
1385
|
replacements
|
|
1668
1386
|
}) {
|
|
1669
|
-
let fileContent =
|
|
1387
|
+
let fileContent = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1670
1388
|
replacements.forEach(({ search, replace }) => {
|
|
1671
1389
|
fileContent = fileContent.replaceAll(search, replace);
|
|
1672
1390
|
});
|
|
1673
|
-
|
|
1391
|
+
fs3__default__default.writeFileSync(filePath, fileContent);
|
|
1674
1392
|
}
|
|
1675
1393
|
};
|
|
1676
|
-
var
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1394
|
+
var createArgs = (versionTag) => {
|
|
1395
|
+
const packageName = versionTag ? `@mastra/mcp-docs-server@${versionTag}` : "@mastra/mcp-docs-server";
|
|
1396
|
+
return ["-y", packageName];
|
|
1397
|
+
};
|
|
1398
|
+
var createMcpConfig = (editor, versionTag) => {
|
|
1399
|
+
const args = createArgs(versionTag);
|
|
1400
|
+
if (editor === "vscode") {
|
|
1401
|
+
return {
|
|
1402
|
+
servers: {
|
|
1403
|
+
mastra: process.platform === `win32` ? {
|
|
1404
|
+
command: "cmd",
|
|
1405
|
+
args: ["/c", "npx", ...args],
|
|
1406
|
+
type: "stdio"
|
|
1407
|
+
} : {
|
|
1408
|
+
command: "npx",
|
|
1409
|
+
args,
|
|
1410
|
+
type: "stdio"
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1691
1414
|
}
|
|
1415
|
+
return {
|
|
1416
|
+
mcpServers: {
|
|
1417
|
+
mastra: {
|
|
1418
|
+
command: "npx",
|
|
1419
|
+
args
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1692
1423
|
};
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
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";
|
|
1702
1520
|
} else if (llmProvider === "groq") {
|
|
1703
|
-
|
|
1704
|
-
modelItem = `groq('llama-3.3-70b-versatile')`;
|
|
1521
|
+
model = "groq/llama-3.3-70b-versatile";
|
|
1705
1522
|
} else if (llmProvider === "google") {
|
|
1706
|
-
|
|
1707
|
-
modelItem = `google('gemini-2.5-pro-exp-03-25')`;
|
|
1523
|
+
model = "google/gemini-2.5-pro";
|
|
1708
1524
|
} else if (llmProvider === "cerebras") {
|
|
1709
|
-
|
|
1710
|
-
|
|
1525
|
+
model = "cerebras/llama-3.3-70b";
|
|
1526
|
+
} else if (llmProvider === "mistral") {
|
|
1527
|
+
model = "mistral/mistral-medium-2508";
|
|
1711
1528
|
}
|
|
1712
|
-
return
|
|
1529
|
+
return model;
|
|
1713
1530
|
};
|
|
1714
|
-
async function writeAgentSample(llmProvider, destPath, addExampleTool) {
|
|
1715
|
-
const
|
|
1531
|
+
async function writeAgentSample(llmProvider, destPath, addExampleTool, addScorers) {
|
|
1532
|
+
const modelString = getModelIdentifier(llmProvider);
|
|
1716
1533
|
const instructions = `
|
|
1717
1534
|
You are a helpful weather assistant that provides accurate weather information and can help planning activities based on the weather.
|
|
1718
1535
|
|
|
@@ -1728,19 +1545,44 @@ async function writeAgentSample(llmProvider, destPath, addExampleTool) {
|
|
|
1728
1545
|
${addExampleTool ? "Use the weatherTool to fetch current weather data." : ""}
|
|
1729
1546
|
`;
|
|
1730
1547
|
const content = `
|
|
1731
|
-
${providerImport}
|
|
1732
1548
|
import { Agent } from '@mastra/core/agent';
|
|
1733
1549
|
import { Memory } from '@mastra/memory';
|
|
1734
1550
|
import { LibSQLStore } from '@mastra/libsql';
|
|
1735
1551
|
${addExampleTool ? `import { weatherTool } from '../tools/weather-tool';` : ""}
|
|
1552
|
+
${addScorers ? `import { scorers } from '../scorers/weather-scorer';` : ""}
|
|
1736
1553
|
|
|
1737
1554
|
export const weatherAgent = new Agent({
|
|
1555
|
+
id: 'weather-agent',
|
|
1738
1556
|
name: 'Weather Agent',
|
|
1739
1557
|
instructions: \`${instructions}\`,
|
|
1740
|
-
model: ${
|
|
1558
|
+
model: '${modelString}',
|
|
1741
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
|
+
},` : ""}
|
|
1742
1583
|
memory: new Memory({
|
|
1743
1584
|
storage: new LibSQLStore({
|
|
1585
|
+
id: "memory-storage",
|
|
1744
1586
|
url: "file:../mastra.db", // path is relative to the .mastra/output directory
|
|
1745
1587
|
})
|
|
1746
1588
|
})
|
|
@@ -1750,8 +1592,8 @@ export const weatherAgent = new Agent({
|
|
|
1750
1592
|
parser: "typescript",
|
|
1751
1593
|
singleQuote: true
|
|
1752
1594
|
});
|
|
1753
|
-
await
|
|
1754
|
-
await
|
|
1595
|
+
await fs4.writeFile(destPath, "");
|
|
1596
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1755
1597
|
}
|
|
1756
1598
|
async function writeWorkflowSample(destPath) {
|
|
1757
1599
|
const content = `import { createStep, createWorkflow } from '@mastra/core/workflows';
|
|
@@ -1944,72 +1786,176 @@ export { weatherWorkflow };`;
|
|
|
1944
1786
|
semi: true,
|
|
1945
1787
|
singleQuote: true
|
|
1946
1788
|
});
|
|
1947
|
-
await
|
|
1789
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1948
1790
|
}
|
|
1949
1791
|
async function writeToolSample(destPath) {
|
|
1950
1792
|
const fileService = new FileService();
|
|
1951
1793
|
await fileService.copyStarterFile("tools.ts", destPath);
|
|
1952
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
|
+
}
|
|
1953
1883
|
async function writeCodeSampleForComponents(llmprovider, component, destPath, importComponents) {
|
|
1954
1884
|
switch (component) {
|
|
1955
1885
|
case "agents":
|
|
1956
|
-
return writeAgentSample(
|
|
1886
|
+
return writeAgentSample(
|
|
1887
|
+
llmprovider,
|
|
1888
|
+
destPath,
|
|
1889
|
+
importComponents.includes("tools"),
|
|
1890
|
+
importComponents.includes("scorers")
|
|
1891
|
+
);
|
|
1957
1892
|
case "tools":
|
|
1958
1893
|
return writeToolSample(destPath);
|
|
1959
1894
|
case "workflows":
|
|
1960
1895
|
return writeWorkflowSample(destPath);
|
|
1896
|
+
case "scorers":
|
|
1897
|
+
return writeScorersSample(llmprovider, destPath);
|
|
1961
1898
|
default:
|
|
1962
1899
|
return "";
|
|
1963
1900
|
}
|
|
1964
1901
|
}
|
|
1965
1902
|
var createComponentsDir = async (dirPath, component) => {
|
|
1966
1903
|
const componentPath = dirPath + `/${component}`;
|
|
1967
|
-
await
|
|
1904
|
+
await fsExtra.ensureDir(componentPath);
|
|
1968
1905
|
};
|
|
1969
1906
|
var writeIndexFile = async ({
|
|
1970
1907
|
dirPath,
|
|
1971
1908
|
addAgent,
|
|
1972
1909
|
addExample,
|
|
1973
|
-
addWorkflow
|
|
1910
|
+
addWorkflow,
|
|
1911
|
+
addScorers
|
|
1974
1912
|
}) => {
|
|
1975
1913
|
const indexPath = dirPath + "/index.ts";
|
|
1976
1914
|
const destPath = path3.join(indexPath);
|
|
1977
1915
|
try {
|
|
1978
|
-
await
|
|
1916
|
+
await fs4.writeFile(destPath, "");
|
|
1979
1917
|
const filteredExports = [
|
|
1980
1918
|
addWorkflow ? `workflows: { weatherWorkflow },` : "",
|
|
1981
|
-
addAgent ? `agents: { weatherAgent },` : ""
|
|
1919
|
+
addAgent ? `agents: { weatherAgent },` : "",
|
|
1920
|
+
addScorers ? `scorers: { toolCallAppropriatenessScorer, completenessScorer, translationScorer },` : ""
|
|
1982
1921
|
].filter(Boolean);
|
|
1983
1922
|
if (!addExample) {
|
|
1984
|
-
await
|
|
1923
|
+
await fs4.writeFile(
|
|
1985
1924
|
destPath,
|
|
1986
1925
|
`
|
|
1987
|
-
import { Mastra } from '@mastra/core';
|
|
1926
|
+
import { Mastra } from '@mastra/core/mastra';
|
|
1988
1927
|
|
|
1989
1928
|
export const mastra = new Mastra()
|
|
1990
1929
|
`
|
|
1991
1930
|
);
|
|
1992
1931
|
return;
|
|
1993
1932
|
}
|
|
1994
|
-
await
|
|
1933
|
+
await fs4.writeFile(
|
|
1995
1934
|
destPath,
|
|
1996
1935
|
`
|
|
1997
1936
|
import { Mastra } from '@mastra/core/mastra';
|
|
1998
1937
|
import { PinoLogger } from '@mastra/loggers';
|
|
1999
1938
|
import { LibSQLStore } from '@mastra/libsql';
|
|
1939
|
+
import { Observability } from '@mastra/observability';
|
|
2000
1940
|
${addWorkflow ? `import { weatherWorkflow } from './workflows/weather-workflow';` : ""}
|
|
2001
1941
|
${addAgent ? `import { weatherAgent } from './agents/weather-agent';` : ""}
|
|
1942
|
+
${addScorers ? `import { toolCallAppropriatenessScorer, completenessScorer, translationScorer } from './scorers/weather-scorer';` : ""}
|
|
2002
1943
|
|
|
2003
1944
|
export const mastra = new Mastra({
|
|
2004
1945
|
${filteredExports.join("\n ")}
|
|
2005
1946
|
storage: new LibSQLStore({
|
|
2006
|
-
|
|
1947
|
+
id: "mastra-storage",
|
|
1948
|
+
// stores observability, scores, ... into memory storage, if it needs to persist, change to file:../mastra.db
|
|
2007
1949
|
url: ":memory:",
|
|
2008
1950
|
}),
|
|
2009
1951
|
logger: new PinoLogger({
|
|
2010
1952
|
name: 'Mastra',
|
|
2011
1953
|
level: 'info',
|
|
2012
1954
|
}),
|
|
1955
|
+
observability: new Observability({
|
|
1956
|
+
// Enables DefaultExporter and CloudExporter for tracing
|
|
1957
|
+
default: { enabled: true },
|
|
1958
|
+
}),
|
|
2013
1959
|
});
|
|
2014
1960
|
`
|
|
2015
1961
|
);
|
|
@@ -2017,7 +1963,6 @@ export const mastra = new Mastra({
|
|
|
2017
1963
|
throw err;
|
|
2018
1964
|
}
|
|
2019
1965
|
};
|
|
2020
|
-
yoctoSpinner({ text: "Installing Mastra core dependencies\n" });
|
|
2021
1966
|
var getAPIKey = async (provider) => {
|
|
2022
1967
|
let key = "OPENAI_API_KEY";
|
|
2023
1968
|
switch (provider) {
|
|
@@ -2033,27 +1978,28 @@ var getAPIKey = async (provider) => {
|
|
|
2033
1978
|
case "cerebras":
|
|
2034
1979
|
key = "CEREBRAS_API_KEY";
|
|
2035
1980
|
return key;
|
|
1981
|
+
case "mistral":
|
|
1982
|
+
key = "MISTRAL_API_KEY";
|
|
1983
|
+
return key;
|
|
2036
1984
|
default:
|
|
2037
1985
|
return key;
|
|
2038
1986
|
}
|
|
2039
1987
|
};
|
|
2040
|
-
var writeAPIKey = async ({
|
|
2041
|
-
|
|
2042
|
-
apiKey = "your-api-key"
|
|
2043
|
-
}) => {
|
|
1988
|
+
var writeAPIKey = async ({ provider, apiKey }) => {
|
|
1989
|
+
const envFileName = apiKey ? ".env" : ".env.example";
|
|
2044
1990
|
const key = await getAPIKey(provider);
|
|
2045
|
-
const escapedKey =
|
|
2046
|
-
const escapedApiKey =
|
|
2047
|
-
await
|
|
1991
|
+
const escapedKey = shellQuote2.quote([key]);
|
|
1992
|
+
const escapedApiKey = shellQuote2.quote([apiKey ? apiKey : "your-api-key"]);
|
|
1993
|
+
await exec(`echo ${escapedKey}=${escapedApiKey} >> ${envFileName}`);
|
|
2048
1994
|
};
|
|
2049
1995
|
var createMastraDir = async (directory) => {
|
|
2050
1996
|
let dir = directory.trim().split("/").filter((item) => item !== "");
|
|
2051
1997
|
const dirPath = path3.join(process.cwd(), ...dir, "mastra");
|
|
2052
1998
|
try {
|
|
2053
|
-
await
|
|
1999
|
+
await fs4.access(dirPath);
|
|
2054
2000
|
return { ok: false };
|
|
2055
2001
|
} catch {
|
|
2056
|
-
await
|
|
2002
|
+
await fsExtra.ensureDir(dirPath);
|
|
2057
2003
|
return { ok: true, dirPath };
|
|
2058
2004
|
}
|
|
2059
2005
|
};
|
|
@@ -2065,8 +2011,19 @@ var writeCodeSample = async (dirPath, component, llmProvider, importComponents)
|
|
|
2065
2011
|
throw err;
|
|
2066
2012
|
}
|
|
2067
2013
|
};
|
|
2068
|
-
var
|
|
2069
|
-
|
|
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
|
+
}
|
|
2070
2027
|
const mastraProject = await Ce(
|
|
2071
2028
|
{
|
|
2072
2029
|
directory: () => he({
|
|
@@ -2074,19 +2031,15 @@ var interactivePrompt = async () => {
|
|
|
2074
2031
|
placeholder: "src/",
|
|
2075
2032
|
defaultValue: "src/"
|
|
2076
2033
|
}),
|
|
2077
|
-
llmProvider: () => ve({
|
|
2078
|
-
message: "Select default provider:",
|
|
2079
|
-
options:
|
|
2080
|
-
{ value: "openai", label: "OpenAI", hint: "recommended" },
|
|
2081
|
-
{ value: "anthropic", label: "Anthropic" },
|
|
2082
|
-
{ value: "groq", label: "Groq" },
|
|
2083
|
-
{ value: "google", label: "Google" },
|
|
2084
|
-
{ value: "cerebras", label: "Cerebras" }
|
|
2085
|
-
]
|
|
2034
|
+
llmProvider: () => skip?.llmProvider ? void 0 : ve({
|
|
2035
|
+
message: "Select a default provider:",
|
|
2036
|
+
options: LLM_PROVIDERS
|
|
2086
2037
|
}),
|
|
2087
2038
|
llmApiKey: async ({ results: { llmProvider } }) => {
|
|
2039
|
+
if (skip?.llmApiKey) return void 0;
|
|
2040
|
+
const llmName = LLM_PROVIDERS.find((p6) => p6.value === llmProvider)?.label || "provider";
|
|
2088
2041
|
const keyChoice = await ve({
|
|
2089
|
-
message: `Enter your ${
|
|
2042
|
+
message: `Enter your ${llmName} API key?`,
|
|
2090
2043
|
options: [
|
|
2091
2044
|
{ value: "skip", label: "Skip for now", hint: "default" },
|
|
2092
2045
|
{ value: "enter", label: "Enter API key" }
|
|
@@ -2096,52 +2049,38 @@ var interactivePrompt = async () => {
|
|
|
2096
2049
|
if (keyChoice === "enter") {
|
|
2097
2050
|
return he({
|
|
2098
2051
|
message: "Enter your API key:",
|
|
2099
|
-
placeholder: "sk-..."
|
|
2052
|
+
placeholder: "sk-...",
|
|
2053
|
+
validate: (value) => {
|
|
2054
|
+
if (value.length === 0) return "API key cannot be empty";
|
|
2055
|
+
}
|
|
2100
2056
|
});
|
|
2101
2057
|
}
|
|
2102
2058
|
return void 0;
|
|
2103
2059
|
},
|
|
2104
2060
|
configureEditorWithDocsMCP: async () => {
|
|
2105
|
-
const windsurfIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`windsurf`);
|
|
2106
|
-
const cursorIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`cursor`);
|
|
2107
|
-
const vscodeIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`vscode`);
|
|
2108
2061
|
const editor = await ve({
|
|
2109
|
-
message: `Make your
|
|
2062
|
+
message: `Make your IDE into a Mastra expert? (Installs Mastra's MCP server)`,
|
|
2110
2063
|
options: [
|
|
2111
2064
|
{ value: "skip", label: "Skip for now", hint: "default" },
|
|
2112
2065
|
{
|
|
2113
2066
|
value: "cursor",
|
|
2114
|
-
label: "Cursor (project only)"
|
|
2115
|
-
hint: cursorIsAlreadyInstalled ? `Already installed globally` : void 0
|
|
2067
|
+
label: "Cursor (project only)"
|
|
2116
2068
|
},
|
|
2117
2069
|
{
|
|
2118
2070
|
value: "cursor-global",
|
|
2119
|
-
label: "Cursor (global, all projects)"
|
|
2120
|
-
hint: cursorIsAlreadyInstalled ? `Already installed` : void 0
|
|
2071
|
+
label: "Cursor (global, all projects)"
|
|
2121
2072
|
},
|
|
2122
2073
|
{
|
|
2123
2074
|
value: "windsurf",
|
|
2124
|
-
label: "Windsurf"
|
|
2125
|
-
hint: windsurfIsAlreadyInstalled ? `Already installed` : void 0
|
|
2075
|
+
label: "Windsurf"
|
|
2126
2076
|
},
|
|
2127
2077
|
{
|
|
2128
2078
|
value: "vscode",
|
|
2129
|
-
label: "VSCode"
|
|
2130
|
-
hint: vscodeIsAlreadyInstalled ? `Already installed` : void 0
|
|
2079
|
+
label: "VSCode"
|
|
2131
2080
|
}
|
|
2132
2081
|
]
|
|
2133
2082
|
});
|
|
2134
2083
|
if (editor === `skip`) return void 0;
|
|
2135
|
-
if (editor === `windsurf` && windsurfIsAlreadyInstalled) {
|
|
2136
|
-
M.message(`
|
|
2137
|
-
Windsurf is already installed, skipping.`);
|
|
2138
|
-
return void 0;
|
|
2139
|
-
}
|
|
2140
|
-
if (editor === `vscode` && vscodeIsAlreadyInstalled) {
|
|
2141
|
-
M.message(`
|
|
2142
|
-
VSCode is already installed, skipping.`);
|
|
2143
|
-
return void 0;
|
|
2144
|
-
}
|
|
2145
2084
|
if (editor === `cursor`) {
|
|
2146
2085
|
M.message(
|
|
2147
2086
|
`
|
|
@@ -2150,19 +2089,19 @@ Note: you will need to go into Cursor Settings -> MCP Settings and manually enab
|
|
|
2150
2089
|
);
|
|
2151
2090
|
}
|
|
2152
2091
|
if (editor === `cursor-global`) {
|
|
2153
|
-
const
|
|
2092
|
+
const confirm = await ve({
|
|
2154
2093
|
message: `Global install will add/update ${cursorGlobalMCPConfigPath} and make the Mastra docs MCP server available in all your Cursor projects. Continue?`,
|
|
2155
2094
|
options: [
|
|
2156
2095
|
{ value: "yes", label: "Yes, I understand" },
|
|
2157
2096
|
{ value: "skip", label: "No, skip for now" }
|
|
2158
2097
|
]
|
|
2159
2098
|
});
|
|
2160
|
-
if (
|
|
2099
|
+
if (confirm !== `yes`) {
|
|
2161
2100
|
return void 0;
|
|
2162
2101
|
}
|
|
2163
2102
|
}
|
|
2164
2103
|
if (editor === `windsurf`) {
|
|
2165
|
-
const
|
|
2104
|
+
const confirm = await ve({
|
|
2166
2105
|
message: `Windsurf only supports a global MCP config (at ${windsurfGlobalMCPConfigPath}) is it ok to add/update that global config?
|
|
2167
2106
|
This means the Mastra docs MCP server will be available in all your Windsurf projects.`,
|
|
2168
2107
|
options: [
|
|
@@ -2170,7 +2109,7 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2170
2109
|
{ value: "skip", label: "No, skip for now" }
|
|
2171
2110
|
]
|
|
2172
2111
|
});
|
|
2173
|
-
if (
|
|
2112
|
+
if (confirm !== `yes`) {
|
|
2174
2113
|
return void 0;
|
|
2175
2114
|
}
|
|
2176
2115
|
}
|
|
@@ -2186,17 +2125,230 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2186
2125
|
);
|
|
2187
2126
|
return mastraProject;
|
|
2188
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
|
+
}
|
|
2189
2340
|
var s = Y();
|
|
2190
|
-
var exec3 = util.promisify(child_process.exec);
|
|
2191
2341
|
var init = async ({
|
|
2192
|
-
directory,
|
|
2193
|
-
addExample = false,
|
|
2342
|
+
directory = "src/",
|
|
2194
2343
|
components,
|
|
2195
2344
|
llmProvider = "openai",
|
|
2196
2345
|
llmApiKey,
|
|
2197
|
-
|
|
2346
|
+
addExample = false,
|
|
2347
|
+
configureEditorWithDocsMCP,
|
|
2348
|
+
versionTag
|
|
2198
2349
|
}) => {
|
|
2199
2350
|
s.start("Initializing Mastra");
|
|
2351
|
+
const packageVersionTag = versionTag ? `@${versionTag}` : "";
|
|
2200
2352
|
try {
|
|
2201
2353
|
const result = await createMastraDir(directory);
|
|
2202
2354
|
if (!result.ok) {
|
|
@@ -2209,7 +2361,8 @@ var init = async ({
|
|
|
2209
2361
|
dirPath,
|
|
2210
2362
|
addExample,
|
|
2211
2363
|
addWorkflow: components.includes("workflows"),
|
|
2212
|
-
addAgent: components.includes("agents")
|
|
2364
|
+
addAgent: components.includes("agents"),
|
|
2365
|
+
addScorers: components.includes("scorers")
|
|
2213
2366
|
}),
|
|
2214
2367
|
...components.map((component) => createComponentsDir(dirPath, component)),
|
|
2215
2368
|
writeAPIKey({ provider: llmProvider, apiKey: llmApiKey })
|
|
@@ -2223,27 +2376,31 @@ var init = async ({
|
|
|
2223
2376
|
const depService = new DepsService();
|
|
2224
2377
|
const needsLibsql = await depService.checkDependencies(["@mastra/libsql"]) !== `ok`;
|
|
2225
2378
|
if (needsLibsql) {
|
|
2226
|
-
await depService.installPackages([
|
|
2379
|
+
await depService.installPackages([`@mastra/libsql${packageVersionTag}`]);
|
|
2227
2380
|
}
|
|
2228
2381
|
const needsMemory = components.includes(`agents`) && await depService.checkDependencies(["@mastra/memory"]) !== `ok`;
|
|
2229
2382
|
if (needsMemory) {
|
|
2230
|
-
await depService.installPackages([
|
|
2383
|
+
await depService.installPackages([`@mastra/memory${packageVersionTag}`]);
|
|
2231
2384
|
}
|
|
2232
2385
|
const needsLoggers = await depService.checkDependencies(["@mastra/loggers"]) !== `ok`;
|
|
2233
2386
|
if (needsLoggers) {
|
|
2234
|
-
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}`]);
|
|
2235
2396
|
}
|
|
2236
2397
|
}
|
|
2237
2398
|
const key = await getAPIKey(llmProvider || "openai");
|
|
2238
|
-
const aiSdkPackage = getAISDKPackage(llmProvider);
|
|
2239
|
-
const depsService = new DepsService();
|
|
2240
|
-
const pm = depsService.packageManager;
|
|
2241
|
-
const installCommand = getPackageManagerInstallCommand(pm);
|
|
2242
|
-
await exec3(`${pm} ${installCommand} ${aiSdkPackage}`);
|
|
2243
2399
|
if (configureEditorWithDocsMCP) {
|
|
2244
2400
|
await installMastraDocsMCPServer({
|
|
2245
2401
|
editor: configureEditorWithDocsMCP,
|
|
2246
|
-
directory: process.cwd()
|
|
2402
|
+
directory: process.cwd(),
|
|
2403
|
+
versionTag
|
|
2247
2404
|
});
|
|
2248
2405
|
}
|
|
2249
2406
|
s.stop();
|
|
@@ -2266,10 +2423,10 @@ var init = async ({
|
|
|
2266
2423
|
return { success: false };
|
|
2267
2424
|
}
|
|
2268
2425
|
};
|
|
2269
|
-
var
|
|
2426
|
+
var exec3 = util.promisify(child_process.exec);
|
|
2270
2427
|
var execWithTimeout = async (command, timeoutMs) => {
|
|
2271
2428
|
try {
|
|
2272
|
-
const promise =
|
|
2429
|
+
const promise = exec3(command, { killSignal: "SIGTERM" });
|
|
2273
2430
|
if (!timeoutMs) {
|
|
2274
2431
|
return await promise;
|
|
2275
2432
|
}
|
|
@@ -2292,10 +2449,36 @@ var execWithTimeout = async (command, timeoutMs) => {
|
|
|
2292
2449
|
throw error;
|
|
2293
2450
|
}
|
|
2294
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
|
+
}
|
|
2295
2478
|
async function installMastraDependency(pm, dependency, versionTag, isDev, timeout) {
|
|
2296
|
-
let installCommand =
|
|
2479
|
+
let installCommand = getPackageManagerAddCommand(pm);
|
|
2297
2480
|
if (isDev) {
|
|
2298
|
-
installCommand = `${installCommand}
|
|
2481
|
+
installCommand = `${installCommand} -D`;
|
|
2299
2482
|
}
|
|
2300
2483
|
try {
|
|
2301
2484
|
await execWithTimeout(`${pm} ${installCommand} ${dependency}${versionTag}`, timeout);
|
|
@@ -2317,23 +2500,42 @@ async function installMastraDependency(pm, dependency, versionTag, isDev, timeou
|
|
|
2317
2500
|
var createMastraProject = async ({
|
|
2318
2501
|
projectName: name,
|
|
2319
2502
|
createVersionTag,
|
|
2320
|
-
timeout
|
|
2503
|
+
timeout,
|
|
2504
|
+
llmProvider,
|
|
2505
|
+
llmApiKey,
|
|
2506
|
+
needsInteractive
|
|
2321
2507
|
}) => {
|
|
2322
2508
|
Ie(color2.inverse(" Mastra Create "));
|
|
2323
2509
|
const projectName = name ?? await he({
|
|
2324
2510
|
message: "What do you want to name your project?",
|
|
2325
2511
|
placeholder: "my-mastra-app",
|
|
2326
|
-
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
|
+
}
|
|
2327
2519
|
});
|
|
2328
2520
|
if (pD(projectName)) {
|
|
2329
2521
|
xe("Operation cancelled");
|
|
2330
2522
|
process.exit(0);
|
|
2331
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
|
+
}
|
|
2332
2531
|
const s2 = Y();
|
|
2532
|
+
const originalCwd = process.cwd();
|
|
2533
|
+
let projectPath = null;
|
|
2333
2534
|
try {
|
|
2334
2535
|
s2.start("Creating project");
|
|
2335
2536
|
try {
|
|
2336
|
-
await
|
|
2537
|
+
await fs4.mkdir(projectName);
|
|
2538
|
+
projectPath = path3.resolve(originalCwd, projectName);
|
|
2337
2539
|
} catch (error) {
|
|
2338
2540
|
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
2339
2541
|
s2.stop(`A directory named "${projectName}" already exists. Please choose a different name.`);
|
|
@@ -2345,12 +2547,10 @@ var createMastraProject = async ({
|
|
|
2345
2547
|
}
|
|
2346
2548
|
process.chdir(projectName);
|
|
2347
2549
|
const pm = getPackageManager();
|
|
2348
|
-
const installCommand =
|
|
2550
|
+
const installCommand = getPackageManagerAddCommand(pm);
|
|
2349
2551
|
s2.message("Initializing project structure");
|
|
2350
2552
|
try {
|
|
2351
|
-
await
|
|
2352
|
-
await exec4(`npm pkg set type="module"`);
|
|
2353
|
-
await exec4(`npm pkg set engines.node=">=20.9.0"`);
|
|
2553
|
+
await initializePackageJson(pm);
|
|
2354
2554
|
const depsService = new DepsService();
|
|
2355
2555
|
await depsService.addScriptsToPackageJson({
|
|
2356
2556
|
dev: "mastra dev",
|
|
@@ -2365,9 +2565,9 @@ var createMastraProject = async ({
|
|
|
2365
2565
|
s2.stop("Project structure created");
|
|
2366
2566
|
s2.start(`Installing ${pm} dependencies`);
|
|
2367
2567
|
try {
|
|
2368
|
-
await
|
|
2369
|
-
await
|
|
2370
|
-
await
|
|
2568
|
+
await exec3(`${pm} ${installCommand} zod@^4`);
|
|
2569
|
+
await exec3(`${pm} ${installCommand} -D typescript @types/node`);
|
|
2570
|
+
await exec3(`echo '{
|
|
2371
2571
|
"compilerOptions": {
|
|
2372
2572
|
"target": "ES2022",
|
|
2373
2573
|
"module": "ES2022",
|
|
@@ -2389,15 +2589,15 @@ var createMastraProject = async ({
|
|
|
2389
2589
|
);
|
|
2390
2590
|
}
|
|
2391
2591
|
s2.stop(`${pm} dependencies installed`);
|
|
2392
|
-
s2.start("Installing
|
|
2592
|
+
s2.start("Installing Mastra CLI");
|
|
2393
2593
|
const versionTag = createVersionTag ? `@${createVersionTag}` : "@latest";
|
|
2394
2594
|
try {
|
|
2395
2595
|
await installMastraDependency(pm, "mastra", versionTag, true, timeout);
|
|
2396
2596
|
} catch (error) {
|
|
2397
2597
|
throw new Error(`Failed to install Mastra CLI: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2398
2598
|
}
|
|
2399
|
-
s2.stop("
|
|
2400
|
-
s2.start("Installing dependencies");
|
|
2599
|
+
s2.stop("Mastra CLI installed");
|
|
2600
|
+
s2.start("Installing Mastra dependencies");
|
|
2401
2601
|
try {
|
|
2402
2602
|
await installMastraDependency(pm, "@mastra/core", versionTag, false, timeout);
|
|
2403
2603
|
await installMastraDependency(pm, "@mastra/libsql", versionTag, false, timeout);
|
|
@@ -2410,58 +2610,80 @@ var createMastraProject = async ({
|
|
|
2410
2610
|
s2.stop("Mastra dependencies installed");
|
|
2411
2611
|
s2.start("Adding .gitignore");
|
|
2412
2612
|
try {
|
|
2413
|
-
await
|
|
2414
|
-
await
|
|
2415
|
-
await
|
|
2416
|
-
await
|
|
2417
|
-
await
|
|
2418
|
-
await
|
|
2419
|
-
await
|
|
2420
|
-
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`);
|
|
2421
2621
|
} catch (error) {
|
|
2422
2622
|
throw new Error(`Failed to create .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2423
2623
|
}
|
|
2424
2624
|
s2.stop(".gitignore added");
|
|
2425
2625
|
Se("Project created successfully");
|
|
2426
|
-
console.
|
|
2427
|
-
return { projectName };
|
|
2626
|
+
console.info("");
|
|
2627
|
+
return { projectName, result };
|
|
2428
2628
|
} catch (error) {
|
|
2429
2629
|
s2.stop();
|
|
2430
2630
|
const errorMessage = error instanceof Error ? error.message : "An unexpected error occurred";
|
|
2431
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
|
+
}
|
|
2432
2642
|
process.exit(1);
|
|
2433
2643
|
}
|
|
2434
2644
|
};
|
|
2435
|
-
var
|
|
2436
|
-
|
|
2437
|
-
|
|
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
|
+
});
|
|
2438
2655
|
return;
|
|
2439
2656
|
}
|
|
2440
|
-
const
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
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
|
|
2444
2665
|
});
|
|
2445
|
-
const directory =
|
|
2446
|
-
if (
|
|
2447
|
-
const result = await interactivePrompt();
|
|
2666
|
+
const directory = args.directory || "src/";
|
|
2667
|
+
if (needsInteractive && result) {
|
|
2448
2668
|
await init({
|
|
2449
2669
|
...result,
|
|
2450
2670
|
llmApiKey: result?.llmApiKey,
|
|
2451
|
-
components: ["agents", "tools", "workflows"],
|
|
2452
|
-
addExample: true
|
|
2671
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2672
|
+
addExample: true,
|
|
2673
|
+
versionTag: args.createVersionTag
|
|
2453
2674
|
});
|
|
2454
2675
|
postCreate({ projectName });
|
|
2455
2676
|
return;
|
|
2456
2677
|
}
|
|
2457
|
-
const { components = [], llmProvider = "openai", addExample = false, llmApiKey } =
|
|
2678
|
+
const { components = [], llmProvider = "openai", addExample = false, llmApiKey } = args;
|
|
2458
2679
|
await init({
|
|
2459
2680
|
directory,
|
|
2460
2681
|
components,
|
|
2461
2682
|
llmProvider,
|
|
2462
2683
|
addExample,
|
|
2463
2684
|
llmApiKey,
|
|
2464
|
-
configureEditorWithDocsMCP:
|
|
2685
|
+
configureEditorWithDocsMCP: args.mcpServer,
|
|
2686
|
+
versionTag: args.createVersionTag
|
|
2465
2687
|
});
|
|
2466
2688
|
postCreate({ projectName });
|
|
2467
2689
|
};
|
|
@@ -2474,27 +2696,122 @@ var postCreate = ({ projectName }) => {
|
|
|
2474
2696
|
${color2.cyan(`${packageManager} run dev`)}
|
|
2475
2697
|
`);
|
|
2476
2698
|
};
|
|
2477
|
-
|
|
2478
|
-
|
|
2699
|
+
function isGitHubUrl(url) {
|
|
2700
|
+
try {
|
|
2701
|
+
const parsedUrl = new URL(url);
|
|
2702
|
+
return parsedUrl.hostname === "github.com" && parsedUrl.pathname.split("/").length >= 3;
|
|
2703
|
+
} catch {
|
|
2704
|
+
return false;
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2707
|
+
async function validateGitHubProject(githubUrl) {
|
|
2708
|
+
const errors = [];
|
|
2709
|
+
try {
|
|
2710
|
+
const urlParts = new URL(githubUrl).pathname.split("/").filter(Boolean);
|
|
2711
|
+
const owner = urlParts[0];
|
|
2712
|
+
const repo = urlParts[1]?.replace(".git", "");
|
|
2713
|
+
if (!owner || !repo) {
|
|
2714
|
+
throw new Error("Invalid GitHub URL format");
|
|
2715
|
+
}
|
|
2716
|
+
const branches = ["main", "master"];
|
|
2717
|
+
let packageJsonContent = null;
|
|
2718
|
+
let indexContent = null;
|
|
2719
|
+
for (const branch of branches) {
|
|
2720
|
+
try {
|
|
2721
|
+
const packageJsonUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/package.json`;
|
|
2722
|
+
const packageJsonResponse = await fetch(packageJsonUrl);
|
|
2723
|
+
if (packageJsonResponse.ok) {
|
|
2724
|
+
packageJsonContent = await packageJsonResponse.text();
|
|
2725
|
+
const indexUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/src/mastra/index.ts`;
|
|
2726
|
+
const indexResponse = await fetch(indexUrl);
|
|
2727
|
+
if (indexResponse.ok) {
|
|
2728
|
+
indexContent = await indexResponse.text();
|
|
2729
|
+
}
|
|
2730
|
+
break;
|
|
2731
|
+
}
|
|
2732
|
+
} catch {
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
if (!packageJsonContent) {
|
|
2736
|
+
errors.push("Could not fetch package.json from repository");
|
|
2737
|
+
return { isValid: false, errors };
|
|
2738
|
+
}
|
|
2739
|
+
try {
|
|
2740
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
2741
|
+
const hasMastraCore = packageJson.dependencies?.["@mastra/core"] || packageJson.devDependencies?.["@mastra/core"] || packageJson.peerDependencies?.["@mastra/core"];
|
|
2742
|
+
if (!hasMastraCore) {
|
|
2743
|
+
errors.push("Missing @mastra/core dependency in package.json");
|
|
2744
|
+
}
|
|
2745
|
+
} catch {
|
|
2746
|
+
errors.push("Invalid package.json format");
|
|
2747
|
+
}
|
|
2748
|
+
if (!indexContent) {
|
|
2749
|
+
errors.push("Missing src/mastra/index.ts file");
|
|
2750
|
+
} else {
|
|
2751
|
+
const hasMastraExport = indexContent.includes("export") && (indexContent.includes("new Mastra") || indexContent.includes("Mastra("));
|
|
2752
|
+
if (!hasMastraExport) {
|
|
2753
|
+
errors.push("src/mastra/index.ts does not export a Mastra instance");
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
return { isValid: errors.length === 0, errors };
|
|
2757
|
+
} catch (error) {
|
|
2758
|
+
errors.push(`Failed to validate GitHub repository: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2759
|
+
return { isValid: false, errors };
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
async function createFromGitHubUrl(url) {
|
|
2763
|
+
const urlParts = new URL(url).pathname.split("/").filter(Boolean);
|
|
2764
|
+
const owner = urlParts[0] || "unknown";
|
|
2765
|
+
const repo = urlParts[1] || "unknown";
|
|
2766
|
+
return {
|
|
2767
|
+
githubUrl: url,
|
|
2768
|
+
title: `${owner}/${repo}`,
|
|
2769
|
+
slug: repo,
|
|
2770
|
+
agents: [],
|
|
2771
|
+
mcp: [],
|
|
2772
|
+
tools: [],
|
|
2773
|
+
networks: [],
|
|
2774
|
+
workflows: []
|
|
2775
|
+
};
|
|
2776
|
+
}
|
|
2777
|
+
async function createFromTemplate(args) {
|
|
2479
2778
|
let selectedTemplate;
|
|
2480
|
-
if (
|
|
2481
|
-
|
|
2482
|
-
|
|
2779
|
+
if (args.template === true) {
|
|
2780
|
+
const templates = await loadTemplates();
|
|
2781
|
+
const selected = await selectTemplate(templates);
|
|
2782
|
+
if (!selected) {
|
|
2483
2783
|
M.info("No template selected. Exiting.");
|
|
2484
2784
|
return;
|
|
2485
2785
|
}
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
if (
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2786
|
+
selectedTemplate = selected;
|
|
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);
|
|
2792
|
+
if (!validation.isValid) {
|
|
2793
|
+
spinner4.stop("Validation failed");
|
|
2794
|
+
M.error("This does not appear to be a valid Mastra project:");
|
|
2795
|
+
validation.errors.forEach((error) => M.error(` - ${error}`));
|
|
2796
|
+
throw new Error("Invalid Mastra project");
|
|
2797
|
+
}
|
|
2798
|
+
spinner4.stop("Valid Mastra project \u2713");
|
|
2799
|
+
selectedTemplate = await createFromGitHubUrl(args.template);
|
|
2800
|
+
} else {
|
|
2801
|
+
const templates = await loadTemplates();
|
|
2802
|
+
const found = findTemplateByName(templates, args.template);
|
|
2803
|
+
if (!found) {
|
|
2804
|
+
M.error(`Template "${args.template}" not found. Available templates:`);
|
|
2805
|
+
templates.forEach((t) => M.info(` - ${t.title} (use: ${t.slug.replace("template-", "")})`));
|
|
2806
|
+
throw new Error(`Template "${args.template}" not found`);
|
|
2807
|
+
}
|
|
2808
|
+
selectedTemplate = found;
|
|
2492
2809
|
}
|
|
2493
2810
|
}
|
|
2494
2811
|
if (!selectedTemplate) {
|
|
2495
2812
|
throw new Error("No template selected");
|
|
2496
2813
|
}
|
|
2497
|
-
let projectName =
|
|
2814
|
+
let projectName = args.projectName;
|
|
2498
2815
|
if (!projectName) {
|
|
2499
2816
|
const defaultName = getDefaultProjectName(selectedTemplate);
|
|
2500
2817
|
const response = await he({
|
|
@@ -2508,22 +2825,62 @@ async function createFromTemplate(args2) {
|
|
|
2508
2825
|
}
|
|
2509
2826
|
projectName = response;
|
|
2510
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;
|
|
2511
2841
|
try {
|
|
2512
|
-
const analytics = getAnalytics();
|
|
2513
|
-
if (analytics)
|
|
2514
|
-
|
|
2842
|
+
const analytics = args.injectedAnalytics || getAnalytics();
|
|
2843
|
+
if (analytics) {
|
|
2844
|
+
analytics.trackEvent("cli_template_used", {
|
|
2845
|
+
template_slug: selectedTemplate.slug,
|
|
2846
|
+
template_title: selectedTemplate.title
|
|
2847
|
+
});
|
|
2848
|
+
if (llmProvider) {
|
|
2849
|
+
analytics.trackEvent("cli_model_provider_selected", {
|
|
2850
|
+
provider: llmProvider,
|
|
2851
|
+
selection_method: args.llmProvider ? "cli_args" : "interactive"
|
|
2852
|
+
});
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
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({
|
|
2515
2859
|
template: selectedTemplate,
|
|
2516
|
-
projectName
|
|
2860
|
+
projectName,
|
|
2861
|
+
branch,
|
|
2862
|
+
llmProvider
|
|
2517
2863
|
});
|
|
2518
2864
|
await installDependencies(projectPath);
|
|
2519
2865
|
Me(`
|
|
2520
2866
|
${color2.green("Mastra template installed!")}
|
|
2521
2867
|
|
|
2522
|
-
Add the necessary environment
|
|
2868
|
+
Add the necessary environment
|
|
2523
2869
|
variables in your ${color2.cyan(".env")} file
|
|
2524
2870
|
`);
|
|
2525
2871
|
postCreate({ projectName });
|
|
2526
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
|
+
}
|
|
2527
2884
|
M.error(`Failed to create project from template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2528
2885
|
throw error;
|
|
2529
2886
|
}
|
|
@@ -2533,13 +2890,13 @@ async function getPackageVersion() {
|
|
|
2533
2890
|
const __filename = fileURLToPath(import.meta.url);
|
|
2534
2891
|
const __dirname = dirname(__filename);
|
|
2535
2892
|
const pkgJsonPath = path3.join(__dirname, "..", "package.json");
|
|
2536
|
-
const content = await fsExtra.readJSON(pkgJsonPath);
|
|
2893
|
+
const content = await fsExtra$1.readJSON(pkgJsonPath);
|
|
2537
2894
|
return content.version;
|
|
2538
2895
|
}
|
|
2539
2896
|
async function getCreateVersionTag() {
|
|
2540
2897
|
try {
|
|
2541
2898
|
const pkgPath = fileURLToPath(import.meta.resolve("create-mastra/package.json"));
|
|
2542
|
-
const json = await fsExtra.readJSON(pkgPath);
|
|
2899
|
+
const json = await fsExtra$1.readJSON(pkgPath);
|
|
2543
2900
|
const { stdout } = await execa("npm", ["dist-tag", "create-mastra"]);
|
|
2544
2901
|
const tagLine = stdout.split("\n").find((distLine) => distLine.endsWith(`: ${json.version}`));
|
|
2545
2902
|
const tag = tagLine ? tagLine.split(":")[0].trim() : "latest";
|
|
@@ -2563,29 +2920,30 @@ program.version(`${version}`, "-v, --version").description(`create-mastra ${vers
|
|
|
2563
2920
|
analytics.trackCommand({
|
|
2564
2921
|
command: "version"
|
|
2565
2922
|
});
|
|
2566
|
-
console.
|
|
2923
|
+
console.info(`create-mastra ${version}`);
|
|
2567
2924
|
} catch {
|
|
2568
2925
|
}
|
|
2569
2926
|
});
|
|
2570
2927
|
program.name("create-mastra").description("Create a new Mastra project").argument("[project-name]", "Directory name of the project").option(
|
|
2571
2928
|
"-p, --project-name <string>",
|
|
2572
2929
|
"Project name that will be used in package.json and as the project directory name."
|
|
2573
|
-
).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(
|
|
2574
2931
|
"--template [template-name]",
|
|
2575
|
-
"Create project from a template (use template name or leave blank to select from list)"
|
|
2932
|
+
"Create project from a template (use template name, public GitHub URL, or leave blank to select from list)"
|
|
2576
2933
|
).action(async (projectNameArg, args) => {
|
|
2577
2934
|
const projectName = projectNameArg || args.projectName;
|
|
2578
2935
|
const timeout = args?.timeout ? args?.timeout === true ? 6e4 : parseInt(args?.timeout, 10) : void 0;
|
|
2579
2936
|
if (args.default) {
|
|
2580
2937
|
await create({
|
|
2581
|
-
components: ["agents", "tools", "workflows"],
|
|
2938
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2582
2939
|
llmProvider: "openai",
|
|
2583
2940
|
addExample: true,
|
|
2584
2941
|
createVersionTag,
|
|
2585
2942
|
timeout,
|
|
2586
2943
|
mcpServer: args.mcp,
|
|
2587
2944
|
directory: "src/",
|
|
2588
|
-
template: args.template
|
|
2945
|
+
template: args.template,
|
|
2946
|
+
analytics
|
|
2589
2947
|
});
|
|
2590
2948
|
return;
|
|
2591
2949
|
}
|
|
@@ -2593,13 +2951,14 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2593
2951
|
components: args.components ? args.components.split(",") : [],
|
|
2594
2952
|
llmProvider: args.llm,
|
|
2595
2953
|
addExample: args.example,
|
|
2596
|
-
llmApiKey: args
|
|
2954
|
+
llmApiKey: args.llmApiKey,
|
|
2597
2955
|
createVersionTag,
|
|
2598
2956
|
timeout,
|
|
2599
2957
|
projectName,
|
|
2600
2958
|
directory: args.dir,
|
|
2601
2959
|
mcpServer: args.mcp,
|
|
2602
|
-
template: args.template
|
|
2960
|
+
template: args.template,
|
|
2961
|
+
analytics
|
|
2603
2962
|
});
|
|
2604
2963
|
});
|
|
2605
2964
|
program.parse(process.argv);
|