create-mastra 0.0.0-fix-read-json-esm-20251009172143 → 0.0.0-fix-model-router-machine-cache-20251021232825
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 +69 -1
- package/README.md +10 -32
- package/dist/index.js +473 -341
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import * as
|
|
5
|
-
import
|
|
4
|
+
import * as fs3__default from 'node:fs';
|
|
5
|
+
import fs3__default__default, { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
6
|
import os from 'node:os';
|
|
7
|
-
import
|
|
7
|
+
import path, { dirname } from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { PostHog } from 'posthog-node';
|
|
10
10
|
import util, { stripVTControlCharacters } from 'node:util';
|
|
@@ -12,18 +12,18 @@ import y$1, { stdout, stdin } from 'node:process';
|
|
|
12
12
|
import * as g from 'node:readline';
|
|
13
13
|
import g__default from 'node:readline';
|
|
14
14
|
import { Writable } from 'node:stream';
|
|
15
|
-
import
|
|
15
|
+
import fs4 from 'node:fs/promises';
|
|
16
16
|
import child_process from 'node:child_process';
|
|
17
17
|
import tty from 'node:tty';
|
|
18
|
-
import pino from 'pino';
|
|
19
|
-
import pretty from 'pino-pretty';
|
|
20
|
-
import { execa } from 'execa';
|
|
21
18
|
import fsExtra, { readJSON, ensureFile, writeJSON } from 'fs-extra/esm';
|
|
22
19
|
import prettier from 'prettier';
|
|
20
|
+
import { execa } from 'execa';
|
|
21
|
+
import pino from 'pino';
|
|
22
|
+
import pretty from 'pino-pretty';
|
|
23
23
|
import fsExtra$1 from 'fs-extra';
|
|
24
24
|
|
|
25
25
|
var __filename = fileURLToPath(import.meta.url);
|
|
26
|
-
var __dirname =
|
|
26
|
+
var __dirname = path.dirname(__filename);
|
|
27
27
|
var analyticsInstance = null;
|
|
28
28
|
function getAnalytics() {
|
|
29
29
|
return analyticsInstance;
|
|
@@ -39,7 +39,7 @@ var PosthogAnalytics = class {
|
|
|
39
39
|
host = "https://app.posthog.com"
|
|
40
40
|
}) {
|
|
41
41
|
this.version = version;
|
|
42
|
-
const cliConfigPath =
|
|
42
|
+
const cliConfigPath = path.join(__dirname, "mastra-cli.json");
|
|
43
43
|
if (existsSync(cliConfigPath)) {
|
|
44
44
|
try {
|
|
45
45
|
const { distinctId, sessionId } = JSON.parse(readFileSync(cliConfigPath, "utf-8"));
|
|
@@ -67,7 +67,7 @@ var PosthogAnalytics = class {
|
|
|
67
67
|
}
|
|
68
68
|
writeCliConfig({ distinctId, sessionId }) {
|
|
69
69
|
try {
|
|
70
|
-
writeFileSync(
|
|
70
|
+
writeFileSync(path.join(__dirname, "mastra-cli.json"), JSON.stringify({ distinctId, sessionId }));
|
|
71
71
|
} catch {
|
|
72
72
|
}
|
|
73
73
|
}
|
|
@@ -422,7 +422,7 @@ ${color2.gray(d)} ${t}
|
|
|
422
422
|
`):process.stdout.write(`${w} ${l}
|
|
423
423
|
`),E(),s();};return {start:H,stop:N,message:(m="")=>{l=R(m??l);}}},Ce=async(t,n)=>{const r={},i=Object.keys(t);for(const s of i){const c=t[s],a=await c({results:r})?.catch(l=>{throw l});if(typeof n?.onCancel=="function"&&pD(a)){r[s]="canceled",n.onCancel({results:r});continue}r[s]=a;}return r};
|
|
424
424
|
|
|
425
|
-
var shellQuote
|
|
425
|
+
var shellQuote = {};
|
|
426
426
|
|
|
427
427
|
var quote;
|
|
428
428
|
var hasRequiredQuote;
|
|
@@ -688,16 +688,16 @@ function requireParse () {
|
|
|
688
688
|
var hasRequiredShellQuote;
|
|
689
689
|
|
|
690
690
|
function requireShellQuote () {
|
|
691
|
-
if (hasRequiredShellQuote) return shellQuote
|
|
691
|
+
if (hasRequiredShellQuote) return shellQuote;
|
|
692
692
|
hasRequiredShellQuote = 1;
|
|
693
693
|
|
|
694
|
-
shellQuote
|
|
695
|
-
shellQuote
|
|
696
|
-
return shellQuote
|
|
694
|
+
shellQuote.quote = requireQuote();
|
|
695
|
+
shellQuote.parse = requireParse();
|
|
696
|
+
return shellQuote;
|
|
697
697
|
}
|
|
698
698
|
|
|
699
699
|
var shellQuoteExports = requireShellQuote();
|
|
700
|
-
var
|
|
700
|
+
var shellQuote2 = /*@__PURE__*/getDefaultExportFromCjs(shellQuoteExports);
|
|
701
701
|
|
|
702
702
|
// eslint-disable-next-line no-warning-comments
|
|
703
703
|
// TODO: Use a better method when it's added to Node.js (https://github.com/nodejs/node/pull/40240)
|
|
@@ -724,13 +724,18 @@ const format = (open, close) => {
|
|
|
724
724
|
// Handle nested colors.
|
|
725
725
|
|
|
726
726
|
// We could have done this, but it's too slow (as of Node.js 22).
|
|
727
|
-
// return openCode + string.replaceAll(closeCode, openCode) + closeCode;
|
|
727
|
+
// return openCode + string.replaceAll(closeCode, (close === 22 ? closeCode : '') + openCode) + closeCode;
|
|
728
728
|
|
|
729
729
|
let result = openCode;
|
|
730
730
|
let lastIndex = 0;
|
|
731
731
|
|
|
732
|
+
// SGR 22 resets both bold (1) and dim (2). When we encounter a nested
|
|
733
|
+
// close for styles that use 22, we need to re-open the outer style.
|
|
734
|
+
const reopenOnNestedClose = close === 22;
|
|
735
|
+
const replaceCode = (reopenOnNestedClose ? closeCode : '') + openCode;
|
|
736
|
+
|
|
732
737
|
while (index !== -1) {
|
|
733
|
-
result += string.slice(lastIndex, index) +
|
|
738
|
+
result += string.slice(lastIndex, index) + replaceCode;
|
|
734
739
|
lastIndex = index + closeCode.length;
|
|
735
740
|
index = string.indexOf(closeCode, lastIndex);
|
|
736
741
|
}
|
|
@@ -1173,279 +1178,6 @@ var PinoLogger = class extends MastraLogger {
|
|
|
1173
1178
|
}
|
|
1174
1179
|
};
|
|
1175
1180
|
|
|
1176
|
-
function getPackageManager() {
|
|
1177
|
-
const userAgent = process.env.npm_config_user_agent || "";
|
|
1178
|
-
const execPath = process.env.npm_execpath || "";
|
|
1179
|
-
if (userAgent.includes("yarn")) {
|
|
1180
|
-
return "yarn";
|
|
1181
|
-
}
|
|
1182
|
-
if (userAgent.includes("pnpm")) {
|
|
1183
|
-
return "pnpm";
|
|
1184
|
-
}
|
|
1185
|
-
if (userAgent.includes("npm")) {
|
|
1186
|
-
return "npm";
|
|
1187
|
-
}
|
|
1188
|
-
if (execPath.includes("yarn")) {
|
|
1189
|
-
return "yarn";
|
|
1190
|
-
}
|
|
1191
|
-
if (execPath.includes("pnpm")) {
|
|
1192
|
-
return "pnpm";
|
|
1193
|
-
}
|
|
1194
|
-
if (execPath.includes("npm")) {
|
|
1195
|
-
return "npm";
|
|
1196
|
-
}
|
|
1197
|
-
return "npm";
|
|
1198
|
-
}
|
|
1199
|
-
var logger = new PinoLogger({
|
|
1200
|
-
name: "Mastra CLI",
|
|
1201
|
-
level: "info"
|
|
1202
|
-
});
|
|
1203
|
-
var exec = util.promisify(child_process.exec);
|
|
1204
|
-
async function cloneTemplate(options) {
|
|
1205
|
-
const { template, projectName, targetDir } = options;
|
|
1206
|
-
const projectPath = targetDir ? path3.resolve(targetDir, projectName) : path3.resolve(projectName);
|
|
1207
|
-
const spinner5 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
|
|
1208
|
-
try {
|
|
1209
|
-
if (await directoryExists(projectPath)) {
|
|
1210
|
-
spinner5.error(`Directory ${projectName} already exists`);
|
|
1211
|
-
throw new Error(`Directory ${projectName} already exists`);
|
|
1212
|
-
}
|
|
1213
|
-
await cloneRepositoryWithoutGit(template.githubUrl, projectPath);
|
|
1214
|
-
await updatePackageJson(projectPath, projectName);
|
|
1215
|
-
const envExamplePath = path3.join(projectPath, ".env.example");
|
|
1216
|
-
if (await fileExists(envExamplePath)) {
|
|
1217
|
-
await fs5.copyFile(envExamplePath, path3.join(projectPath, ".env"));
|
|
1218
|
-
}
|
|
1219
|
-
spinner5.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
1220
|
-
return projectPath;
|
|
1221
|
-
} catch (error) {
|
|
1222
|
-
spinner5.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1223
|
-
throw error;
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
async function directoryExists(dirPath) {
|
|
1227
|
-
try {
|
|
1228
|
-
const stat = await fs5.stat(dirPath);
|
|
1229
|
-
return stat.isDirectory();
|
|
1230
|
-
} catch {
|
|
1231
|
-
return false;
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
async function fileExists(filePath) {
|
|
1235
|
-
try {
|
|
1236
|
-
const stat = await fs5.stat(filePath);
|
|
1237
|
-
return stat.isFile();
|
|
1238
|
-
} catch {
|
|
1239
|
-
return false;
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
async function cloneRepositoryWithoutGit(repoUrl, targetPath) {
|
|
1243
|
-
await fs5.mkdir(targetPath, { recursive: true });
|
|
1244
|
-
try {
|
|
1245
|
-
const degitRepo = repoUrl.replace("https://github.com/", "");
|
|
1246
|
-
const degitCommand = shellQuote.quote(["npx", "degit", degitRepo, targetPath]);
|
|
1247
|
-
await exec(degitCommand, {
|
|
1248
|
-
cwd: process.cwd()
|
|
1249
|
-
});
|
|
1250
|
-
} catch {
|
|
1251
|
-
try {
|
|
1252
|
-
const gitCommand = shellQuote.quote(["git", "clone", repoUrl, targetPath]);
|
|
1253
|
-
await exec(gitCommand, {
|
|
1254
|
-
cwd: process.cwd()
|
|
1255
|
-
});
|
|
1256
|
-
const gitDir = path3.join(targetPath, ".git");
|
|
1257
|
-
if (await directoryExists(gitDir)) {
|
|
1258
|
-
await fs5.rm(gitDir, { recursive: true, force: true });
|
|
1259
|
-
}
|
|
1260
|
-
} catch (gitError) {
|
|
1261
|
-
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
async function updatePackageJson(projectPath, projectName) {
|
|
1266
|
-
const packageJsonPath = path3.join(projectPath, "package.json");
|
|
1267
|
-
try {
|
|
1268
|
-
const packageJsonContent = await fs5.readFile(packageJsonPath, "utf-8");
|
|
1269
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
1270
|
-
packageJson.name = projectName;
|
|
1271
|
-
await fs5.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
1272
|
-
} catch (error) {
|
|
1273
|
-
logger.warn(`Could not update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
async function installDependencies(projectPath, packageManager) {
|
|
1277
|
-
const spinner5 = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
1278
|
-
try {
|
|
1279
|
-
const pm = packageManager || getPackageManager();
|
|
1280
|
-
const installCommand = shellQuote.quote([pm, "install"]);
|
|
1281
|
-
await exec(installCommand, {
|
|
1282
|
-
cwd: projectPath
|
|
1283
|
-
});
|
|
1284
|
-
spinner5.success("Dependencies installed successfully");
|
|
1285
|
-
} catch (error) {
|
|
1286
|
-
spinner5.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1287
|
-
throw error;
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
|
|
1291
|
-
async function loadTemplates() {
|
|
1292
|
-
try {
|
|
1293
|
-
const response = await fetch(TEMPLATES_API_URL);
|
|
1294
|
-
if (!response.ok) {
|
|
1295
|
-
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
1296
|
-
}
|
|
1297
|
-
const templates = await response.json();
|
|
1298
|
-
return templates;
|
|
1299
|
-
} catch (error) {
|
|
1300
|
-
console.error("Error loading templates:", error);
|
|
1301
|
-
throw new Error("Failed to load templates. Please check your internet connection and try again.");
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
function pluralize(count, singular, plural) {
|
|
1305
|
-
return count === 1 ? singular : plural || `${singular}s`;
|
|
1306
|
-
}
|
|
1307
|
-
async function selectTemplate(templates) {
|
|
1308
|
-
const choices = templates.map((template) => {
|
|
1309
|
-
const parts = [];
|
|
1310
|
-
if (template.agents?.length) {
|
|
1311
|
-
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
|
|
1312
|
-
}
|
|
1313
|
-
if (template.tools?.length) {
|
|
1314
|
-
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
|
|
1315
|
-
}
|
|
1316
|
-
if (template.workflows?.length) {
|
|
1317
|
-
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
|
|
1318
|
-
}
|
|
1319
|
-
if (template.mcp?.length) {
|
|
1320
|
-
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
|
|
1321
|
-
}
|
|
1322
|
-
if (template.networks?.length) {
|
|
1323
|
-
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
|
|
1324
|
-
}
|
|
1325
|
-
return {
|
|
1326
|
-
value: template,
|
|
1327
|
-
label: template.title,
|
|
1328
|
-
hint: parts.join(", ") || "Template components"
|
|
1329
|
-
};
|
|
1330
|
-
});
|
|
1331
|
-
const selected = await ve({
|
|
1332
|
-
message: "Select a template:",
|
|
1333
|
-
options: choices
|
|
1334
|
-
});
|
|
1335
|
-
if (pD(selected)) {
|
|
1336
|
-
return null;
|
|
1337
|
-
}
|
|
1338
|
-
return selected;
|
|
1339
|
-
}
|
|
1340
|
-
function findTemplateByName(templates, templateName) {
|
|
1341
|
-
let template = templates.find((t) => t.slug === templateName);
|
|
1342
|
-
if (template) return template;
|
|
1343
|
-
const slugWithPrefix = `template-${templateName}`;
|
|
1344
|
-
template = templates.find((t) => t.slug === slugWithPrefix);
|
|
1345
|
-
if (template) return template;
|
|
1346
|
-
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
|
|
1347
|
-
if (template) return template;
|
|
1348
|
-
return null;
|
|
1349
|
-
}
|
|
1350
|
-
function getDefaultProjectName(template) {
|
|
1351
|
-
return template.slug.replace(/^template-/, "");
|
|
1352
|
-
}
|
|
1353
|
-
function getPackageManagerAddCommand(pm) {
|
|
1354
|
-
switch (pm) {
|
|
1355
|
-
case "npm":
|
|
1356
|
-
return "install --audit=false --fund=false --loglevel=error --progress=false --update-notifier=false";
|
|
1357
|
-
case "yarn":
|
|
1358
|
-
return "add";
|
|
1359
|
-
case "pnpm":
|
|
1360
|
-
return "add --loglevel=error";
|
|
1361
|
-
case "bun":
|
|
1362
|
-
return "add";
|
|
1363
|
-
default:
|
|
1364
|
-
return "add";
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
var DepsService = class {
|
|
1368
|
-
packageManager;
|
|
1369
|
-
constructor() {
|
|
1370
|
-
this.packageManager = this.getPackageManager();
|
|
1371
|
-
}
|
|
1372
|
-
findLockFile(dir) {
|
|
1373
|
-
const lockFiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock"];
|
|
1374
|
-
for (const file of lockFiles) {
|
|
1375
|
-
if (fs4__default__default.existsSync(path3.join(dir, file))) {
|
|
1376
|
-
return file;
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
const parentDir = path3.resolve(dir, "..");
|
|
1380
|
-
if (parentDir !== dir) {
|
|
1381
|
-
return this.findLockFile(parentDir);
|
|
1382
|
-
}
|
|
1383
|
-
return null;
|
|
1384
|
-
}
|
|
1385
|
-
getPackageManager() {
|
|
1386
|
-
const lockFile = this.findLockFile(process.cwd());
|
|
1387
|
-
switch (lockFile) {
|
|
1388
|
-
case "pnpm-lock.yaml":
|
|
1389
|
-
return "pnpm";
|
|
1390
|
-
case "package-lock.json":
|
|
1391
|
-
return "npm";
|
|
1392
|
-
case "yarn.lock":
|
|
1393
|
-
return "yarn";
|
|
1394
|
-
case "bun.lock":
|
|
1395
|
-
return "bun";
|
|
1396
|
-
default:
|
|
1397
|
-
return "npm";
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
async installPackages(packages) {
|
|
1401
|
-
const pm = this.packageManager;
|
|
1402
|
-
const installCommand = getPackageManagerAddCommand(pm);
|
|
1403
|
-
const packageList = packages.join(" ");
|
|
1404
|
-
return execa(`${pm} ${installCommand} ${packageList}`, {
|
|
1405
|
-
all: true,
|
|
1406
|
-
shell: true,
|
|
1407
|
-
stdio: "inherit"
|
|
1408
|
-
});
|
|
1409
|
-
}
|
|
1410
|
-
async checkDependencies(dependencies) {
|
|
1411
|
-
try {
|
|
1412
|
-
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1413
|
-
try {
|
|
1414
|
-
await fs5.access(packageJsonPath);
|
|
1415
|
-
} catch {
|
|
1416
|
-
return "No package.json file found in the current directory";
|
|
1417
|
-
}
|
|
1418
|
-
const packageJson = JSON.parse(await fs5.readFile(packageJsonPath, "utf-8"));
|
|
1419
|
-
for (const dependency of dependencies) {
|
|
1420
|
-
if (!packageJson.dependencies || !packageJson.dependencies[dependency]) {
|
|
1421
|
-
return `Please install ${dependency} before running this command (${this.packageManager} install ${dependency})`;
|
|
1422
|
-
}
|
|
1423
|
-
}
|
|
1424
|
-
return "ok";
|
|
1425
|
-
} catch (err) {
|
|
1426
|
-
console.error(err);
|
|
1427
|
-
return "Could not check dependencies";
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1430
|
-
async getProjectName() {
|
|
1431
|
-
try {
|
|
1432
|
-
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1433
|
-
const packageJson = await fs5.readFile(packageJsonPath, "utf-8");
|
|
1434
|
-
const pkg = JSON.parse(packageJson);
|
|
1435
|
-
return pkg.name;
|
|
1436
|
-
} catch (err) {
|
|
1437
|
-
throw err;
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
async addScriptsToPackageJson(scripts) {
|
|
1441
|
-
const packageJson = JSON.parse(await fs5.readFile("package.json", "utf-8"));
|
|
1442
|
-
packageJson.scripts = {
|
|
1443
|
-
...packageJson.scripts,
|
|
1444
|
-
...scripts
|
|
1445
|
-
};
|
|
1446
|
-
await fs5.writeFile("package.json", JSON.stringify(packageJson, null, 2));
|
|
1447
|
-
}
|
|
1448
|
-
};
|
|
1449
1181
|
var args = ["-y", "@mastra/mcp-docs-server"];
|
|
1450
1182
|
var createMcpConfig = (editor) => {
|
|
1451
1183
|
if (editor === "vscode") {
|
|
@@ -1498,19 +1230,19 @@ async function writeMergedConfig(configPath, editor) {
|
|
|
1498
1230
|
spaces: 2
|
|
1499
1231
|
});
|
|
1500
1232
|
}
|
|
1501
|
-
var windsurfGlobalMCPConfigPath =
|
|
1502
|
-
var cursorGlobalMCPConfigPath =
|
|
1503
|
-
|
|
1504
|
-
var vscodeGlobalMCPConfigPath =
|
|
1233
|
+
var windsurfGlobalMCPConfigPath = path.join(os.homedir(), ".codeium", "windsurf", "mcp_config.json");
|
|
1234
|
+
var cursorGlobalMCPConfigPath = path.join(os.homedir(), ".cursor", "mcp.json");
|
|
1235
|
+
path.join(process.cwd(), ".vscode", "mcp.json");
|
|
1236
|
+
var vscodeGlobalMCPConfigPath = path.join(
|
|
1505
1237
|
os.homedir(),
|
|
1506
|
-
process.platform === "win32" ?
|
|
1238
|
+
process.platform === "win32" ? path.join("AppData", "Roaming", "Code", "User", "settings.json") : process.platform === "darwin" ? path.join("Library", "Application Support", "Code", "User", "settings.json") : path.join(".config", "Code", "User", "settings.json")
|
|
1507
1239
|
);
|
|
1508
1240
|
async function installMastraDocsMCPServer({ editor, directory }) {
|
|
1509
1241
|
if (editor === `cursor`) {
|
|
1510
|
-
await writeMergedConfig(
|
|
1242
|
+
await writeMergedConfig(path.join(directory, ".cursor", "mcp.json"), "cursor");
|
|
1511
1243
|
}
|
|
1512
1244
|
if (editor === `vscode`) {
|
|
1513
|
-
await writeMergedConfig(
|
|
1245
|
+
await writeMergedConfig(path.join(directory, ".vscode", "mcp.json"), "vscode");
|
|
1514
1246
|
}
|
|
1515
1247
|
if (editor === `cursor-global`) {
|
|
1516
1248
|
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor);
|
|
@@ -1558,17 +1290,113 @@ async function globalMCPIsAlreadyInstalled(editor) {
|
|
|
1558
1290
|
return false;
|
|
1559
1291
|
}
|
|
1560
1292
|
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1293
|
+
function getPackageManagerAddCommand(pm) {
|
|
1294
|
+
switch (pm) {
|
|
1295
|
+
case "npm":
|
|
1296
|
+
return "install --audit=false --fund=false --loglevel=error --progress=false --update-notifier=false";
|
|
1297
|
+
case "yarn":
|
|
1298
|
+
return "add";
|
|
1299
|
+
case "pnpm":
|
|
1300
|
+
return "add --loglevel=error";
|
|
1301
|
+
case "bun":
|
|
1302
|
+
return "add";
|
|
1303
|
+
default:
|
|
1304
|
+
return "add";
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
var DepsService = class {
|
|
1308
|
+
packageManager;
|
|
1309
|
+
constructor() {
|
|
1310
|
+
this.packageManager = this.getPackageManager();
|
|
1311
|
+
}
|
|
1312
|
+
findLockFile(dir) {
|
|
1313
|
+
const lockFiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock"];
|
|
1314
|
+
for (const file of lockFiles) {
|
|
1315
|
+
if (fs3__default__default.existsSync(path.join(dir, file))) {
|
|
1316
|
+
return file;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
const parentDir = path.resolve(dir, "..");
|
|
1320
|
+
if (parentDir !== dir) {
|
|
1321
|
+
return this.findLockFile(parentDir);
|
|
1322
|
+
}
|
|
1323
|
+
return null;
|
|
1324
|
+
}
|
|
1325
|
+
getPackageManager() {
|
|
1326
|
+
const lockFile = this.findLockFile(process.cwd());
|
|
1327
|
+
switch (lockFile) {
|
|
1328
|
+
case "pnpm-lock.yaml":
|
|
1329
|
+
return "pnpm";
|
|
1330
|
+
case "package-lock.json":
|
|
1331
|
+
return "npm";
|
|
1332
|
+
case "yarn.lock":
|
|
1333
|
+
return "yarn";
|
|
1334
|
+
case "bun.lock":
|
|
1335
|
+
return "bun";
|
|
1336
|
+
default:
|
|
1337
|
+
return "npm";
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
async installPackages(packages) {
|
|
1341
|
+
const pm = this.packageManager;
|
|
1342
|
+
const installCommand = getPackageManagerAddCommand(pm);
|
|
1343
|
+
const packageList = packages.join(" ");
|
|
1344
|
+
return execa(`${pm} ${installCommand} ${packageList}`, {
|
|
1345
|
+
all: true,
|
|
1346
|
+
shell: true,
|
|
1347
|
+
stdio: "inherit"
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
async checkDependencies(dependencies) {
|
|
1351
|
+
try {
|
|
1352
|
+
const packageJsonPath = path.join(process.cwd(), "package.json");
|
|
1353
|
+
try {
|
|
1354
|
+
await fs4.access(packageJsonPath);
|
|
1355
|
+
} catch {
|
|
1356
|
+
return "No package.json file found in the current directory";
|
|
1357
|
+
}
|
|
1358
|
+
const packageJson = JSON.parse(await fs4.readFile(packageJsonPath, "utf-8"));
|
|
1359
|
+
for (const dependency of dependencies) {
|
|
1360
|
+
if (!packageJson.dependencies || !packageJson.dependencies[dependency]) {
|
|
1361
|
+
return `Please install ${dependency} before running this command (${this.packageManager} install ${dependency})`;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
return "ok";
|
|
1365
|
+
} catch (err) {
|
|
1366
|
+
console.error(err);
|
|
1367
|
+
return "Could not check dependencies";
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
async getProjectName() {
|
|
1371
|
+
try {
|
|
1372
|
+
const packageJsonPath = path.join(process.cwd(), "package.json");
|
|
1373
|
+
const packageJson = await fs4.readFile(packageJsonPath, "utf-8");
|
|
1374
|
+
const pkg = JSON.parse(packageJson);
|
|
1375
|
+
return pkg.name;
|
|
1376
|
+
} catch (err) {
|
|
1377
|
+
throw err;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
async addScriptsToPackageJson(scripts) {
|
|
1381
|
+
const packageJson = JSON.parse(await fs4.readFile("package.json", "utf-8"));
|
|
1382
|
+
packageJson.scripts = {
|
|
1383
|
+
...packageJson.scripts,
|
|
1384
|
+
...scripts
|
|
1385
|
+
};
|
|
1386
|
+
await fs4.writeFile("package.json", JSON.stringify(packageJson, null, 2));
|
|
1387
|
+
}
|
|
1388
|
+
};
|
|
1389
|
+
var EnvService = class {
|
|
1390
|
+
};
|
|
1391
|
+
var FileEnvService = class extends EnvService {
|
|
1392
|
+
filePath;
|
|
1393
|
+
constructor(filePath) {
|
|
1566
1394
|
super();
|
|
1567
1395
|
this.filePath = filePath;
|
|
1568
1396
|
}
|
|
1569
1397
|
readFile(filePath) {
|
|
1570
1398
|
return new Promise((resolve, reject) => {
|
|
1571
|
-
|
|
1399
|
+
fs3__default.readFile(filePath, "utf8", (err, data) => {
|
|
1572
1400
|
if (err) reject(err);
|
|
1573
1401
|
else resolve(data);
|
|
1574
1402
|
});
|
|
@@ -1576,7 +1404,7 @@ var FileEnvService = class extends EnvService {
|
|
|
1576
1404
|
}
|
|
1577
1405
|
writeFile({ filePath, data }) {
|
|
1578
1406
|
return new Promise((resolve, reject) => {
|
|
1579
|
-
|
|
1407
|
+
fs3__default.writeFile(filePath, data, "utf8", (err) => {
|
|
1580
1408
|
if (err) reject(err);
|
|
1581
1409
|
else resolve();
|
|
1582
1410
|
});
|
|
@@ -1629,10 +1457,10 @@ var FileService = class {
|
|
|
1629
1457
|
*/
|
|
1630
1458
|
async copyStarterFile(inputFile, outputFilePath, replaceIfExists) {
|
|
1631
1459
|
const __filename = fileURLToPath(import.meta.url);
|
|
1632
|
-
const __dirname =
|
|
1633
|
-
const filePath =
|
|
1634
|
-
const fileString =
|
|
1635
|
-
if (
|
|
1460
|
+
const __dirname = path.dirname(__filename);
|
|
1461
|
+
const filePath = path.resolve(__dirname, "starter-files", inputFile);
|
|
1462
|
+
const fileString = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1463
|
+
if (fs3__default__default.existsSync(outputFilePath) && !replaceIfExists) {
|
|
1636
1464
|
console.info(`${outputFilePath} already exists`);
|
|
1637
1465
|
return false;
|
|
1638
1466
|
}
|
|
@@ -1640,14 +1468,14 @@ var FileService = class {
|
|
|
1640
1468
|
return true;
|
|
1641
1469
|
}
|
|
1642
1470
|
async setupEnvFile({ dbUrl }) {
|
|
1643
|
-
const envPath =
|
|
1471
|
+
const envPath = path.join(process.cwd(), ".env.development");
|
|
1644
1472
|
await fsExtra.ensureFile(envPath);
|
|
1645
1473
|
const fileEnvService = new FileEnvService(envPath);
|
|
1646
1474
|
await fileEnvService.setEnvValue("DB_URL", dbUrl);
|
|
1647
1475
|
}
|
|
1648
1476
|
getFirstExistingFile(files) {
|
|
1649
1477
|
for (const f of files) {
|
|
1650
|
-
if (
|
|
1478
|
+
if (fs3__default__default.existsSync(f)) {
|
|
1651
1479
|
return f;
|
|
1652
1480
|
}
|
|
1653
1481
|
}
|
|
@@ -1657,19 +1485,19 @@ var FileService = class {
|
|
|
1657
1485
|
filePath,
|
|
1658
1486
|
replacements
|
|
1659
1487
|
}) {
|
|
1660
|
-
let fileContent =
|
|
1488
|
+
let fileContent = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1661
1489
|
replacements.forEach(({ search, replace }) => {
|
|
1662
1490
|
fileContent = fileContent.replaceAll(search, replace);
|
|
1663
1491
|
});
|
|
1664
|
-
|
|
1492
|
+
fs3__default__default.writeFileSync(filePath, fileContent);
|
|
1665
1493
|
}
|
|
1666
1494
|
};
|
|
1667
|
-
var
|
|
1495
|
+
var exec = util.promisify(child_process.exec);
|
|
1668
1496
|
var getModelIdentifier = (llmProvider) => {
|
|
1669
1497
|
if (llmProvider === "openai") {
|
|
1670
1498
|
return `'openai/gpt-4o-mini'`;
|
|
1671
1499
|
} else if (llmProvider === "anthropic") {
|
|
1672
|
-
return `'anthropic/claude-
|
|
1500
|
+
return `'anthropic/claude-sonnet-4-5-20250929'`;
|
|
1673
1501
|
} else if (llmProvider === "groq") {
|
|
1674
1502
|
return `'groq/llama-3.3-70b-versatile'`;
|
|
1675
1503
|
} else if (llmProvider === "google") {
|
|
@@ -1680,7 +1508,7 @@ var getModelIdentifier = (llmProvider) => {
|
|
|
1680
1508
|
return `'mistral/mistral-medium-2508'`;
|
|
1681
1509
|
}
|
|
1682
1510
|
};
|
|
1683
|
-
async function writeAgentSample(llmProvider, destPath, addExampleTool) {
|
|
1511
|
+
async function writeAgentSample(llmProvider, destPath, addExampleTool, addScorers) {
|
|
1684
1512
|
const modelString = getModelIdentifier(llmProvider);
|
|
1685
1513
|
const instructions = `
|
|
1686
1514
|
You are a helpful weather assistant that provides accurate weather information and can help planning activities based on the weather.
|
|
@@ -1701,12 +1529,36 @@ import { Agent } from '@mastra/core/agent';
|
|
|
1701
1529
|
import { Memory } from '@mastra/memory';
|
|
1702
1530
|
import { LibSQLStore } from '@mastra/libsql';
|
|
1703
1531
|
${addExampleTool ? `import { weatherTool } from '../tools/weather-tool';` : ""}
|
|
1532
|
+
${addScorers ? `import { scorers } from '../scorers/weather-scorer';` : ""}
|
|
1704
1533
|
|
|
1705
1534
|
export const weatherAgent = new Agent({
|
|
1706
1535
|
name: 'Weather Agent',
|
|
1707
1536
|
instructions: \`${instructions}\`,
|
|
1708
1537
|
model: ${modelString},
|
|
1709
1538
|
${addExampleTool ? "tools: { weatherTool }," : ""}
|
|
1539
|
+
${addScorers ? `scorers: {
|
|
1540
|
+
toolCallAppropriateness: {
|
|
1541
|
+
scorer: scorers.toolCallAppropriatenessScorer,
|
|
1542
|
+
sampling: {
|
|
1543
|
+
type: 'ratio',
|
|
1544
|
+
rate: 1,
|
|
1545
|
+
},
|
|
1546
|
+
},
|
|
1547
|
+
completeness: {
|
|
1548
|
+
scorer: scorers.completenessScorer,
|
|
1549
|
+
sampling: {
|
|
1550
|
+
type: 'ratio',
|
|
1551
|
+
rate: 1,
|
|
1552
|
+
},
|
|
1553
|
+
},
|
|
1554
|
+
translation: {
|
|
1555
|
+
scorer: scorers.translationScorer,
|
|
1556
|
+
sampling: {
|
|
1557
|
+
type: 'ratio',
|
|
1558
|
+
rate: 1,
|
|
1559
|
+
},
|
|
1560
|
+
},
|
|
1561
|
+
},` : ""}
|
|
1710
1562
|
memory: new Memory({
|
|
1711
1563
|
storage: new LibSQLStore({
|
|
1712
1564
|
url: "file:../mastra.db", // path is relative to the .mastra/output directory
|
|
@@ -1718,8 +1570,8 @@ export const weatherAgent = new Agent({
|
|
|
1718
1570
|
parser: "typescript",
|
|
1719
1571
|
singleQuote: true
|
|
1720
1572
|
});
|
|
1721
|
-
await
|
|
1722
|
-
await
|
|
1573
|
+
await fs4.writeFile(destPath, "");
|
|
1574
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1723
1575
|
}
|
|
1724
1576
|
async function writeWorkflowSample(destPath) {
|
|
1725
1577
|
const content = `import { createStep, createWorkflow } from '@mastra/core/workflows';
|
|
@@ -1912,20 +1764,112 @@ export { weatherWorkflow };`;
|
|
|
1912
1764
|
semi: true,
|
|
1913
1765
|
singleQuote: true
|
|
1914
1766
|
});
|
|
1915
|
-
await
|
|
1767
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1916
1768
|
}
|
|
1917
1769
|
async function writeToolSample(destPath) {
|
|
1918
1770
|
const fileService = new FileService();
|
|
1919
1771
|
await fileService.copyStarterFile("tools.ts", destPath);
|
|
1920
1772
|
}
|
|
1773
|
+
async function writeScorersSample(destPath) {
|
|
1774
|
+
const content = `import { z } from 'zod';
|
|
1775
|
+
import { createToolCallAccuracyScorerCode } from '@mastra/evals/scorers/code';
|
|
1776
|
+
import { createCompletenessScorer } from '@mastra/evals/scorers/code';
|
|
1777
|
+
import { createScorer } from '@mastra/core/scores';
|
|
1778
|
+
|
|
1779
|
+
export const toolCallAppropriatenessScorer = createToolCallAccuracyScorerCode({
|
|
1780
|
+
expectedTool: 'weatherTool',
|
|
1781
|
+
strictMode: false,
|
|
1782
|
+
});
|
|
1783
|
+
|
|
1784
|
+
export const completenessScorer = createCompletenessScorer();
|
|
1785
|
+
|
|
1786
|
+
// Custom LLM-judged scorer: evaluates if non-English locations are translated appropriately
|
|
1787
|
+
export const translationScorer = createScorer({
|
|
1788
|
+
name: 'Translation Quality',
|
|
1789
|
+
description: 'Checks that non-English location names are translated and used correctly',
|
|
1790
|
+
type: 'agent',
|
|
1791
|
+
judge: {
|
|
1792
|
+
model: 'openai/gpt-4o-mini',
|
|
1793
|
+
instructions:
|
|
1794
|
+
'You are an expert evaluator of translation quality for geographic locations. ' +
|
|
1795
|
+
'Determine whether the user text mentions a non-English location and whether the assistant correctly uses an English translation of that location. ' +
|
|
1796
|
+
'Be lenient with transliteration differences and diacritics. ' +
|
|
1797
|
+
'Return only the structured JSON matching the provided schema.',
|
|
1798
|
+
},
|
|
1799
|
+
})
|
|
1800
|
+
.preprocess(({ run }) => {
|
|
1801
|
+
const userText = (run.input?.inputMessages?.[0]?.content as string) || '';
|
|
1802
|
+
const assistantText = (run.output?.[0]?.content as string) || '';
|
|
1803
|
+
return { userText, assistantText };
|
|
1804
|
+
})
|
|
1805
|
+
.analyze({
|
|
1806
|
+
description: 'Extract location names and detect language/translation adequacy',
|
|
1807
|
+
outputSchema: z.object({
|
|
1808
|
+
nonEnglish: z.boolean(),
|
|
1809
|
+
translated: z.boolean(),
|
|
1810
|
+
confidence: z.number().min(0).max(1).default(1),
|
|
1811
|
+
explanation: z.string().default(''),
|
|
1812
|
+
}),
|
|
1813
|
+
createPrompt: ({ results }) => \`
|
|
1814
|
+
You are evaluating if a weather assistant correctly handled translation of a non-English location.
|
|
1815
|
+
User text:
|
|
1816
|
+
"""
|
|
1817
|
+
\${results.preprocessStepResult.userText}
|
|
1818
|
+
"""
|
|
1819
|
+
Assistant response:
|
|
1820
|
+
"""
|
|
1821
|
+
\${results.preprocessStepResult.assistantText}
|
|
1822
|
+
"""
|
|
1823
|
+
Tasks:
|
|
1824
|
+
1) Identify if the user mentioned a location that appears non-English.
|
|
1825
|
+
2) If non-English, check whether the assistant used a correct English translation of that location in its response.
|
|
1826
|
+
3) Be lenient with transliteration differences (e.g., accents/diacritics).
|
|
1827
|
+
Return JSON with fields:
|
|
1828
|
+
{
|
|
1829
|
+
"nonEnglish": boolean,
|
|
1830
|
+
"translated": boolean,
|
|
1831
|
+
"confidence": number, // 0-1
|
|
1832
|
+
"explanation": string
|
|
1833
|
+
}
|
|
1834
|
+
\`,
|
|
1835
|
+
})
|
|
1836
|
+
.generateScore(({ results }) => {
|
|
1837
|
+
const r = (results as any)?.analyzeStepResult || {};
|
|
1838
|
+
if (!r.nonEnglish) return 1; // If not applicable, full credit
|
|
1839
|
+
if (r.translated) return Math.max(0, Math.min(1, 0.7 + 0.3 * (r.confidence ?? 1)));
|
|
1840
|
+
return 0; // Non-English but not translated
|
|
1841
|
+
})
|
|
1842
|
+
.generateReason(({ results, score }) => {
|
|
1843
|
+
const r = (results as any)?.analyzeStepResult || {};
|
|
1844
|
+
return \`Translation scoring: nonEnglish=\${r.nonEnglish ?? false}, translated=\${r.translated ?? false}, confidence=\${r.confidence ?? 0}. Score=\${score}. \${r.explanation ?? ''}\`;
|
|
1845
|
+
});
|
|
1846
|
+
|
|
1847
|
+
export const scorers = {
|
|
1848
|
+
toolCallAppropriatenessScorer,
|
|
1849
|
+
completenessScorer,
|
|
1850
|
+
translationScorer,
|
|
1851
|
+
};`;
|
|
1852
|
+
const formattedContent = await prettier.format(content, {
|
|
1853
|
+
parser: "typescript",
|
|
1854
|
+
singleQuote: true
|
|
1855
|
+
});
|
|
1856
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1857
|
+
}
|
|
1921
1858
|
async function writeCodeSampleForComponents(llmprovider, component, destPath, importComponents) {
|
|
1922
1859
|
switch (component) {
|
|
1923
1860
|
case "agents":
|
|
1924
|
-
return writeAgentSample(
|
|
1861
|
+
return writeAgentSample(
|
|
1862
|
+
llmprovider,
|
|
1863
|
+
destPath,
|
|
1864
|
+
importComponents.includes("tools"),
|
|
1865
|
+
importComponents.includes("scorers")
|
|
1866
|
+
);
|
|
1925
1867
|
case "tools":
|
|
1926
1868
|
return writeToolSample(destPath);
|
|
1927
1869
|
case "workflows":
|
|
1928
1870
|
return writeWorkflowSample(destPath);
|
|
1871
|
+
case "scorers":
|
|
1872
|
+
return writeScorersSample(destPath);
|
|
1929
1873
|
default:
|
|
1930
1874
|
return "";
|
|
1931
1875
|
}
|
|
@@ -1938,18 +1882,20 @@ var writeIndexFile = async ({
|
|
|
1938
1882
|
dirPath,
|
|
1939
1883
|
addAgent,
|
|
1940
1884
|
addExample,
|
|
1941
|
-
addWorkflow
|
|
1885
|
+
addWorkflow,
|
|
1886
|
+
addScorers
|
|
1942
1887
|
}) => {
|
|
1943
1888
|
const indexPath = dirPath + "/index.ts";
|
|
1944
|
-
const destPath =
|
|
1889
|
+
const destPath = path.join(indexPath);
|
|
1945
1890
|
try {
|
|
1946
|
-
await
|
|
1891
|
+
await fs4.writeFile(destPath, "");
|
|
1947
1892
|
const filteredExports = [
|
|
1948
1893
|
addWorkflow ? `workflows: { weatherWorkflow },` : "",
|
|
1949
|
-
addAgent ? `agents: { weatherAgent },` : ""
|
|
1894
|
+
addAgent ? `agents: { weatherAgent },` : "",
|
|
1895
|
+
addScorers ? `scorers: { toolCallAppropriatenessScorer, completenessScorer, translationScorer },` : ""
|
|
1950
1896
|
].filter(Boolean);
|
|
1951
1897
|
if (!addExample) {
|
|
1952
|
-
await
|
|
1898
|
+
await fs4.writeFile(
|
|
1953
1899
|
destPath,
|
|
1954
1900
|
`
|
|
1955
1901
|
import { Mastra } from '@mastra/core';
|
|
@@ -1959,7 +1905,7 @@ export const mastra = new Mastra()
|
|
|
1959
1905
|
);
|
|
1960
1906
|
return;
|
|
1961
1907
|
}
|
|
1962
|
-
await
|
|
1908
|
+
await fs4.writeFile(
|
|
1963
1909
|
destPath,
|
|
1964
1910
|
`
|
|
1965
1911
|
import { Mastra } from '@mastra/core/mastra';
|
|
@@ -1967,6 +1913,7 @@ import { PinoLogger } from '@mastra/loggers';
|
|
|
1967
1913
|
import { LibSQLStore } from '@mastra/libsql';
|
|
1968
1914
|
${addWorkflow ? `import { weatherWorkflow } from './workflows/weather-workflow';` : ""}
|
|
1969
1915
|
${addAgent ? `import { weatherAgent } from './agents/weather-agent';` : ""}
|
|
1916
|
+
${addScorers ? `import { toolCallAppropriatenessScorer, completenessScorer, translationScorer } from './scorers/weather-scorer';` : ""}
|
|
1970
1917
|
|
|
1971
1918
|
export const mastra = new Mastra({
|
|
1972
1919
|
${filteredExports.join("\n ")}
|
|
@@ -2019,15 +1966,15 @@ var getAPIKey = async (provider) => {
|
|
|
2019
1966
|
var writeAPIKey = async ({ provider, apiKey }) => {
|
|
2020
1967
|
const envFileName = apiKey ? ".env" : ".env.example";
|
|
2021
1968
|
const key = await getAPIKey(provider);
|
|
2022
|
-
const escapedKey =
|
|
2023
|
-
const escapedApiKey =
|
|
2024
|
-
await
|
|
1969
|
+
const escapedKey = shellQuote2.quote([key]);
|
|
1970
|
+
const escapedApiKey = shellQuote2.quote([apiKey ? apiKey : "your-api-key"]);
|
|
1971
|
+
await exec(`echo ${escapedKey}=${escapedApiKey} >> ${envFileName}`);
|
|
2025
1972
|
};
|
|
2026
1973
|
var createMastraDir = async (directory) => {
|
|
2027
1974
|
let dir = directory.trim().split("/").filter((item) => item !== "");
|
|
2028
|
-
const dirPath =
|
|
1975
|
+
const dirPath = path.join(process.cwd(), ...dir, "mastra");
|
|
2029
1976
|
try {
|
|
2030
|
-
await
|
|
1977
|
+
await fs4.access(dirPath);
|
|
2031
1978
|
return { ok: false };
|
|
2032
1979
|
} catch {
|
|
2033
1980
|
await fsExtra.ensureDir(dirPath);
|
|
@@ -2173,13 +2120,193 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2173
2120
|
);
|
|
2174
2121
|
return mastraProject;
|
|
2175
2122
|
};
|
|
2123
|
+
function getPackageManager() {
|
|
2124
|
+
const userAgent = process.env.npm_config_user_agent || "";
|
|
2125
|
+
const execPath = process.env.npm_execpath || "";
|
|
2126
|
+
if (userAgent.includes("yarn")) {
|
|
2127
|
+
return "yarn";
|
|
2128
|
+
}
|
|
2129
|
+
if (userAgent.includes("pnpm")) {
|
|
2130
|
+
return "pnpm";
|
|
2131
|
+
}
|
|
2132
|
+
if (userAgent.includes("npm")) {
|
|
2133
|
+
return "npm";
|
|
2134
|
+
}
|
|
2135
|
+
if (execPath.includes("yarn")) {
|
|
2136
|
+
return "yarn";
|
|
2137
|
+
}
|
|
2138
|
+
if (execPath.includes("pnpm")) {
|
|
2139
|
+
return "pnpm";
|
|
2140
|
+
}
|
|
2141
|
+
if (execPath.includes("npm")) {
|
|
2142
|
+
return "npm";
|
|
2143
|
+
}
|
|
2144
|
+
return "npm";
|
|
2145
|
+
}
|
|
2146
|
+
var logger = createLogger(false);
|
|
2147
|
+
function createLogger(debug = false) {
|
|
2148
|
+
return new PinoLogger({
|
|
2149
|
+
name: "Mastra CLI",
|
|
2150
|
+
level: debug ? "debug" : "info"
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
var exec2 = util.promisify(child_process.exec);
|
|
2154
|
+
async function cloneTemplate(options) {
|
|
2155
|
+
const { template, projectName, targetDir } = options;
|
|
2156
|
+
const projectPath = targetDir ? path.resolve(targetDir, projectName) : path.resolve(projectName);
|
|
2157
|
+
const spinner5 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
|
|
2158
|
+
try {
|
|
2159
|
+
if (await directoryExists(projectPath)) {
|
|
2160
|
+
spinner5.error(`Directory ${projectName} already exists`);
|
|
2161
|
+
throw new Error(`Directory ${projectName} already exists`);
|
|
2162
|
+
}
|
|
2163
|
+
await cloneRepositoryWithoutGit(template.githubUrl, projectPath);
|
|
2164
|
+
await updatePackageJson(projectPath, projectName);
|
|
2165
|
+
const envExamplePath = path.join(projectPath, ".env.example");
|
|
2166
|
+
if (await fileExists(envExamplePath)) {
|
|
2167
|
+
await fs4.copyFile(envExamplePath, path.join(projectPath, ".env"));
|
|
2168
|
+
}
|
|
2169
|
+
spinner5.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
2170
|
+
return projectPath;
|
|
2171
|
+
} catch (error) {
|
|
2172
|
+
spinner5.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2173
|
+
throw error;
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
async function directoryExists(dirPath) {
|
|
2177
|
+
try {
|
|
2178
|
+
const stat = await fs4.stat(dirPath);
|
|
2179
|
+
return stat.isDirectory();
|
|
2180
|
+
} catch {
|
|
2181
|
+
return false;
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
async function fileExists(filePath) {
|
|
2185
|
+
try {
|
|
2186
|
+
const stat = await fs4.stat(filePath);
|
|
2187
|
+
return stat.isFile();
|
|
2188
|
+
} catch {
|
|
2189
|
+
return false;
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
async function cloneRepositoryWithoutGit(repoUrl, targetPath) {
|
|
2193
|
+
await fs4.mkdir(targetPath, { recursive: true });
|
|
2194
|
+
try {
|
|
2195
|
+
const degitRepo = repoUrl.replace("https://github.com/", "");
|
|
2196
|
+
const degitCommand = shellQuote2.quote(["npx", "degit", degitRepo, targetPath]);
|
|
2197
|
+
await exec2(degitCommand, {
|
|
2198
|
+
cwd: process.cwd()
|
|
2199
|
+
});
|
|
2200
|
+
} catch {
|
|
2201
|
+
try {
|
|
2202
|
+
const gitCommand = shellQuote2.quote(["git", "clone", repoUrl, targetPath]);
|
|
2203
|
+
await exec2(gitCommand, {
|
|
2204
|
+
cwd: process.cwd()
|
|
2205
|
+
});
|
|
2206
|
+
const gitDir = path.join(targetPath, ".git");
|
|
2207
|
+
if (await directoryExists(gitDir)) {
|
|
2208
|
+
await fs4.rm(gitDir, { recursive: true, force: true });
|
|
2209
|
+
}
|
|
2210
|
+
} catch (gitError) {
|
|
2211
|
+
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
async function updatePackageJson(projectPath, projectName) {
|
|
2216
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
2217
|
+
try {
|
|
2218
|
+
const packageJsonContent = await fs4.readFile(packageJsonPath, "utf-8");
|
|
2219
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
2220
|
+
packageJson.name = projectName;
|
|
2221
|
+
await fs4.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
2222
|
+
} catch (error) {
|
|
2223
|
+
logger.warn(`Could not update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
async function installDependencies(projectPath, packageManager) {
|
|
2227
|
+
const spinner5 = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
2228
|
+
try {
|
|
2229
|
+
const pm = packageManager || getPackageManager();
|
|
2230
|
+
const installCommand = shellQuote2.quote([pm, "install"]);
|
|
2231
|
+
await exec2(installCommand, {
|
|
2232
|
+
cwd: projectPath
|
|
2233
|
+
});
|
|
2234
|
+
spinner5.success("Dependencies installed successfully");
|
|
2235
|
+
} catch (error) {
|
|
2236
|
+
spinner5.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2237
|
+
throw error;
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
|
|
2241
|
+
async function loadTemplates() {
|
|
2242
|
+
try {
|
|
2243
|
+
const response = await fetch(TEMPLATES_API_URL);
|
|
2244
|
+
if (!response.ok) {
|
|
2245
|
+
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
2246
|
+
}
|
|
2247
|
+
const templates = await response.json();
|
|
2248
|
+
return templates;
|
|
2249
|
+
} catch (error) {
|
|
2250
|
+
console.error("Error loading templates:", error);
|
|
2251
|
+
throw new Error("Failed to load templates. Please check your internet connection and try again.");
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
function pluralize(count, singular, plural) {
|
|
2255
|
+
return count === 1 ? singular : plural || `${singular}s`;
|
|
2256
|
+
}
|
|
2257
|
+
async function selectTemplate(templates) {
|
|
2258
|
+
const choices = templates.map((template) => {
|
|
2259
|
+
const parts = [];
|
|
2260
|
+
if (template.agents?.length) {
|
|
2261
|
+
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
|
|
2262
|
+
}
|
|
2263
|
+
if (template.tools?.length) {
|
|
2264
|
+
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
|
|
2265
|
+
}
|
|
2266
|
+
if (template.workflows?.length) {
|
|
2267
|
+
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
|
|
2268
|
+
}
|
|
2269
|
+
if (template.mcp?.length) {
|
|
2270
|
+
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
|
|
2271
|
+
}
|
|
2272
|
+
if (template.networks?.length) {
|
|
2273
|
+
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
|
|
2274
|
+
}
|
|
2275
|
+
return {
|
|
2276
|
+
value: template,
|
|
2277
|
+
label: template.title,
|
|
2278
|
+
hint: parts.join(", ") || "Template components"
|
|
2279
|
+
};
|
|
2280
|
+
});
|
|
2281
|
+
const selected = await ve({
|
|
2282
|
+
message: "Select a template:",
|
|
2283
|
+
options: choices
|
|
2284
|
+
});
|
|
2285
|
+
if (pD(selected)) {
|
|
2286
|
+
return null;
|
|
2287
|
+
}
|
|
2288
|
+
return selected;
|
|
2289
|
+
}
|
|
2290
|
+
function findTemplateByName(templates, templateName) {
|
|
2291
|
+
let template = templates.find((t) => t.slug === templateName);
|
|
2292
|
+
if (template) return template;
|
|
2293
|
+
const slugWithPrefix = `template-${templateName}`;
|
|
2294
|
+
template = templates.find((t) => t.slug === slugWithPrefix);
|
|
2295
|
+
if (template) return template;
|
|
2296
|
+
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
|
|
2297
|
+
if (template) return template;
|
|
2298
|
+
return null;
|
|
2299
|
+
}
|
|
2300
|
+
function getDefaultProjectName(template) {
|
|
2301
|
+
return template.slug.replace(/^template-/, "");
|
|
2302
|
+
}
|
|
2176
2303
|
var s = Y();
|
|
2177
2304
|
var init = async ({
|
|
2178
|
-
directory,
|
|
2179
|
-
addExample = false,
|
|
2305
|
+
directory = "src/",
|
|
2180
2306
|
components,
|
|
2181
2307
|
llmProvider = "openai",
|
|
2182
2308
|
llmApiKey,
|
|
2309
|
+
addExample = false,
|
|
2183
2310
|
configureEditorWithDocsMCP
|
|
2184
2311
|
}) => {
|
|
2185
2312
|
s.start("Initializing Mastra");
|
|
@@ -2195,7 +2322,8 @@ var init = async ({
|
|
|
2195
2322
|
dirPath,
|
|
2196
2323
|
addExample,
|
|
2197
2324
|
addWorkflow: components.includes("workflows"),
|
|
2198
|
-
addAgent: components.includes("agents")
|
|
2325
|
+
addAgent: components.includes("agents"),
|
|
2326
|
+
addScorers: components.includes("scorers")
|
|
2199
2327
|
}),
|
|
2200
2328
|
...components.map((component) => createComponentsDir(dirPath, component)),
|
|
2201
2329
|
writeAPIKey({ provider: llmProvider, apiKey: llmApiKey })
|
|
@@ -2219,6 +2347,10 @@ var init = async ({
|
|
|
2219
2347
|
if (needsLoggers) {
|
|
2220
2348
|
await depService.installPackages(["@mastra/loggers"]);
|
|
2221
2349
|
}
|
|
2350
|
+
const needsEvals = components.includes(`scorers`) && await depService.checkDependencies(["@mastra/evals"]) !== `ok`;
|
|
2351
|
+
if (needsEvals) {
|
|
2352
|
+
await depService.installPackages(["@mastra/evals"]);
|
|
2353
|
+
}
|
|
2222
2354
|
}
|
|
2223
2355
|
const key = await getAPIKey(llmProvider || "openai");
|
|
2224
2356
|
if (configureEditorWithDocsMCP) {
|
|
@@ -2310,7 +2442,7 @@ var createMastraProject = async ({
|
|
|
2310
2442
|
defaultValue: "my-mastra-app",
|
|
2311
2443
|
validate: (value) => {
|
|
2312
2444
|
if (value.length === 0) return "Project name cannot be empty";
|
|
2313
|
-
if (
|
|
2445
|
+
if (fs3__default__default.existsSync(value)) {
|
|
2314
2446
|
return `A directory named "${value}" already exists. Please choose a different name.`;
|
|
2315
2447
|
}
|
|
2316
2448
|
}
|
|
@@ -2330,7 +2462,7 @@ var createMastraProject = async ({
|
|
|
2330
2462
|
try {
|
|
2331
2463
|
s2.start("Creating project");
|
|
2332
2464
|
try {
|
|
2333
|
-
await
|
|
2465
|
+
await fs4.mkdir(projectName);
|
|
2334
2466
|
} catch (error) {
|
|
2335
2467
|
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
2336
2468
|
s2.stop(`A directory named "${projectName}" already exists. Please choose a different name.`);
|
|
@@ -2362,7 +2494,7 @@ var createMastraProject = async ({
|
|
|
2362
2494
|
s2.stop("Project structure created");
|
|
2363
2495
|
s2.start(`Installing ${pm} dependencies`);
|
|
2364
2496
|
try {
|
|
2365
|
-
await exec3(`${pm} ${installCommand} zod@^
|
|
2497
|
+
await exec3(`${pm} ${installCommand} zod@^4`);
|
|
2366
2498
|
await exec3(`${pm} ${installCommand} typescript @types/node --save-dev`);
|
|
2367
2499
|
await exec3(`echo '{
|
|
2368
2500
|
"compilerOptions": {
|
|
@@ -2448,7 +2580,7 @@ var create = async (args2) => {
|
|
|
2448
2580
|
await init({
|
|
2449
2581
|
...result,
|
|
2450
2582
|
llmApiKey: result?.llmApiKey,
|
|
2451
|
-
components: ["agents", "tools", "workflows"],
|
|
2583
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2452
2584
|
addExample: true
|
|
2453
2585
|
});
|
|
2454
2586
|
postCreate({ projectName });
|
|
@@ -2632,7 +2764,7 @@ async function createFromTemplate(args2) {
|
|
|
2632
2764
|
async function getPackageVersion() {
|
|
2633
2765
|
const __filename = fileURLToPath(import.meta.url);
|
|
2634
2766
|
const __dirname = dirname(__filename);
|
|
2635
|
-
const pkgJsonPath =
|
|
2767
|
+
const pkgJsonPath = path.join(__dirname, "..", "package.json");
|
|
2636
2768
|
const content = await fsExtra$1.readJSON(pkgJsonPath);
|
|
2637
2769
|
return content.version;
|
|
2638
2770
|
}
|
|
@@ -2670,7 +2802,7 @@ program.version(`${version}`, "-v, --version").description(`create-mastra ${vers
|
|
|
2670
2802
|
program.name("create-mastra").description("Create a new Mastra project").argument("[project-name]", "Directory name of the project").option(
|
|
2671
2803
|
"-p, --project-name <string>",
|
|
2672
2804
|
"Project name that will be used in package.json and as the project directory name."
|
|
2673
|
-
).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(
|
|
2805
|
+
).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(
|
|
2674
2806
|
"--template [template-name]",
|
|
2675
2807
|
"Create project from a template (use template name, public GitHub URL, or leave blank to select from list)"
|
|
2676
2808
|
).action(async (projectNameArg, args) => {
|
|
@@ -2678,7 +2810,7 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2678
2810
|
const timeout = args?.timeout ? args?.timeout === true ? 6e4 : parseInt(args?.timeout, 10) : void 0;
|
|
2679
2811
|
if (args.default) {
|
|
2680
2812
|
await create({
|
|
2681
|
-
components: ["agents", "tools", "workflows"],
|
|
2813
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2682
2814
|
llmProvider: "openai",
|
|
2683
2815
|
addExample: true,
|
|
2684
2816
|
createVersionTag,
|