create-mastra 0.0.0-taofeeq-fix-tool-call-showing-after-message-20250806184630 → 0.0.0-testing-cloud-studios-20260114234039
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 +2322 -0
- package/README.md +11 -39
- package/dist/index.js +937 -566
- package/dist/index.js.map +1 -1
- package/dist/starter-files/tools.ts +2 -2
- package/dist/templates/dev.entry.js +4 -42
- package/package.json +30 -23
- package/dist/starter-files/config.d.ts +0 -26
- package/dist/starter-files/config.d.ts.map +0 -1
- package/dist/starter-files/config.ts +0 -25
- package/dist/starter-files/mastra-pg.docker-compose.yaml +0 -15
- package/dist/starter-files/tools.d.ts +0 -79
- package/dist/starter-files/tools.d.ts.map +0 -1
- package/dist/templates/dev.entry.d.ts +0 -2
- package/dist/templates/dev.entry.d.ts.map +0 -1
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';
|
|
21
|
+
import fsExtra$1 from 'fs-extra';
|
|
18
22
|
import pino from 'pino';
|
|
19
23
|
import pretty from 'pino-pretty';
|
|
20
|
-
import { execa } from 'execa';
|
|
21
|
-
import fsExtra3, { readJSON, ensureFile, writeJSON } from 'fs-extra/esm';
|
|
22
|
-
import prettier from 'prettier';
|
|
23
|
-
import fsExtra from 'fs-extra';
|
|
24
24
|
|
|
25
25
|
var __filename = fileURLToPath(import.meta.url);
|
|
26
26
|
var __dirname = path3.dirname(__filename);
|
|
@@ -105,6 +105,10 @@ var PosthogAnalytics = class {
|
|
|
105
105
|
machine_id: os.hostname()
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
|
+
getDurationMs(startTime) {
|
|
109
|
+
const [seconds, nanoseconds] = process.hrtime(startTime);
|
|
110
|
+
return seconds * 1e3 + nanoseconds / 1e6;
|
|
111
|
+
}
|
|
108
112
|
captureSessionStart() {
|
|
109
113
|
if (!this.client) {
|
|
110
114
|
return;
|
|
@@ -173,8 +177,7 @@ var PosthogAnalytics = class {
|
|
|
173
177
|
const startTime = process.hrtime();
|
|
174
178
|
try {
|
|
175
179
|
const result = await execution();
|
|
176
|
-
const
|
|
177
|
-
const durationMs = seconds * 1e3 + nanoseconds / 1e6;
|
|
180
|
+
const durationMs = this.getDurationMs(startTime);
|
|
178
181
|
this.trackCommand({
|
|
179
182
|
command,
|
|
180
183
|
args,
|
|
@@ -184,8 +187,7 @@ var PosthogAnalytics = class {
|
|
|
184
187
|
});
|
|
185
188
|
return result;
|
|
186
189
|
} catch (error) {
|
|
187
|
-
const
|
|
188
|
-
const durationMs = seconds * 1e3 + nanoseconds / 1e6;
|
|
190
|
+
const durationMs = this.getDurationMs(startTime);
|
|
189
191
|
this.trackCommand({
|
|
190
192
|
command,
|
|
191
193
|
args,
|
|
@@ -382,7 +384,7 @@ function DD({onlyFirst:e=false}={}){const t=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:
|
|
|
382
384
|
`).length-1;this.output.write(srcExports.cursor.move(-999,u*-1));}render(){const u=Y$1(this._render(this)??"",process.stdout.columns,{hard:true});if(u!==this._prevFrame){if(this.state==="initial")this.output.write(srcExports.cursor.hide);else {const t=BD(this._prevFrame,u);if(this.restoreCursor(),t&&t?.length===1){const F=t[0];this.output.write(srcExports.cursor.move(0,F)),this.output.write(srcExports.erase.lines(1));const s=u.split(`
|
|
383
385
|
`);this.output.write(s[F]),this._prevFrame=u,this.output.write(srcExports.cursor.move(0,s.length-F-1));return}if(t&&t?.length>1){const F=t[0];this.output.write(srcExports.cursor.move(0,F)),this.output.write(srcExports.erase.down());const s=u.split(`
|
|
384
386
|
`).slice(F);this.output.write(s.join(`
|
|
385
|
-
`)),this._prevFrame=u;return}this.output.write(srcExports.erase.down());}this.output.write(u),this.state==="initial"&&(this.state="active"),this._prevFrame=u;}}}var OD=Object.defineProperty,PD=(e,u,t)=>u in e?OD(e,u,{enumerable:true,configurable:true,writable:true,value:t}):e[u]=t,J=(e,u,t)=>(PD(e,typeof u!="symbol"?u+"":u,t),t);class LD extends x{constructor(u){super(u,false),J(this,"options"),J(this,"cursor",0),this.options=u.options,this.cursor=this.options.findIndex(({value:t})=>t===u.initialValue),this.cursor===-1&&(this.cursor=0),this.changeValue(),this.on("cursor",t=>{switch(t){case "left":case "up":this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;break;case "down":case "right":this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;break}this.changeValue();});}get _value(){return this.options[this.cursor]}changeValue(){this.value=this._value.value;}}class RD extends x{get valueWithCursor(){if(this.state==="submit")return this.value;if(this.cursor>=this.value.length)return `${this.value}\u2588`;const u=this.value.slice(0,this.cursor),[t,...F]=this.value.slice(this.cursor);return `${u}${color2.inverse(t)}${F.join("")}`}get cursor(){return this._cursor}constructor(u){super(u),this.on("finalize",()=>{this.value||(this.value=u.defaultValue);});}}
|
|
387
|
+
`)),this._prevFrame=u;return}this.output.write(srcExports.erase.down());}this.output.write(u),this.state==="initial"&&(this.state="active"),this._prevFrame=u;}}}class dD extends x{get cursor(){return this.value?0:1}get _value(){return this.cursor===0}constructor(u){super(u,false),this.value=!!u.initialValue,this.on("value",()=>{this.value=this._value;}),this.on("confirm",t=>{this.output.write(srcExports.cursor.move(0,-1)),this.value=t,this.state="submit",this.close();}),this.on("cursor",()=>{this.value=!this.value;});}}var OD=Object.defineProperty,PD=(e,u,t)=>u in e?OD(e,u,{enumerable:true,configurable:true,writable:true,value:t}):e[u]=t,J=(e,u,t)=>(PD(e,typeof u!="symbol"?u+"":u,t),t);class LD extends x{constructor(u){super(u,false),J(this,"options"),J(this,"cursor",0),this.options=u.options,this.cursor=this.options.findIndex(({value:t})=>t===u.initialValue),this.cursor===-1&&(this.cursor=0),this.changeValue(),this.on("cursor",t=>{switch(t){case "left":case "up":this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;break;case "down":case "right":this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;break}this.changeValue();});}get _value(){return this.options[this.cursor]}changeValue(){this.value=this._value.value;}}class RD extends x{get valueWithCursor(){if(this.state==="submit")return this.value;if(this.cursor>=this.value.length)return `${this.value}\u2588`;const u=this.value.slice(0,this.cursor),[t,...F]=this.value.slice(this.cursor);return `${u}${color2.inverse(t)}${F.join("")}`}get cursor(){return this._cursor}constructor(u){super(u),this.on("finalize",()=>{this.value||(this.value=u.defaultValue);});}}
|
|
386
388
|
|
|
387
389
|
function ce(){return y$1.platform!=="win32"?y$1.env.TERM!=="linux":!!y$1.env.CI||!!y$1.env.WT_SESSION||!!y$1.env.TERMINUS_SUBLIME||y$1.env.ConEmuTask==="{cmd::Cmder}"||y$1.env.TERM_PROGRAM==="Terminus-Sublime"||y$1.env.TERM_PROGRAM==="vscode"||y$1.env.TERM==="xterm-256color"||y$1.env.TERM==="alacritty"||y$1.env.TERMINAL_EMULATOR==="JetBrains-JediTerm"}const V=ce(),u=(t,n)=>V?t:n,le=u("\u25C6","*"),L=u("\u25A0","x"),W=u("\u25B2","x"),C=u("\u25C7","o"),ue=u("\u250C","T"),o=u("\u2502","|"),d=u("\u2514","\u2014"),k=u("\u25CF",">"),P=u("\u25CB"," "),_=u("\u2500","-"),me=u("\u256E","+"),de=u("\u251C","+"),pe=u("\u256F","+"),q=u("\u25CF","\u2022"),D=u("\u25C6","*"),U=u("\u25B2","!"),K=u("\u25A0","x"),b=t=>{switch(t){case "initial":case "active":return color2.cyan(le);case "cancel":return color2.red(L);case "error":return color2.yellow(W);case "submit":return color2.green(C)}},G=t=>{const{cursor:n,options:r,style:i}=t,s=t.maxItems??Number.POSITIVE_INFINITY,c=Math.max(process.stdout.rows-4,0),a=Math.min(c,Math.max(s,5));let l=0;n>=l+a-3?l=Math.max(Math.min(n-a+3,r.length-a),0):n<l+2&&(l=Math.max(n-2,0));const $=a<r.length&&l>0,g=a<r.length&&l+a<r.length;return r.slice(l,l+a).map((p,v,f)=>{const j=v===0&&$,E=v===f.length-1&&g;return j||E?color2.dim("..."):i(p,v+l===n)})},he=t=>new RD({validate:t.validate,placeholder:t.placeholder,defaultValue:t.defaultValue,initialValue:t.initialValue,render(){const n=`${color2.gray(o)}
|
|
388
390
|
${b(this.state)} ${t.message}
|
|
@@ -392,7 +394,12 @@ ${color2.yellow(d)} ${color2.yellow(this.error)}
|
|
|
392
394
|
`;case "submit":return `${n}${color2.gray(o)} ${color2.dim(this.value||t.placeholder)}`;case "cancel":return `${n}${color2.gray(o)} ${color2.strikethrough(color2.dim(this.value??""))}${this.value?.trim()?`
|
|
393
395
|
${color2.gray(o)}`:""}`;default:return `${n}${color2.cyan(o)} ${i}
|
|
394
396
|
${color2.cyan(d)}
|
|
395
|
-
`}}}).prompt(),
|
|
397
|
+
`}}}).prompt(),ye=t=>{const n=t.active??"Yes",r=t.inactive??"No";return new dD({active:n,inactive:r,initialValue:t.initialValue??true,render(){const i=`${color2.gray(o)}
|
|
398
|
+
${b(this.state)} ${t.message}
|
|
399
|
+
`,s=this.value?n:r;switch(this.state){case "submit":return `${i}${color2.gray(o)} ${color2.dim(s)}`;case "cancel":return `${i}${color2.gray(o)} ${color2.strikethrough(color2.dim(s))}
|
|
400
|
+
${color2.gray(o)}`;default:return `${i}${color2.cyan(o)} ${this.value?`${color2.green(k)} ${n}`:`${color2.dim(P)} ${color2.dim(n)}`} ${color2.dim("/")} ${this.value?`${color2.dim(P)} ${color2.dim(r)}`:`${color2.green(k)} ${r}`}
|
|
401
|
+
${color2.cyan(d)}
|
|
402
|
+
`}}}).prompt()},ve=t=>{const n=(r,i)=>{const s=r.label??String(r.value);switch(i){case "selected":return `${color2.dim(s)}`;case "active":return `${color2.green(k)} ${s} ${r.hint?color2.dim(`(${r.hint})`):""}`;case "cancelled":return `${color2.strikethrough(color2.dim(s))}`;default:return `${color2.dim(P)} ${color2.dim(s)}`}};return new LD({options:t.options,initialValue:t.initialValue,render(){const r=`${color2.gray(o)}
|
|
396
403
|
${b(this.state)} ${t.message}
|
|
397
404
|
`;switch(this.state){case "submit":return `${r}${color2.gray(o)} ${n(this.options[this.cursor],"selected")}`;case "cancel":return `${r}${color2.gray(o)} ${n(this.options[this.cursor],"cancelled")}
|
|
398
405
|
${color2.gray(o)}`;default:return `${r}${color2.cyan(o)} ${G({cursor:this.cursor,options:this.options,maxItems:t.maxItems,style:(i,s)=>n(i,s?"active":"inactive")}).join(`
|
|
@@ -422,7 +429,7 @@ ${color2.gray(d)} ${t}
|
|
|
422
429
|
`):process.stdout.write(`${w} ${l}
|
|
423
430
|
`),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
431
|
|
|
425
|
-
var shellQuote
|
|
432
|
+
var shellQuote = {};
|
|
426
433
|
|
|
427
434
|
var quote;
|
|
428
435
|
var hasRequiredQuote;
|
|
@@ -688,16 +695,16 @@ function requireParse () {
|
|
|
688
695
|
var hasRequiredShellQuote;
|
|
689
696
|
|
|
690
697
|
function requireShellQuote () {
|
|
691
|
-
if (hasRequiredShellQuote) return shellQuote
|
|
698
|
+
if (hasRequiredShellQuote) return shellQuote;
|
|
692
699
|
hasRequiredShellQuote = 1;
|
|
693
700
|
|
|
694
|
-
shellQuote
|
|
695
|
-
shellQuote
|
|
696
|
-
return shellQuote
|
|
701
|
+
shellQuote.quote = requireQuote();
|
|
702
|
+
shellQuote.parse = requireParse();
|
|
703
|
+
return shellQuote;
|
|
697
704
|
}
|
|
698
705
|
|
|
699
706
|
var shellQuoteExports = requireShellQuote();
|
|
700
|
-
var
|
|
707
|
+
var shellQuote2 = /*@__PURE__*/getDefaultExportFromCjs(shellQuoteExports);
|
|
701
708
|
|
|
702
709
|
// eslint-disable-next-line no-warning-comments
|
|
703
710
|
// TODO: Use a better method when it's added to Node.js (https://github.com/nodejs/node/pull/40240)
|
|
@@ -724,13 +731,18 @@ const format = (open, close) => {
|
|
|
724
731
|
// Handle nested colors.
|
|
725
732
|
|
|
726
733
|
// We could have done this, but it's too slow (as of Node.js 22).
|
|
727
|
-
// return openCode + string.replaceAll(closeCode, openCode) + closeCode;
|
|
734
|
+
// return openCode + string.replaceAll(closeCode, (close === 22 ? closeCode : '') + openCode) + closeCode;
|
|
728
735
|
|
|
729
736
|
let result = openCode;
|
|
730
737
|
let lastIndex = 0;
|
|
731
738
|
|
|
739
|
+
// SGR 22 resets both bold (1) and dim (2). When we encounter a nested
|
|
740
|
+
// close for styles that use 22, we need to re-open the outer style.
|
|
741
|
+
const reopenOnNestedClose = close === 22;
|
|
742
|
+
const replaceCode = (reopenOnNestedClose ? closeCode : '') + openCode;
|
|
743
|
+
|
|
732
744
|
while (index !== -1) {
|
|
733
|
-
result += string.slice(lastIndex, index) +
|
|
745
|
+
result += string.slice(lastIndex, index) + replaceCode;
|
|
734
746
|
lastIndex = index + closeCode.length;
|
|
735
747
|
index = string.indexOf(closeCode, lastIndex);
|
|
736
748
|
}
|
|
@@ -882,6 +894,7 @@ class YoctoSpinner {
|
|
|
882
894
|
#exitHandlerBound;
|
|
883
895
|
#isInteractive;
|
|
884
896
|
#lastSpinnerFrameTime = 0;
|
|
897
|
+
#isSpinning = false;
|
|
885
898
|
|
|
886
899
|
constructor(options = {}) {
|
|
887
900
|
const spinner = options.spinner ?? defaultSpinner;
|
|
@@ -903,13 +916,17 @@ class YoctoSpinner {
|
|
|
903
916
|
return this;
|
|
904
917
|
}
|
|
905
918
|
|
|
919
|
+
this.#isSpinning = true;
|
|
906
920
|
this.#hideCursor();
|
|
907
921
|
this.#render();
|
|
908
922
|
this.#subscribeToProcessEvents();
|
|
909
923
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
924
|
+
// Only start the timer in interactive mode
|
|
925
|
+
if (this.#isInteractive) {
|
|
926
|
+
this.#timer = setInterval(() => {
|
|
927
|
+
this.#render();
|
|
928
|
+
}, this.#interval);
|
|
929
|
+
}
|
|
913
930
|
|
|
914
931
|
return this;
|
|
915
932
|
}
|
|
@@ -919,8 +936,12 @@ class YoctoSpinner {
|
|
|
919
936
|
return this;
|
|
920
937
|
}
|
|
921
938
|
|
|
922
|
-
|
|
923
|
-
this.#timer
|
|
939
|
+
this.#isSpinning = false;
|
|
940
|
+
if (this.#timer) {
|
|
941
|
+
clearInterval(this.#timer);
|
|
942
|
+
this.#timer = undefined;
|
|
943
|
+
}
|
|
944
|
+
|
|
924
945
|
this.#showCursor();
|
|
925
946
|
this.clear();
|
|
926
947
|
this.#unsubscribeFromProcessEvents();
|
|
@@ -953,7 +974,7 @@ class YoctoSpinner {
|
|
|
953
974
|
}
|
|
954
975
|
|
|
955
976
|
get isSpinning() {
|
|
956
|
-
return this.#
|
|
977
|
+
return this.#isSpinning;
|
|
957
978
|
}
|
|
958
979
|
|
|
959
980
|
get text() {
|
|
@@ -1090,11 +1111,11 @@ var MastraLogger = class {
|
|
|
1090
1111
|
}
|
|
1091
1112
|
trackException(_error) {
|
|
1092
1113
|
}
|
|
1093
|
-
async
|
|
1114
|
+
async listLogs(transportId, params) {
|
|
1094
1115
|
if (!transportId || !this.transports.has(transportId)) {
|
|
1095
1116
|
return { logs: [], total: 0, page: params?.page ?? 1, perPage: params?.perPage ?? 100, hasMore: false };
|
|
1096
1117
|
}
|
|
1097
|
-
return this.transports.get(transportId).
|
|
1118
|
+
return this.transports.get(transportId).listLogs(params) ?? {
|
|
1098
1119
|
logs: [],
|
|
1099
1120
|
total: 0,
|
|
1100
1121
|
page: params?.page ?? 1,
|
|
@@ -1102,7 +1123,7 @@ var MastraLogger = class {
|
|
|
1102
1123
|
hasMore: false
|
|
1103
1124
|
};
|
|
1104
1125
|
}
|
|
1105
|
-
async
|
|
1126
|
+
async listLogsByRunId({
|
|
1106
1127
|
transportId,
|
|
1107
1128
|
runId,
|
|
1108
1129
|
fromDate,
|
|
@@ -1115,7 +1136,7 @@ var MastraLogger = class {
|
|
|
1115
1136
|
if (!transportId || !this.transports.has(transportId) || !runId) {
|
|
1116
1137
|
return { logs: [], total: 0, page: page ?? 1, perPage: perPage ?? 100, hasMore: false };
|
|
1117
1138
|
}
|
|
1118
|
-
return this.transports.get(transportId).
|
|
1139
|
+
return this.transports.get(transportId).listLogsByRunId({ runId, fromDate, toDate, logLevel, filters, page, perPage }) ?? {
|
|
1119
1140
|
logs: [],
|
|
1120
1141
|
total: 0,
|
|
1121
1142
|
page: page ?? 1,
|
|
@@ -1125,10 +1146,15 @@ var MastraLogger = class {
|
|
|
1125
1146
|
}
|
|
1126
1147
|
};
|
|
1127
1148
|
|
|
1128
|
-
var PinoLogger = class extends MastraLogger {
|
|
1149
|
+
var PinoLogger = class _PinoLogger extends MastraLogger {
|
|
1129
1150
|
logger;
|
|
1130
1151
|
constructor(options = {}) {
|
|
1131
1152
|
super(options);
|
|
1153
|
+
const internalOptions = options;
|
|
1154
|
+
if (internalOptions._logger) {
|
|
1155
|
+
this.logger = internalOptions._logger;
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1132
1158
|
let prettyStream = void 0;
|
|
1133
1159
|
if (!options.overrideDefaultTransports) {
|
|
1134
1160
|
prettyStream = pretty({
|
|
@@ -1145,7 +1171,8 @@ var PinoLogger = class extends MastraLogger {
|
|
|
1145
1171
|
{
|
|
1146
1172
|
name: options.name || "app",
|
|
1147
1173
|
level: options.level || LogLevel.INFO,
|
|
1148
|
-
formatters: options.formatters
|
|
1174
|
+
formatters: options.formatters,
|
|
1175
|
+
redact: options.redact
|
|
1149
1176
|
},
|
|
1150
1177
|
options.overrideDefaultTransports ? options?.transports?.default : transportsAry.length === 0 ? prettyStream : pino.multistream([
|
|
1151
1178
|
...transportsAry.map(([, transport]) => ({
|
|
@@ -1159,6 +1186,38 @@ var PinoLogger = class extends MastraLogger {
|
|
|
1159
1186
|
])
|
|
1160
1187
|
);
|
|
1161
1188
|
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Creates a child logger with additional bound context.
|
|
1191
|
+
* All logs from the child logger will include the bound context.
|
|
1192
|
+
*
|
|
1193
|
+
* @param bindings - Key-value pairs to include in all logs from this child logger
|
|
1194
|
+
* @returns A new PinoLogger instance with the bound context
|
|
1195
|
+
*
|
|
1196
|
+
* @example
|
|
1197
|
+
* ```typescript
|
|
1198
|
+
* const baseLogger = new PinoLogger({ name: 'MyApp' });
|
|
1199
|
+
*
|
|
1200
|
+
* // Create module-scoped logger
|
|
1201
|
+
* const serviceLogger = baseLogger.child({ module: 'UserService' });
|
|
1202
|
+
* serviceLogger.info('User created', { userId: '123' });
|
|
1203
|
+
* // Output includes: { module: 'UserService', userId: '123', msg: 'User created' }
|
|
1204
|
+
*
|
|
1205
|
+
* // Create request-scoped logger
|
|
1206
|
+
* const requestLogger = baseLogger.child({ requestId: req.id });
|
|
1207
|
+
* requestLogger.error('Request failed', { err: error });
|
|
1208
|
+
* // Output includes: { requestId: 'abc', msg: 'Request failed', err: {...} }
|
|
1209
|
+
* ```
|
|
1210
|
+
*/
|
|
1211
|
+
child(bindings) {
|
|
1212
|
+
const childPino = this.logger.child(bindings);
|
|
1213
|
+
const childOptions = {
|
|
1214
|
+
name: this.name,
|
|
1215
|
+
level: this.level,
|
|
1216
|
+
transports: Object.fromEntries(this.transports),
|
|
1217
|
+
_logger: childPino
|
|
1218
|
+
};
|
|
1219
|
+
return new _PinoLogger(childOptions);
|
|
1220
|
+
}
|
|
1162
1221
|
debug(message, args = {}) {
|
|
1163
1222
|
this.logger.debug(args, message);
|
|
1164
1223
|
}
|
|
@@ -1173,194 +1232,21 @@ var PinoLogger = class extends MastraLogger {
|
|
|
1173
1232
|
}
|
|
1174
1233
|
};
|
|
1175
1234
|
|
|
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) {
|
|
1235
|
+
var package_default = {
|
|
1236
|
+
version: "1.0.0-beta.13"};
|
|
1237
|
+
function getPackageManagerAddCommand(pm) {
|
|
1200
1238
|
switch (pm) {
|
|
1201
1239
|
case "npm":
|
|
1202
|
-
return "install";
|
|
1240
|
+
return "install --audit=false --fund=false --loglevel=error --progress=false --update-notifier=false";
|
|
1203
1241
|
case "yarn":
|
|
1204
1242
|
return "add";
|
|
1205
1243
|
case "pnpm":
|
|
1244
|
+
return "add --loglevel=error";
|
|
1245
|
+
case "bun":
|
|
1206
1246
|
return "add";
|
|
1207
1247
|
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 spinner5 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
|
|
1220
|
-
try {
|
|
1221
|
-
if (await directoryExists(projectPath)) {
|
|
1222
|
-
spinner5.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
|
-
spinner5.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
1232
|
-
return projectPath;
|
|
1233
|
-
} catch (error) {
|
|
1234
|
-
spinner5.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 spinner5 = 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
|
-
spinner5.success("Dependencies installed successfully");
|
|
1297
|
-
} catch (error) {
|
|
1298
|
-
spinner5.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;
|
|
1248
|
+
return "add";
|
|
1349
1249
|
}
|
|
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
1250
|
}
|
|
1365
1251
|
var DepsService = class {
|
|
1366
1252
|
packageManager;
|
|
@@ -1370,7 +1256,7 @@ var DepsService = class {
|
|
|
1370
1256
|
findLockFile(dir) {
|
|
1371
1257
|
const lockFiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock"];
|
|
1372
1258
|
for (const file of lockFiles) {
|
|
1373
|
-
if (
|
|
1259
|
+
if (fs3__default__default.existsSync(path3.join(dir, file))) {
|
|
1374
1260
|
return file;
|
|
1375
1261
|
}
|
|
1376
1262
|
}
|
|
@@ -1396,14 +1282,10 @@ var DepsService = class {
|
|
|
1396
1282
|
}
|
|
1397
1283
|
}
|
|
1398
1284
|
async installPackages(packages) {
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
runCommand = `${this.packageManager} i`;
|
|
1402
|
-
} else {
|
|
1403
|
-
runCommand = `${this.packageManager} add`;
|
|
1404
|
-
}
|
|
1285
|
+
const pm = this.packageManager;
|
|
1286
|
+
const installCommand = getPackageManagerAddCommand(pm);
|
|
1405
1287
|
const packageList = packages.join(" ");
|
|
1406
|
-
return execa(`${
|
|
1288
|
+
return execa(`${pm} ${installCommand} ${packageList}`, {
|
|
1407
1289
|
all: true,
|
|
1408
1290
|
shell: true,
|
|
1409
1291
|
stdio: "inherit"
|
|
@@ -1413,11 +1295,11 @@ var DepsService = class {
|
|
|
1413
1295
|
try {
|
|
1414
1296
|
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1415
1297
|
try {
|
|
1416
|
-
await
|
|
1298
|
+
await fs4.access(packageJsonPath);
|
|
1417
1299
|
} catch {
|
|
1418
1300
|
return "No package.json file found in the current directory";
|
|
1419
1301
|
}
|
|
1420
|
-
const packageJson = JSON.parse(await
|
|
1302
|
+
const packageJson = JSON.parse(await fs4.readFile(packageJsonPath, "utf-8"));
|
|
1421
1303
|
for (const dependency of dependencies) {
|
|
1422
1304
|
if (!packageJson.dependencies || !packageJson.dependencies[dependency]) {
|
|
1423
1305
|
return `Please install ${dependency} before running this command (${this.packageManager} install ${dependency})`;
|
|
@@ -1432,164 +1314,45 @@ var DepsService = class {
|
|
|
1432
1314
|
async getProjectName() {
|
|
1433
1315
|
try {
|
|
1434
1316
|
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
1435
|
-
const packageJson = await
|
|
1317
|
+
const packageJson = await fs4.readFile(packageJsonPath, "utf-8");
|
|
1436
1318
|
const pkg = JSON.parse(packageJson);
|
|
1437
1319
|
return pkg.name;
|
|
1438
1320
|
} catch (err) {
|
|
1439
1321
|
throw err;
|
|
1440
1322
|
}
|
|
1441
1323
|
}
|
|
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
1324
|
async addScriptsToPackageJson(scripts) {
|
|
1450
|
-
const packageJson = JSON.parse(await
|
|
1325
|
+
const packageJson = JSON.parse(await fs4.readFile("package.json", "utf-8"));
|
|
1451
1326
|
packageJson.scripts = {
|
|
1452
1327
|
...packageJson.scripts,
|
|
1453
1328
|
...scripts
|
|
1454
1329
|
};
|
|
1455
|
-
await
|
|
1330
|
+
await fs4.writeFile("package.json", JSON.stringify(packageJson, null, 2));
|
|
1456
1331
|
}
|
|
1457
1332
|
};
|
|
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
|
-
};
|
|
1333
|
+
var EnvService = class {
|
|
1483
1334
|
};
|
|
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");
|
|
1335
|
+
var FileEnvService = class extends EnvService {
|
|
1336
|
+
filePath;
|
|
1337
|
+
constructor(filePath) {
|
|
1338
|
+
super();
|
|
1339
|
+
this.filePath = filePath;
|
|
1520
1340
|
}
|
|
1521
|
-
|
|
1522
|
-
|
|
1341
|
+
readFile(filePath) {
|
|
1342
|
+
return new Promise((resolve, reject) => {
|
|
1343
|
+
fs3__default.readFile(filePath, "utf8", (err, data) => {
|
|
1344
|
+
if (err) reject(err);
|
|
1345
|
+
else resolve(data);
|
|
1346
|
+
});
|
|
1347
|
+
});
|
|
1523
1348
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
if (editor === `windsurf`) {
|
|
1532
|
-
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor);
|
|
1533
|
-
if (alreadyInstalled) {
|
|
1534
|
-
return;
|
|
1535
|
-
}
|
|
1536
|
-
await writeMergedConfig(windsurfGlobalMCPConfigPath, editor);
|
|
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
|
-
});
|
|
1349
|
+
writeFile({ filePath, data }) {
|
|
1350
|
+
return new Promise((resolve, reject) => {
|
|
1351
|
+
fs3__default.writeFile(filePath, data, "utf8", (err) => {
|
|
1352
|
+
if (err) reject(err);
|
|
1353
|
+
else resolve();
|
|
1354
|
+
});
|
|
1355
|
+
});
|
|
1593
1356
|
}
|
|
1594
1357
|
async updateEnvData({
|
|
1595
1358
|
key,
|
|
@@ -1605,7 +1368,7 @@ var FileEnvService = class extends EnvService {
|
|
|
1605
1368
|
${key}=${value}`;
|
|
1606
1369
|
}
|
|
1607
1370
|
await this.writeFile({ filePath, data });
|
|
1608
|
-
console.
|
|
1371
|
+
console.info(`${key} set to ${value} in ENV file.`);
|
|
1609
1372
|
return data;
|
|
1610
1373
|
}
|
|
1611
1374
|
async getEnvValue(key) {
|
|
@@ -1640,23 +1403,23 @@ var FileService = class {
|
|
|
1640
1403
|
const __filename = fileURLToPath(import.meta.url);
|
|
1641
1404
|
const __dirname = path3.dirname(__filename);
|
|
1642
1405
|
const filePath = path3.resolve(__dirname, "starter-files", inputFile);
|
|
1643
|
-
const fileString =
|
|
1644
|
-
if (
|
|
1645
|
-
console.
|
|
1406
|
+
const fileString = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1407
|
+
if (fs3__default__default.existsSync(outputFilePath) && !replaceIfExists) {
|
|
1408
|
+
console.info(`${outputFilePath} already exists`);
|
|
1646
1409
|
return false;
|
|
1647
1410
|
}
|
|
1648
|
-
await
|
|
1411
|
+
await fsExtra.outputFile(outputFilePath, fileString);
|
|
1649
1412
|
return true;
|
|
1650
1413
|
}
|
|
1651
1414
|
async setupEnvFile({ dbUrl }) {
|
|
1652
1415
|
const envPath = path3.join(process.cwd(), ".env.development");
|
|
1653
|
-
await
|
|
1416
|
+
await fsExtra.ensureFile(envPath);
|
|
1654
1417
|
const fileEnvService = new FileEnvService(envPath);
|
|
1655
1418
|
await fileEnvService.setEnvValue("DB_URL", dbUrl);
|
|
1656
1419
|
}
|
|
1657
1420
|
getFirstExistingFile(files) {
|
|
1658
1421
|
for (const f of files) {
|
|
1659
|
-
if (
|
|
1422
|
+
if (fs3__default__default.existsSync(f)) {
|
|
1660
1423
|
return f;
|
|
1661
1424
|
}
|
|
1662
1425
|
}
|
|
@@ -1666,61 +1429,162 @@ var FileService = class {
|
|
|
1666
1429
|
filePath,
|
|
1667
1430
|
replacements
|
|
1668
1431
|
}) {
|
|
1669
|
-
let fileContent =
|
|
1432
|
+
let fileContent = fs3__default__default.readFileSync(filePath, "utf8");
|
|
1670
1433
|
replacements.forEach(({ search, replace }) => {
|
|
1671
1434
|
fileContent = fileContent.replaceAll(search, replace);
|
|
1672
1435
|
});
|
|
1673
|
-
|
|
1436
|
+
fs3__default__default.writeFileSync(filePath, fileContent);
|
|
1674
1437
|
}
|
|
1675
1438
|
};
|
|
1676
|
-
var
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
case "cerebras":
|
|
1680
|
-
return "^0.2.14";
|
|
1681
|
-
default:
|
|
1682
|
-
return "^1.0.0";
|
|
1683
|
-
}
|
|
1439
|
+
var createArgs = (versionTag) => {
|
|
1440
|
+
const packageName = versionTag ? `@mastra/mcp-docs-server@${versionTag}` : "@mastra/mcp-docs-server";
|
|
1441
|
+
return ["-y", packageName];
|
|
1684
1442
|
};
|
|
1685
|
-
var
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1443
|
+
var createMcpConfig = (editor, versionTag) => {
|
|
1444
|
+
const args = createArgs(versionTag);
|
|
1445
|
+
if (editor === "vscode") {
|
|
1446
|
+
return {
|
|
1447
|
+
servers: {
|
|
1448
|
+
mastra: process.platform === `win32` ? {
|
|
1449
|
+
command: "cmd",
|
|
1450
|
+
args: ["/c", "npx", ...args],
|
|
1451
|
+
type: "stdio"
|
|
1452
|
+
} : {
|
|
1453
|
+
command: "npx",
|
|
1454
|
+
args,
|
|
1455
|
+
type: "stdio"
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
};
|
|
1699
1459
|
}
|
|
1460
|
+
return {
|
|
1461
|
+
mcpServers: {
|
|
1462
|
+
mastra: {
|
|
1463
|
+
command: "npx",
|
|
1464
|
+
args
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1700
1468
|
};
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1469
|
+
function makeConfig(original, editor, versionTag) {
|
|
1470
|
+
if (editor === "vscode") {
|
|
1471
|
+
return {
|
|
1472
|
+
...original,
|
|
1473
|
+
servers: {
|
|
1474
|
+
...original?.servers || {},
|
|
1475
|
+
...createMcpConfig(editor, versionTag).servers
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
return {
|
|
1480
|
+
...original,
|
|
1481
|
+
mcpServers: {
|
|
1482
|
+
...original?.mcpServers || {},
|
|
1483
|
+
...createMcpConfig(editor, versionTag).mcpServers
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
async function writeMergedConfig(configPath, editor, versionTag) {
|
|
1488
|
+
const configExists = existsSync(configPath);
|
|
1489
|
+
const config = makeConfig(configExists ? await readJSON(configPath) : {}, editor, versionTag);
|
|
1490
|
+
await ensureFile(configPath);
|
|
1491
|
+
await writeJSON(configPath, config, {
|
|
1492
|
+
spaces: 2
|
|
1493
|
+
});
|
|
1494
|
+
}
|
|
1495
|
+
var windsurfGlobalMCPConfigPath = path3.join(os.homedir(), ".codeium", "windsurf", "mcp_config.json");
|
|
1496
|
+
var antigravityGlobalMCPConfigPath = path3.join(os.homedir(), ".gemini", "antigravity", "mcp_config.json");
|
|
1497
|
+
var cursorGlobalMCPConfigPath = path3.join(os.homedir(), ".cursor", "mcp.json");
|
|
1498
|
+
path3.join(process.cwd(), ".vscode", "mcp.json");
|
|
1499
|
+
var vscodeGlobalMCPConfigPath = path3.join(
|
|
1500
|
+
os.homedir(),
|
|
1501
|
+
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")
|
|
1502
|
+
);
|
|
1503
|
+
async function installMastraDocsMCPServer({
|
|
1504
|
+
editor,
|
|
1505
|
+
directory,
|
|
1506
|
+
versionTag
|
|
1507
|
+
}) {
|
|
1508
|
+
if (editor === `cursor`) {
|
|
1509
|
+
await writeMergedConfig(path3.join(directory, ".cursor", "mcp.json"), "cursor", versionTag);
|
|
1510
|
+
}
|
|
1511
|
+
if (editor === `vscode`) {
|
|
1512
|
+
await writeMergedConfig(path3.join(directory, ".vscode", "mcp.json"), "vscode", versionTag);
|
|
1513
|
+
}
|
|
1514
|
+
if (editor === `cursor-global`) {
|
|
1515
|
+
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor, versionTag);
|
|
1516
|
+
if (alreadyInstalled) {
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
await writeMergedConfig(cursorGlobalMCPConfigPath, "cursor-global", versionTag);
|
|
1520
|
+
}
|
|
1521
|
+
if (editor === `windsurf`) {
|
|
1522
|
+
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor, versionTag);
|
|
1523
|
+
if (alreadyInstalled) {
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
await writeMergedConfig(windsurfGlobalMCPConfigPath, editor, versionTag);
|
|
1527
|
+
}
|
|
1528
|
+
if (editor === `antigravity`) {
|
|
1529
|
+
const alreadyInstalled = await globalMCPIsAlreadyInstalled(editor, versionTag);
|
|
1530
|
+
if (alreadyInstalled) {
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
await writeMergedConfig(antigravityGlobalMCPConfigPath, editor, versionTag);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
async function globalMCPIsAlreadyInstalled(editor, versionTag) {
|
|
1537
|
+
let configPath = ``;
|
|
1538
|
+
if (editor === "windsurf") {
|
|
1539
|
+
configPath = windsurfGlobalMCPConfigPath;
|
|
1540
|
+
} else if (editor === "antigravity") {
|
|
1541
|
+
configPath = antigravityGlobalMCPConfigPath;
|
|
1542
|
+
} else if (editor === "cursor-global") {
|
|
1543
|
+
configPath = cursorGlobalMCPConfigPath;
|
|
1544
|
+
} else if (editor === "vscode") {
|
|
1545
|
+
configPath = vscodeGlobalMCPConfigPath;
|
|
1546
|
+
}
|
|
1547
|
+
if (!configPath || !existsSync(configPath)) {
|
|
1548
|
+
return false;
|
|
1549
|
+
}
|
|
1550
|
+
try {
|
|
1551
|
+
const configContents = await readJSON(configPath);
|
|
1552
|
+
if (!configContents) return false;
|
|
1553
|
+
const expectedPackage = versionTag ? `@mastra/mcp-docs-server@${versionTag}` : "@mastra/mcp-docs-server";
|
|
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 === expectedPackage)
|
|
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 === expectedPackage)
|
|
1564
|
+
);
|
|
1565
|
+
return hasMastraMCP;
|
|
1566
|
+
} catch {
|
|
1567
|
+
return false;
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
var exec = util.promisify(child_process.exec);
|
|
1571
|
+
var getModelIdentifier = (llmProvider) => {
|
|
1572
|
+
let model = "openai/gpt-4o";
|
|
1573
|
+
if (llmProvider === "anthropic") {
|
|
1574
|
+
model = "anthropic/claude-sonnet-4-5";
|
|
1710
1575
|
} else if (llmProvider === "groq") {
|
|
1711
|
-
|
|
1712
|
-
modelItem = `groq('llama-3.3-70b-versatile')`;
|
|
1576
|
+
model = "groq/llama-3.3-70b-versatile";
|
|
1713
1577
|
} else if (llmProvider === "google") {
|
|
1714
|
-
|
|
1715
|
-
modelItem = `google('gemini-2.5-pro')`;
|
|
1578
|
+
model = "google/gemini-2.5-pro";
|
|
1716
1579
|
} else if (llmProvider === "cerebras") {
|
|
1717
|
-
|
|
1718
|
-
|
|
1580
|
+
model = "cerebras/llama-3.3-70b";
|
|
1581
|
+
} else if (llmProvider === "mistral") {
|
|
1582
|
+
model = "mistral/mistral-medium-2508";
|
|
1719
1583
|
}
|
|
1720
|
-
return
|
|
1584
|
+
return model;
|
|
1721
1585
|
};
|
|
1722
|
-
async function writeAgentSample(llmProvider, destPath, addExampleTool) {
|
|
1723
|
-
const
|
|
1586
|
+
async function writeAgentSample(llmProvider, destPath, addExampleTool, addScorers) {
|
|
1587
|
+
const modelString = getModelIdentifier(llmProvider);
|
|
1724
1588
|
const instructions = `
|
|
1725
1589
|
You are a helpful weather assistant that provides accurate weather information and can help planning activities based on the weather.
|
|
1726
1590
|
|
|
@@ -1736,30 +1600,49 @@ async function writeAgentSample(llmProvider, destPath, addExampleTool) {
|
|
|
1736
1600
|
${addExampleTool ? "Use the weatherTool to fetch current weather data." : ""}
|
|
1737
1601
|
`;
|
|
1738
1602
|
const content = `
|
|
1739
|
-
${providerImport}
|
|
1740
1603
|
import { Agent } from '@mastra/core/agent';
|
|
1741
1604
|
import { Memory } from '@mastra/memory';
|
|
1742
|
-
import { LibSQLStore } from '@mastra/libsql';
|
|
1743
1605
|
${addExampleTool ? `import { weatherTool } from '../tools/weather-tool';` : ""}
|
|
1606
|
+
${addScorers ? `import { scorers } from '../scorers/weather-scorer';` : ""}
|
|
1744
1607
|
|
|
1745
1608
|
export const weatherAgent = new Agent({
|
|
1609
|
+
id: 'weather-agent',
|
|
1746
1610
|
name: 'Weather Agent',
|
|
1747
1611
|
instructions: \`${instructions}\`,
|
|
1748
|
-
model: ${
|
|
1612
|
+
model: '${modelString}',
|
|
1749
1613
|
${addExampleTool ? "tools: { weatherTool }," : ""}
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1614
|
+
${addScorers ? `scorers: {
|
|
1615
|
+
toolCallAppropriateness: {
|
|
1616
|
+
scorer: scorers.toolCallAppropriatenessScorer,
|
|
1617
|
+
sampling: {
|
|
1618
|
+
type: 'ratio',
|
|
1619
|
+
rate: 1,
|
|
1620
|
+
},
|
|
1621
|
+
},
|
|
1622
|
+
completeness: {
|
|
1623
|
+
scorer: scorers.completenessScorer,
|
|
1624
|
+
sampling: {
|
|
1625
|
+
type: 'ratio',
|
|
1626
|
+
rate: 1,
|
|
1627
|
+
},
|
|
1628
|
+
},
|
|
1629
|
+
translation: {
|
|
1630
|
+
scorer: scorers.translationScorer,
|
|
1631
|
+
sampling: {
|
|
1632
|
+
type: 'ratio',
|
|
1633
|
+
rate: 1,
|
|
1634
|
+
},
|
|
1635
|
+
},
|
|
1636
|
+
},` : ""}
|
|
1637
|
+
memory: new Memory()
|
|
1755
1638
|
});
|
|
1756
1639
|
`;
|
|
1757
1640
|
const formattedContent = await prettier.format(content, {
|
|
1758
1641
|
parser: "typescript",
|
|
1759
1642
|
singleQuote: true
|
|
1760
1643
|
});
|
|
1761
|
-
await
|
|
1762
|
-
await
|
|
1644
|
+
await fs4.writeFile(destPath, "");
|
|
1645
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1763
1646
|
}
|
|
1764
1647
|
async function writeWorkflowSample(destPath) {
|
|
1765
1648
|
const content = `import { createStep, createWorkflow } from '@mastra/core/workflows';
|
|
@@ -1952,72 +1835,176 @@ export { weatherWorkflow };`;
|
|
|
1952
1835
|
semi: true,
|
|
1953
1836
|
singleQuote: true
|
|
1954
1837
|
});
|
|
1955
|
-
await
|
|
1838
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1956
1839
|
}
|
|
1957
1840
|
async function writeToolSample(destPath) {
|
|
1958
1841
|
const fileService = new FileService();
|
|
1959
1842
|
await fileService.copyStarterFile("tools.ts", destPath);
|
|
1960
1843
|
}
|
|
1844
|
+
async function writeScorersSample(llmProvider, destPath) {
|
|
1845
|
+
const modelString = getModelIdentifier(llmProvider);
|
|
1846
|
+
const content = `import { z } from 'zod';
|
|
1847
|
+
import { createToolCallAccuracyScorerCode } from '@mastra/evals/scorers/prebuilt';
|
|
1848
|
+
import { createCompletenessScorer } from '@mastra/evals/scorers/prebuilt';
|
|
1849
|
+
import { getAssistantMessageFromRunOutput, getUserMessageFromRunInput } from '@mastra/evals/scorers/utils';
|
|
1850
|
+
import { createScorer } from '@mastra/core/evals';
|
|
1851
|
+
|
|
1852
|
+
export const toolCallAppropriatenessScorer = createToolCallAccuracyScorerCode({
|
|
1853
|
+
expectedTool: 'weatherTool',
|
|
1854
|
+
strictMode: false,
|
|
1855
|
+
});
|
|
1856
|
+
|
|
1857
|
+
export const completenessScorer = createCompletenessScorer();
|
|
1858
|
+
|
|
1859
|
+
// Custom LLM-judged scorer: evaluates if non-English locations are translated appropriately
|
|
1860
|
+
export const translationScorer = createScorer({
|
|
1861
|
+
id: 'translation-quality-scorer',
|
|
1862
|
+
name: 'Translation Quality',
|
|
1863
|
+
description: 'Checks that non-English location names are translated and used correctly',
|
|
1864
|
+
type: 'agent',
|
|
1865
|
+
judge: {
|
|
1866
|
+
model: '${modelString}',
|
|
1867
|
+
instructions:
|
|
1868
|
+
'You are an expert evaluator of translation quality for geographic locations. ' +
|
|
1869
|
+
'Determine whether the user text mentions a non-English location and whether the assistant correctly uses an English translation of that location. ' +
|
|
1870
|
+
'Be lenient with transliteration differences and diacritics. ' +
|
|
1871
|
+
'Return only the structured JSON matching the provided schema.',
|
|
1872
|
+
},
|
|
1873
|
+
})
|
|
1874
|
+
.preprocess(({ run }) => {
|
|
1875
|
+
const userText = getUserMessageFromRunInput(run.input) || '';
|
|
1876
|
+
const assistantText = getAssistantMessageFromRunOutput(run.output) || '';
|
|
1877
|
+
return { userText, assistantText };
|
|
1878
|
+
})
|
|
1879
|
+
.analyze({
|
|
1880
|
+
description: 'Extract location names and detect language/translation adequacy',
|
|
1881
|
+
outputSchema: z.object({
|
|
1882
|
+
nonEnglish: z.boolean(),
|
|
1883
|
+
translated: z.boolean(),
|
|
1884
|
+
confidence: z.number().min(0).max(1).default(1),
|
|
1885
|
+
explanation: z.string().default(''),
|
|
1886
|
+
}),
|
|
1887
|
+
createPrompt: ({ results }) => \`
|
|
1888
|
+
You are evaluating if a weather assistant correctly handled translation of a non-English location.
|
|
1889
|
+
User text:
|
|
1890
|
+
"""
|
|
1891
|
+
\${results.preprocessStepResult.userText}
|
|
1892
|
+
"""
|
|
1893
|
+
Assistant response:
|
|
1894
|
+
"""
|
|
1895
|
+
\${results.preprocessStepResult.assistantText}
|
|
1896
|
+
"""
|
|
1897
|
+
Tasks:
|
|
1898
|
+
1) Identify if the user mentioned a location that appears non-English.
|
|
1899
|
+
2) If non-English, check whether the assistant used a correct English translation of that location in its response.
|
|
1900
|
+
3) Be lenient with transliteration differences (e.g., accents/diacritics).
|
|
1901
|
+
Return JSON with fields:
|
|
1902
|
+
{
|
|
1903
|
+
"nonEnglish": boolean,
|
|
1904
|
+
"translated": boolean,
|
|
1905
|
+
"confidence": number, // 0-1
|
|
1906
|
+
"explanation": string
|
|
1907
|
+
}
|
|
1908
|
+
\`,
|
|
1909
|
+
})
|
|
1910
|
+
.generateScore(({ results }) => {
|
|
1911
|
+
const r = (results as any)?.analyzeStepResult || {};
|
|
1912
|
+
if (!r.nonEnglish) return 1; // If not applicable, full credit
|
|
1913
|
+
if (r.translated) return Math.max(0, Math.min(1, 0.7 + 0.3 * (r.confidence ?? 1)));
|
|
1914
|
+
return 0; // Non-English but not translated
|
|
1915
|
+
})
|
|
1916
|
+
.generateReason(({ results, score }) => {
|
|
1917
|
+
const r = (results as any)?.analyzeStepResult || {};
|
|
1918
|
+
return \`Translation scoring: nonEnglish=\${r.nonEnglish ?? false}, translated=\${r.translated ?? false}, confidence=\${r.confidence ?? 0}. Score=\${score}. \${r.explanation ?? ''}\`;
|
|
1919
|
+
});
|
|
1920
|
+
|
|
1921
|
+
export const scorers = {
|
|
1922
|
+
toolCallAppropriatenessScorer,
|
|
1923
|
+
completenessScorer,
|
|
1924
|
+
translationScorer,
|
|
1925
|
+
};`;
|
|
1926
|
+
const formattedContent = await prettier.format(content, {
|
|
1927
|
+
parser: "typescript",
|
|
1928
|
+
singleQuote: true
|
|
1929
|
+
});
|
|
1930
|
+
await fs4.writeFile(destPath, formattedContent);
|
|
1931
|
+
}
|
|
1961
1932
|
async function writeCodeSampleForComponents(llmprovider, component, destPath, importComponents) {
|
|
1962
1933
|
switch (component) {
|
|
1963
1934
|
case "agents":
|
|
1964
|
-
return writeAgentSample(
|
|
1935
|
+
return writeAgentSample(
|
|
1936
|
+
llmprovider,
|
|
1937
|
+
destPath,
|
|
1938
|
+
importComponents.includes("tools"),
|
|
1939
|
+
importComponents.includes("scorers")
|
|
1940
|
+
);
|
|
1965
1941
|
case "tools":
|
|
1966
1942
|
return writeToolSample(destPath);
|
|
1967
1943
|
case "workflows":
|
|
1968
1944
|
return writeWorkflowSample(destPath);
|
|
1945
|
+
case "scorers":
|
|
1946
|
+
return writeScorersSample(llmprovider, destPath);
|
|
1969
1947
|
default:
|
|
1970
1948
|
return "";
|
|
1971
1949
|
}
|
|
1972
1950
|
}
|
|
1973
1951
|
var createComponentsDir = async (dirPath, component) => {
|
|
1974
1952
|
const componentPath = dirPath + `/${component}`;
|
|
1975
|
-
await
|
|
1953
|
+
await fsExtra.ensureDir(componentPath);
|
|
1976
1954
|
};
|
|
1977
1955
|
var writeIndexFile = async ({
|
|
1978
1956
|
dirPath,
|
|
1979
1957
|
addAgent,
|
|
1980
1958
|
addExample,
|
|
1981
|
-
addWorkflow
|
|
1959
|
+
addWorkflow,
|
|
1960
|
+
addScorers
|
|
1982
1961
|
}) => {
|
|
1983
1962
|
const indexPath = dirPath + "/index.ts";
|
|
1984
1963
|
const destPath = path3.join(indexPath);
|
|
1985
1964
|
try {
|
|
1986
|
-
await
|
|
1965
|
+
await fs4.writeFile(destPath, "");
|
|
1987
1966
|
const filteredExports = [
|
|
1988
1967
|
addWorkflow ? `workflows: { weatherWorkflow },` : "",
|
|
1989
|
-
addAgent ? `agents: { weatherAgent },` : ""
|
|
1968
|
+
addAgent ? `agents: { weatherAgent },` : "",
|
|
1969
|
+
addScorers ? `scorers: { toolCallAppropriatenessScorer, completenessScorer, translationScorer },` : ""
|
|
1990
1970
|
].filter(Boolean);
|
|
1991
1971
|
if (!addExample) {
|
|
1992
|
-
await
|
|
1972
|
+
await fs4.writeFile(
|
|
1993
1973
|
destPath,
|
|
1994
1974
|
`
|
|
1995
|
-
import { Mastra } from '@mastra/core';
|
|
1975
|
+
import { Mastra } from '@mastra/core/mastra';
|
|
1996
1976
|
|
|
1997
1977
|
export const mastra = new Mastra()
|
|
1998
1978
|
`
|
|
1999
1979
|
);
|
|
2000
1980
|
return;
|
|
2001
1981
|
}
|
|
2002
|
-
await
|
|
1982
|
+
await fs4.writeFile(
|
|
2003
1983
|
destPath,
|
|
2004
1984
|
`
|
|
2005
1985
|
import { Mastra } from '@mastra/core/mastra';
|
|
2006
1986
|
import { PinoLogger } from '@mastra/loggers';
|
|
2007
1987
|
import { LibSQLStore } from '@mastra/libsql';
|
|
1988
|
+
import { Observability } from '@mastra/observability';
|
|
2008
1989
|
${addWorkflow ? `import { weatherWorkflow } from './workflows/weather-workflow';` : ""}
|
|
2009
1990
|
${addAgent ? `import { weatherAgent } from './agents/weather-agent';` : ""}
|
|
1991
|
+
${addScorers ? `import { toolCallAppropriatenessScorer, completenessScorer, translationScorer } from './scorers/weather-scorer';` : ""}
|
|
2010
1992
|
|
|
2011
1993
|
export const mastra = new Mastra({
|
|
2012
1994
|
${filteredExports.join("\n ")}
|
|
2013
1995
|
storage: new LibSQLStore({
|
|
2014
|
-
|
|
1996
|
+
id: "mastra-storage",
|
|
1997
|
+
// stores observability, scores, ... into memory storage, if it needs to persist, change to file:../mastra.db
|
|
2015
1998
|
url: ":memory:",
|
|
2016
1999
|
}),
|
|
2017
2000
|
logger: new PinoLogger({
|
|
2018
2001
|
name: 'Mastra',
|
|
2019
2002
|
level: 'info',
|
|
2020
2003
|
}),
|
|
2004
|
+
observability: new Observability({
|
|
2005
|
+
// Enables DefaultExporter and CloudExporter for tracing
|
|
2006
|
+
default: { enabled: true },
|
|
2007
|
+
}),
|
|
2021
2008
|
});
|
|
2022
2009
|
`
|
|
2023
2010
|
);
|
|
@@ -2025,7 +2012,6 @@ export const mastra = new Mastra({
|
|
|
2025
2012
|
throw err;
|
|
2026
2013
|
}
|
|
2027
2014
|
};
|
|
2028
|
-
yoctoSpinner({ text: "Installing Mastra core dependencies\n" });
|
|
2029
2015
|
var getAPIKey = async (provider) => {
|
|
2030
2016
|
let key = "OPENAI_API_KEY";
|
|
2031
2017
|
switch (provider) {
|
|
@@ -2041,27 +2027,28 @@ var getAPIKey = async (provider) => {
|
|
|
2041
2027
|
case "cerebras":
|
|
2042
2028
|
key = "CEREBRAS_API_KEY";
|
|
2043
2029
|
return key;
|
|
2030
|
+
case "mistral":
|
|
2031
|
+
key = "MISTRAL_API_KEY";
|
|
2032
|
+
return key;
|
|
2044
2033
|
default:
|
|
2045
2034
|
return key;
|
|
2046
2035
|
}
|
|
2047
2036
|
};
|
|
2048
|
-
var writeAPIKey = async ({
|
|
2049
|
-
|
|
2050
|
-
apiKey = "your-api-key"
|
|
2051
|
-
}) => {
|
|
2037
|
+
var writeAPIKey = async ({ provider, apiKey }) => {
|
|
2038
|
+
const envFileName = apiKey ? ".env" : ".env.example";
|
|
2052
2039
|
const key = await getAPIKey(provider);
|
|
2053
|
-
const escapedKey =
|
|
2054
|
-
const escapedApiKey =
|
|
2055
|
-
await
|
|
2040
|
+
const escapedKey = shellQuote2.quote([key]);
|
|
2041
|
+
const escapedApiKey = shellQuote2.quote([apiKey ? apiKey : "your-api-key"]);
|
|
2042
|
+
await exec(`echo ${escapedKey}=${escapedApiKey} >> ${envFileName}`);
|
|
2056
2043
|
};
|
|
2057
2044
|
var createMastraDir = async (directory) => {
|
|
2058
2045
|
let dir = directory.trim().split("/").filter((item) => item !== "");
|
|
2059
2046
|
const dirPath = path3.join(process.cwd(), ...dir, "mastra");
|
|
2060
2047
|
try {
|
|
2061
|
-
await
|
|
2048
|
+
await fs4.access(dirPath);
|
|
2062
2049
|
return { ok: false };
|
|
2063
2050
|
} catch {
|
|
2064
|
-
await
|
|
2051
|
+
await fsExtra.ensureDir(dirPath);
|
|
2065
2052
|
return { ok: true, dirPath };
|
|
2066
2053
|
}
|
|
2067
2054
|
};
|
|
@@ -2073,8 +2060,19 @@ var writeCodeSample = async (dirPath, component, llmProvider, importComponents)
|
|
|
2073
2060
|
throw err;
|
|
2074
2061
|
}
|
|
2075
2062
|
};
|
|
2076
|
-
var
|
|
2077
|
-
|
|
2063
|
+
var LLM_PROVIDERS = [
|
|
2064
|
+
{ value: "openai", label: "OpenAI", hint: "recommended" },
|
|
2065
|
+
{ value: "anthropic", label: "Anthropic" },
|
|
2066
|
+
{ value: "groq", label: "Groq" },
|
|
2067
|
+
{ value: "google", label: "Google" },
|
|
2068
|
+
{ value: "cerebras", label: "Cerebras" },
|
|
2069
|
+
{ value: "mistral", label: "Mistral" }
|
|
2070
|
+
];
|
|
2071
|
+
var interactivePrompt = async (args = {}) => {
|
|
2072
|
+
const { skip = {}, options: { showBanner = true } = {} } = args;
|
|
2073
|
+
if (showBanner) {
|
|
2074
|
+
Ie(color2.inverse(" Mastra Init "));
|
|
2075
|
+
}
|
|
2078
2076
|
const mastraProject = await Ce(
|
|
2079
2077
|
{
|
|
2080
2078
|
directory: () => he({
|
|
@@ -2082,19 +2080,15 @@ var interactivePrompt = async () => {
|
|
|
2082
2080
|
placeholder: "src/",
|
|
2083
2081
|
defaultValue: "src/"
|
|
2084
2082
|
}),
|
|
2085
|
-
llmProvider: () => ve({
|
|
2086
|
-
message: "Select default provider:",
|
|
2087
|
-
options:
|
|
2088
|
-
{ value: "openai", label: "OpenAI", hint: "recommended" },
|
|
2089
|
-
{ value: "anthropic", label: "Anthropic" },
|
|
2090
|
-
{ value: "groq", label: "Groq" },
|
|
2091
|
-
{ value: "google", label: "Google" },
|
|
2092
|
-
{ value: "cerebras", label: "Cerebras" }
|
|
2093
|
-
]
|
|
2083
|
+
llmProvider: () => skip?.llmProvider ? void 0 : ve({
|
|
2084
|
+
message: "Select a default provider:",
|
|
2085
|
+
options: LLM_PROVIDERS
|
|
2094
2086
|
}),
|
|
2095
2087
|
llmApiKey: async ({ results: { llmProvider } }) => {
|
|
2088
|
+
if (skip?.llmApiKey) return void 0;
|
|
2089
|
+
const llmName = LLM_PROVIDERS.find((p6) => p6.value === llmProvider)?.label || "provider";
|
|
2096
2090
|
const keyChoice = await ve({
|
|
2097
|
-
message: `Enter your ${
|
|
2091
|
+
message: `Enter your ${llmName} API key?`,
|
|
2098
2092
|
options: [
|
|
2099
2093
|
{ value: "skip", label: "Skip for now", hint: "default" },
|
|
2100
2094
|
{ value: "enter", label: "Enter API key" }
|
|
@@ -2104,52 +2098,42 @@ var interactivePrompt = async () => {
|
|
|
2104
2098
|
if (keyChoice === "enter") {
|
|
2105
2099
|
return he({
|
|
2106
2100
|
message: "Enter your API key:",
|
|
2107
|
-
placeholder: "sk-..."
|
|
2101
|
+
placeholder: "sk-...",
|
|
2102
|
+
validate: (value) => {
|
|
2103
|
+
if (value.length === 0) return "API key cannot be empty";
|
|
2104
|
+
}
|
|
2108
2105
|
});
|
|
2109
2106
|
}
|
|
2110
2107
|
return void 0;
|
|
2111
2108
|
},
|
|
2112
2109
|
configureEditorWithDocsMCP: async () => {
|
|
2113
|
-
const windsurfIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`windsurf`);
|
|
2114
|
-
const cursorIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`cursor`);
|
|
2115
|
-
const vscodeIsAlreadyInstalled = await globalMCPIsAlreadyInstalled(`vscode`);
|
|
2116
2110
|
const editor = await ve({
|
|
2117
|
-
message: `Make your
|
|
2111
|
+
message: `Make your IDE into a Mastra expert? (Installs Mastra's MCP server)`,
|
|
2118
2112
|
options: [
|
|
2119
2113
|
{ value: "skip", label: "Skip for now", hint: "default" },
|
|
2120
2114
|
{
|
|
2121
2115
|
value: "cursor",
|
|
2122
|
-
label: "Cursor (project only)"
|
|
2123
|
-
hint: cursorIsAlreadyInstalled ? `Already installed globally` : void 0
|
|
2116
|
+
label: "Cursor (project only)"
|
|
2124
2117
|
},
|
|
2125
2118
|
{
|
|
2126
2119
|
value: "cursor-global",
|
|
2127
|
-
label: "Cursor (global, all projects)"
|
|
2128
|
-
hint: cursorIsAlreadyInstalled ? `Already installed` : void 0
|
|
2120
|
+
label: "Cursor (global, all projects)"
|
|
2129
2121
|
},
|
|
2130
2122
|
{
|
|
2131
2123
|
value: "windsurf",
|
|
2132
|
-
label: "Windsurf"
|
|
2133
|
-
hint: windsurfIsAlreadyInstalled ? `Already installed` : void 0
|
|
2124
|
+
label: "Windsurf"
|
|
2134
2125
|
},
|
|
2135
2126
|
{
|
|
2136
2127
|
value: "vscode",
|
|
2137
|
-
label: "VSCode"
|
|
2138
|
-
|
|
2128
|
+
label: "VSCode"
|
|
2129
|
+
},
|
|
2130
|
+
{
|
|
2131
|
+
value: "antigravity",
|
|
2132
|
+
label: "Antigravity"
|
|
2139
2133
|
}
|
|
2140
2134
|
]
|
|
2141
2135
|
});
|
|
2142
2136
|
if (editor === `skip`) return void 0;
|
|
2143
|
-
if (editor === `windsurf` && windsurfIsAlreadyInstalled) {
|
|
2144
|
-
M.message(`
|
|
2145
|
-
Windsurf is already installed, skipping.`);
|
|
2146
|
-
return void 0;
|
|
2147
|
-
}
|
|
2148
|
-
if (editor === `vscode` && vscodeIsAlreadyInstalled) {
|
|
2149
|
-
M.message(`
|
|
2150
|
-
VSCode is already installed, skipping.`);
|
|
2151
|
-
return void 0;
|
|
2152
|
-
}
|
|
2153
2137
|
if (editor === `cursor`) {
|
|
2154
2138
|
M.message(
|
|
2155
2139
|
`
|
|
@@ -2158,19 +2142,19 @@ Note: you will need to go into Cursor Settings -> MCP Settings and manually enab
|
|
|
2158
2142
|
);
|
|
2159
2143
|
}
|
|
2160
2144
|
if (editor === `cursor-global`) {
|
|
2161
|
-
const
|
|
2145
|
+
const confirm3 = await ve({
|
|
2162
2146
|
message: `Global install will add/update ${cursorGlobalMCPConfigPath} and make the Mastra docs MCP server available in all your Cursor projects. Continue?`,
|
|
2163
2147
|
options: [
|
|
2164
2148
|
{ value: "yes", label: "Yes, I understand" },
|
|
2165
2149
|
{ value: "skip", label: "No, skip for now" }
|
|
2166
2150
|
]
|
|
2167
2151
|
});
|
|
2168
|
-
if (
|
|
2152
|
+
if (confirm3 !== `yes`) {
|
|
2169
2153
|
return void 0;
|
|
2170
2154
|
}
|
|
2171
2155
|
}
|
|
2172
2156
|
if (editor === `windsurf`) {
|
|
2173
|
-
const
|
|
2157
|
+
const confirm3 = await ve({
|
|
2174
2158
|
message: `Windsurf only supports a global MCP config (at ${windsurfGlobalMCPConfigPath}) is it ok to add/update that global config?
|
|
2175
2159
|
This means the Mastra docs MCP server will be available in all your Windsurf projects.`,
|
|
2176
2160
|
options: [
|
|
@@ -2178,11 +2162,31 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2178
2162
|
{ value: "skip", label: "No, skip for now" }
|
|
2179
2163
|
]
|
|
2180
2164
|
});
|
|
2181
|
-
if (
|
|
2165
|
+
if (confirm3 !== `yes`) {
|
|
2166
|
+
return void 0;
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
if (editor === `antigravity`) {
|
|
2170
|
+
const confirm3 = await ve({
|
|
2171
|
+
message: `Antigravity only supports a global MCP config (at ${antigravityGlobalMCPConfigPath}). Is it ok to add/update that global config?
|
|
2172
|
+
This will make the Mastra docs MCP server available in all Antigravity projects.`,
|
|
2173
|
+
options: [
|
|
2174
|
+
{ value: "yes", label: "Yes, I understand" },
|
|
2175
|
+
{ value: "skip", label: "No, skip for now" }
|
|
2176
|
+
]
|
|
2177
|
+
});
|
|
2178
|
+
if (confirm3 !== `yes`) {
|
|
2182
2179
|
return void 0;
|
|
2183
2180
|
}
|
|
2184
2181
|
}
|
|
2185
2182
|
return editor;
|
|
2183
|
+
},
|
|
2184
|
+
initGit: async () => {
|
|
2185
|
+
if (skip?.gitInit) return false;
|
|
2186
|
+
return ye({
|
|
2187
|
+
message: "Initialize a new git repository?",
|
|
2188
|
+
initialValue: true
|
|
2189
|
+
});
|
|
2186
2190
|
}
|
|
2187
2191
|
},
|
|
2188
2192
|
{
|
|
@@ -2194,17 +2198,245 @@ This means the Mastra docs MCP server will be available in all your Windsurf pro
|
|
|
2194
2198
|
);
|
|
2195
2199
|
return mastraProject;
|
|
2196
2200
|
};
|
|
2201
|
+
function getPackageManager() {
|
|
2202
|
+
const userAgent = process.env.npm_config_user_agent || "";
|
|
2203
|
+
const execPath = process.env.npm_execpath || "";
|
|
2204
|
+
if (userAgent.includes("bun")) {
|
|
2205
|
+
return "bun";
|
|
2206
|
+
}
|
|
2207
|
+
if (userAgent.includes("yarn")) {
|
|
2208
|
+
return "yarn";
|
|
2209
|
+
}
|
|
2210
|
+
if (userAgent.includes("pnpm")) {
|
|
2211
|
+
return "pnpm";
|
|
2212
|
+
}
|
|
2213
|
+
if (userAgent.includes("npm")) {
|
|
2214
|
+
return "npm";
|
|
2215
|
+
}
|
|
2216
|
+
if (execPath.includes("bun")) {
|
|
2217
|
+
return "bun";
|
|
2218
|
+
}
|
|
2219
|
+
if (execPath.includes("yarn")) {
|
|
2220
|
+
return "yarn";
|
|
2221
|
+
}
|
|
2222
|
+
if (execPath.includes("pnpm")) {
|
|
2223
|
+
return "pnpm";
|
|
2224
|
+
}
|
|
2225
|
+
if (execPath.includes("npm")) {
|
|
2226
|
+
return "npm";
|
|
2227
|
+
}
|
|
2228
|
+
return "npm";
|
|
2229
|
+
}
|
|
2230
|
+
async function gitInit({ cwd }) {
|
|
2231
|
+
await execa("git", ["init"], { cwd, stdio: "ignore" });
|
|
2232
|
+
await execa("git", ["add", "-A"], { cwd, stdio: "ignore" });
|
|
2233
|
+
await execa(
|
|
2234
|
+
"git",
|
|
2235
|
+
[
|
|
2236
|
+
"commit",
|
|
2237
|
+
"-m",
|
|
2238
|
+
'"Initial commit from Mastra"',
|
|
2239
|
+
'--author="dane-ai-mastra[bot] <dane-ai-mastra[bot]@users.noreply.github.com>"'
|
|
2240
|
+
],
|
|
2241
|
+
{ cwd, stdio: "ignore" }
|
|
2242
|
+
);
|
|
2243
|
+
}
|
|
2244
|
+
var logger = createLogger(false);
|
|
2245
|
+
function createLogger(debug = false) {
|
|
2246
|
+
return new PinoLogger({
|
|
2247
|
+
name: "Mastra CLI",
|
|
2248
|
+
level: debug ? "debug" : "info"
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
var exec2 = util.promisify(child_process.exec);
|
|
2252
|
+
async function cloneTemplate(options) {
|
|
2253
|
+
const { template, projectName, targetDir, branch, llmProvider } = options;
|
|
2254
|
+
const projectPath = targetDir ? path3.resolve(targetDir, projectName) : path3.resolve(projectName);
|
|
2255
|
+
const spinner4 = yoctoSpinner({ text: `Cloning template "${template.title}"...` }).start();
|
|
2256
|
+
try {
|
|
2257
|
+
if (await directoryExists(projectPath)) {
|
|
2258
|
+
spinner4.error(`Directory ${projectName} already exists`);
|
|
2259
|
+
throw new Error(`Directory ${projectName} already exists`);
|
|
2260
|
+
}
|
|
2261
|
+
await cloneRepositoryWithoutGit(template.githubUrl, projectPath, branch);
|
|
2262
|
+
await updatePackageJson(projectPath, projectName);
|
|
2263
|
+
const envExamplePath = path3.join(projectPath, ".env.example");
|
|
2264
|
+
if (await fileExists(envExamplePath)) {
|
|
2265
|
+
const envPath = path3.join(projectPath, ".env");
|
|
2266
|
+
await fs4.copyFile(envExamplePath, envPath);
|
|
2267
|
+
if (llmProvider) {
|
|
2268
|
+
await updateEnvFile(envPath, llmProvider);
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
spinner4.success(`Template "${template.title}" cloned successfully to ${projectName}`);
|
|
2272
|
+
return projectPath;
|
|
2273
|
+
} catch (error) {
|
|
2274
|
+
spinner4.error(`Failed to clone template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2275
|
+
throw error;
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
async function directoryExists(dirPath) {
|
|
2279
|
+
try {
|
|
2280
|
+
const stat = await fs4.stat(dirPath);
|
|
2281
|
+
return stat.isDirectory();
|
|
2282
|
+
} catch {
|
|
2283
|
+
return false;
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
async function fileExists(filePath) {
|
|
2287
|
+
try {
|
|
2288
|
+
const stat = await fs4.stat(filePath);
|
|
2289
|
+
return stat.isFile();
|
|
2290
|
+
} catch {
|
|
2291
|
+
return false;
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
async function cloneRepositoryWithoutGit(repoUrl, targetPath, branch) {
|
|
2295
|
+
await fs4.mkdir(targetPath, { recursive: true });
|
|
2296
|
+
try {
|
|
2297
|
+
const degitRepo = repoUrl.replace("https://github.com/", "");
|
|
2298
|
+
const degitRepoWithBranch = branch ? `${degitRepo}#${branch}` : degitRepo;
|
|
2299
|
+
const degitCommand = shellQuote2.quote(["npx", "degit", degitRepoWithBranch, targetPath]);
|
|
2300
|
+
await exec2(degitCommand, {
|
|
2301
|
+
cwd: process.cwd()
|
|
2302
|
+
});
|
|
2303
|
+
} catch {
|
|
2304
|
+
try {
|
|
2305
|
+
const gitArgs = ["git", "clone"];
|
|
2306
|
+
if (branch) {
|
|
2307
|
+
gitArgs.push("--branch", branch);
|
|
2308
|
+
}
|
|
2309
|
+
gitArgs.push(repoUrl, targetPath);
|
|
2310
|
+
const gitCommand = shellQuote2.quote(gitArgs);
|
|
2311
|
+
await exec2(gitCommand, {
|
|
2312
|
+
cwd: process.cwd()
|
|
2313
|
+
});
|
|
2314
|
+
const gitDir = path3.join(targetPath, ".git");
|
|
2315
|
+
if (await directoryExists(gitDir)) {
|
|
2316
|
+
await fs4.rm(gitDir, { recursive: true, force: true });
|
|
2317
|
+
}
|
|
2318
|
+
} catch (gitError) {
|
|
2319
|
+
throw new Error(`Failed to clone repository: ${gitError instanceof Error ? gitError.message : "Unknown error"}`);
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
async function updatePackageJson(projectPath, projectName) {
|
|
2324
|
+
const packageJsonPath = path3.join(projectPath, "package.json");
|
|
2325
|
+
try {
|
|
2326
|
+
const packageJsonContent = await fs4.readFile(packageJsonPath, "utf-8");
|
|
2327
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
2328
|
+
packageJson.name = projectName;
|
|
2329
|
+
await fs4.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
2330
|
+
} catch (error) {
|
|
2331
|
+
logger.warn(`Could not update package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
async function updateEnvFile(envPath, llmProvider) {
|
|
2335
|
+
try {
|
|
2336
|
+
const envContent = await fs4.readFile(envPath, "utf-8");
|
|
2337
|
+
const modelString = getModelIdentifier(llmProvider);
|
|
2338
|
+
if (!modelString) {
|
|
2339
|
+
logger.warn(`Could not get model identifier for provider: ${llmProvider}`);
|
|
2340
|
+
return;
|
|
2341
|
+
}
|
|
2342
|
+
const modelValue = modelString.replace(/'/g, "");
|
|
2343
|
+
const updatedContent = envContent.replace(/^MODEL=.*/m, `MODEL=${modelValue}`);
|
|
2344
|
+
await fs4.writeFile(envPath, updatedContent, "utf-8");
|
|
2345
|
+
logger.info(`Updated MODEL in .env to ${modelValue}`);
|
|
2346
|
+
} catch (error) {
|
|
2347
|
+
logger.warn(`Could not update .env file: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
async function installDependencies(projectPath, packageManager) {
|
|
2351
|
+
const spinner4 = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
2352
|
+
try {
|
|
2353
|
+
const pm = packageManager || getPackageManager();
|
|
2354
|
+
const installCommand = shellQuote2.quote([pm, "install"]);
|
|
2355
|
+
await exec2(installCommand, {
|
|
2356
|
+
cwd: projectPath
|
|
2357
|
+
});
|
|
2358
|
+
spinner4.success("Dependencies installed successfully");
|
|
2359
|
+
} catch (error) {
|
|
2360
|
+
spinner4.error(`Failed to install dependencies: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2361
|
+
throw error;
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
var TEMPLATES_API_URL = process.env.MASTRA_TEMPLATES_API_URL || "https://mastra.ai/api/templates.json";
|
|
2365
|
+
async function loadTemplates() {
|
|
2366
|
+
try {
|
|
2367
|
+
const response = await fetch(TEMPLATES_API_URL);
|
|
2368
|
+
if (!response.ok) {
|
|
2369
|
+
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
2370
|
+
}
|
|
2371
|
+
const templates = await response.json();
|
|
2372
|
+
return templates;
|
|
2373
|
+
} catch (error) {
|
|
2374
|
+
console.error("Error loading templates:", error);
|
|
2375
|
+
throw new Error("Failed to load templates. Please check your internet connection and try again.");
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
function pluralize(count, singular, plural) {
|
|
2379
|
+
return count === 1 ? singular : plural || `${singular}s`;
|
|
2380
|
+
}
|
|
2381
|
+
async function selectTemplate(templates) {
|
|
2382
|
+
const choices = templates.map((template) => {
|
|
2383
|
+
const parts = [];
|
|
2384
|
+
if (template.agents?.length) {
|
|
2385
|
+
parts.push(`${template.agents.length} ${pluralize(template.agents.length, "agent")}`);
|
|
2386
|
+
}
|
|
2387
|
+
if (template.tools?.length) {
|
|
2388
|
+
parts.push(`${template.tools.length} ${pluralize(template.tools.length, "tool")}`);
|
|
2389
|
+
}
|
|
2390
|
+
if (template.workflows?.length) {
|
|
2391
|
+
parts.push(`${template.workflows.length} ${pluralize(template.workflows.length, "workflow")}`);
|
|
2392
|
+
}
|
|
2393
|
+
if (template.mcp?.length) {
|
|
2394
|
+
parts.push(`${template.mcp.length} ${pluralize(template.mcp.length, "MCP server")}`);
|
|
2395
|
+
}
|
|
2396
|
+
if (template.networks?.length) {
|
|
2397
|
+
parts.push(`${template.networks.length} ${pluralize(template.networks.length, "agent network")}`);
|
|
2398
|
+
}
|
|
2399
|
+
return {
|
|
2400
|
+
value: template,
|
|
2401
|
+
label: template.title,
|
|
2402
|
+
hint: parts.join(", ") || "Template components"
|
|
2403
|
+
};
|
|
2404
|
+
});
|
|
2405
|
+
const selected = await ve({
|
|
2406
|
+
message: "Select a template:",
|
|
2407
|
+
options: choices
|
|
2408
|
+
});
|
|
2409
|
+
if (pD(selected)) {
|
|
2410
|
+
return null;
|
|
2411
|
+
}
|
|
2412
|
+
return selected;
|
|
2413
|
+
}
|
|
2414
|
+
function findTemplateByName(templates, templateName) {
|
|
2415
|
+
let template = templates.find((t) => t.slug === templateName);
|
|
2416
|
+
if (template) return template;
|
|
2417
|
+
const slugWithPrefix = `template-${templateName}`;
|
|
2418
|
+
template = templates.find((t) => t.slug === slugWithPrefix);
|
|
2419
|
+
if (template) return template;
|
|
2420
|
+
template = templates.find((t) => t.title.toLowerCase() === templateName.toLowerCase());
|
|
2421
|
+
if (template) return template;
|
|
2422
|
+
return null;
|
|
2423
|
+
}
|
|
2424
|
+
function getDefaultProjectName(template) {
|
|
2425
|
+
return template.slug.replace(/^template-/, "");
|
|
2426
|
+
}
|
|
2197
2427
|
var s = Y();
|
|
2198
|
-
var exec3 = util.promisify(child_process.exec);
|
|
2199
2428
|
var init = async ({
|
|
2200
|
-
directory,
|
|
2201
|
-
addExample = false,
|
|
2429
|
+
directory = "src/",
|
|
2202
2430
|
components,
|
|
2203
2431
|
llmProvider = "openai",
|
|
2204
2432
|
llmApiKey,
|
|
2205
|
-
|
|
2433
|
+
addExample = false,
|
|
2434
|
+
configureEditorWithDocsMCP,
|
|
2435
|
+
versionTag,
|
|
2436
|
+
initGit = false
|
|
2206
2437
|
}) => {
|
|
2207
2438
|
s.start("Initializing Mastra");
|
|
2439
|
+
const packageVersionTag = versionTag ? `@${versionTag}` : "";
|
|
2208
2440
|
try {
|
|
2209
2441
|
const result = await createMastraDir(directory);
|
|
2210
2442
|
if (!result.ok) {
|
|
@@ -2217,7 +2449,8 @@ var init = async ({
|
|
|
2217
2449
|
dirPath,
|
|
2218
2450
|
addExample,
|
|
2219
2451
|
addWorkflow: components.includes("workflows"),
|
|
2220
|
-
addAgent: components.includes("agents")
|
|
2452
|
+
addAgent: components.includes("agents"),
|
|
2453
|
+
addScorers: components.includes("scorers")
|
|
2221
2454
|
}),
|
|
2222
2455
|
...components.map((component) => createComponentsDir(dirPath, component)),
|
|
2223
2456
|
writeAPIKey({ provider: llmProvider, apiKey: llmApiKey })
|
|
@@ -2231,31 +2464,44 @@ var init = async ({
|
|
|
2231
2464
|
const depService = new DepsService();
|
|
2232
2465
|
const needsLibsql = await depService.checkDependencies(["@mastra/libsql"]) !== `ok`;
|
|
2233
2466
|
if (needsLibsql) {
|
|
2234
|
-
await depService.installPackages([
|
|
2467
|
+
await depService.installPackages([`@mastra/libsql${packageVersionTag}`]);
|
|
2235
2468
|
}
|
|
2236
2469
|
const needsMemory = components.includes(`agents`) && await depService.checkDependencies(["@mastra/memory"]) !== `ok`;
|
|
2237
2470
|
if (needsMemory) {
|
|
2238
|
-
await depService.installPackages([
|
|
2471
|
+
await depService.installPackages([`@mastra/memory${packageVersionTag}`]);
|
|
2239
2472
|
}
|
|
2240
2473
|
const needsLoggers = await depService.checkDependencies(["@mastra/loggers"]) !== `ok`;
|
|
2241
2474
|
if (needsLoggers) {
|
|
2242
|
-
await depService.installPackages([
|
|
2475
|
+
await depService.installPackages([`@mastra/loggers${packageVersionTag}`]);
|
|
2476
|
+
}
|
|
2477
|
+
const needsObservability = await depService.checkDependencies(["@mastra/observability"]) !== `ok`;
|
|
2478
|
+
if (needsObservability) {
|
|
2479
|
+
await depService.installPackages([`@mastra/observability${packageVersionTag}`]);
|
|
2480
|
+
}
|
|
2481
|
+
const needsEvals = components.includes(`scorers`) && await depService.checkDependencies(["@mastra/evals"]) !== `ok`;
|
|
2482
|
+
if (needsEvals) {
|
|
2483
|
+
await depService.installPackages([`@mastra/evals${packageVersionTag}`]);
|
|
2243
2484
|
}
|
|
2244
2485
|
}
|
|
2245
2486
|
const key = await getAPIKey(llmProvider || "openai");
|
|
2246
|
-
const aiSdkPackage = getAISDKPackage(llmProvider);
|
|
2247
|
-
const aiSdkPackageVersion = getAISDKPackageVersion(llmProvider);
|
|
2248
|
-
const depsService = new DepsService();
|
|
2249
|
-
const pm = depsService.packageManager;
|
|
2250
|
-
const installCommand = getPackageManagerInstallCommand(pm);
|
|
2251
|
-
await exec3(`${pm} ${installCommand} ${aiSdkPackage}@${aiSdkPackageVersion}`);
|
|
2252
2487
|
if (configureEditorWithDocsMCP) {
|
|
2253
2488
|
await installMastraDocsMCPServer({
|
|
2254
2489
|
editor: configureEditorWithDocsMCP,
|
|
2255
|
-
directory: process.cwd()
|
|
2490
|
+
directory: process.cwd(),
|
|
2491
|
+
versionTag
|
|
2256
2492
|
});
|
|
2257
2493
|
}
|
|
2258
2494
|
s.stop();
|
|
2495
|
+
if (initGit) {
|
|
2496
|
+
const s2 = Y();
|
|
2497
|
+
try {
|
|
2498
|
+
s2.start("Initializing git repository");
|
|
2499
|
+
await gitInit({ cwd: process.cwd() });
|
|
2500
|
+
s2.stop("Git repository initialized");
|
|
2501
|
+
} catch {
|
|
2502
|
+
s2.stop();
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2259
2505
|
if (!llmApiKey) {
|
|
2260
2506
|
Me(`
|
|
2261
2507
|
${color2.green("Mastra initialized successfully!")}
|
|
@@ -2275,10 +2521,10 @@ var init = async ({
|
|
|
2275
2521
|
return { success: false };
|
|
2276
2522
|
}
|
|
2277
2523
|
};
|
|
2278
|
-
var
|
|
2524
|
+
var exec3 = util.promisify(child_process.exec);
|
|
2279
2525
|
var execWithTimeout = async (command, timeoutMs) => {
|
|
2280
2526
|
try {
|
|
2281
|
-
const promise =
|
|
2527
|
+
const promise = exec3(command, { killSignal: "SIGTERM" });
|
|
2282
2528
|
if (!timeoutMs) {
|
|
2283
2529
|
return await promise;
|
|
2284
2530
|
}
|
|
@@ -2301,10 +2547,36 @@ var execWithTimeout = async (command, timeoutMs) => {
|
|
|
2301
2547
|
throw error;
|
|
2302
2548
|
}
|
|
2303
2549
|
};
|
|
2550
|
+
async function getInitCommand(pm) {
|
|
2551
|
+
switch (pm) {
|
|
2552
|
+
case "npm":
|
|
2553
|
+
return "npm init -y";
|
|
2554
|
+
case "pnpm":
|
|
2555
|
+
return "pnpm init";
|
|
2556
|
+
case "yarn":
|
|
2557
|
+
return "yarn init -y";
|
|
2558
|
+
case "bun":
|
|
2559
|
+
return "bun init -y";
|
|
2560
|
+
default:
|
|
2561
|
+
return "npm init -y";
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
async function initializePackageJson(pm) {
|
|
2565
|
+
const initCommand = await getInitCommand(pm);
|
|
2566
|
+
await exec3(initCommand);
|
|
2567
|
+
const packageJsonPath = path3.join(process.cwd(), "package.json");
|
|
2568
|
+
const packageJson = JSON.parse(await fs4.readFile(packageJsonPath, "utf-8"));
|
|
2569
|
+
packageJson.type = "module";
|
|
2570
|
+
packageJson.engines = {
|
|
2571
|
+
...packageJson.engines,
|
|
2572
|
+
node: ">=22.13.0"
|
|
2573
|
+
};
|
|
2574
|
+
await fs4.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
2575
|
+
}
|
|
2304
2576
|
async function installMastraDependency(pm, dependency, versionTag, isDev, timeout) {
|
|
2305
|
-
let installCommand =
|
|
2577
|
+
let installCommand = getPackageManagerAddCommand(pm);
|
|
2306
2578
|
if (isDev) {
|
|
2307
|
-
installCommand = `${installCommand}
|
|
2579
|
+
installCommand = `${installCommand} -D`;
|
|
2308
2580
|
}
|
|
2309
2581
|
try {
|
|
2310
2582
|
await execWithTimeout(`${pm} ${installCommand} ${dependency}${versionTag}`, timeout);
|
|
@@ -2326,23 +2598,42 @@ async function installMastraDependency(pm, dependency, versionTag, isDev, timeou
|
|
|
2326
2598
|
var createMastraProject = async ({
|
|
2327
2599
|
projectName: name,
|
|
2328
2600
|
createVersionTag,
|
|
2329
|
-
timeout
|
|
2601
|
+
timeout,
|
|
2602
|
+
llmProvider,
|
|
2603
|
+
llmApiKey,
|
|
2604
|
+
needsInteractive
|
|
2330
2605
|
}) => {
|
|
2331
2606
|
Ie(color2.inverse(" Mastra Create "));
|
|
2332
2607
|
const projectName = name ?? await he({
|
|
2333
2608
|
message: "What do you want to name your project?",
|
|
2334
2609
|
placeholder: "my-mastra-app",
|
|
2335
|
-
defaultValue: "my-mastra-app"
|
|
2610
|
+
defaultValue: "my-mastra-app",
|
|
2611
|
+
validate: (value) => {
|
|
2612
|
+
if (value.length === 0) return "Project name cannot be empty";
|
|
2613
|
+
if (fs3__default__default.existsSync(value)) {
|
|
2614
|
+
return `A directory named "${value}" already exists. Please choose a different name.`;
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2336
2617
|
});
|
|
2337
2618
|
if (pD(projectName)) {
|
|
2338
2619
|
xe("Operation cancelled");
|
|
2339
2620
|
process.exit(0);
|
|
2340
2621
|
}
|
|
2622
|
+
let result = void 0;
|
|
2623
|
+
if (needsInteractive) {
|
|
2624
|
+
result = await interactivePrompt({
|
|
2625
|
+
options: { showBanner: false },
|
|
2626
|
+
skip: { llmProvider: llmProvider !== void 0, llmApiKey: llmApiKey !== void 0 }
|
|
2627
|
+
});
|
|
2628
|
+
}
|
|
2341
2629
|
const s2 = Y();
|
|
2630
|
+
const originalCwd = process.cwd();
|
|
2631
|
+
let projectPath = null;
|
|
2342
2632
|
try {
|
|
2343
2633
|
s2.start("Creating project");
|
|
2344
2634
|
try {
|
|
2345
|
-
await
|
|
2635
|
+
await fs4.mkdir(projectName);
|
|
2636
|
+
projectPath = path3.resolve(originalCwd, projectName);
|
|
2346
2637
|
} catch (error) {
|
|
2347
2638
|
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
2348
2639
|
s2.stop(`A directory named "${projectName}" already exists. Please choose a different name.`);
|
|
@@ -2354,12 +2645,10 @@ var createMastraProject = async ({
|
|
|
2354
2645
|
}
|
|
2355
2646
|
process.chdir(projectName);
|
|
2356
2647
|
const pm = getPackageManager();
|
|
2357
|
-
const installCommand =
|
|
2648
|
+
const installCommand = getPackageManagerAddCommand(pm);
|
|
2358
2649
|
s2.message("Initializing project structure");
|
|
2359
2650
|
try {
|
|
2360
|
-
await
|
|
2361
|
-
await exec4(`npm pkg set type="module"`);
|
|
2362
|
-
await exec4(`npm pkg set engines.node=">=20.9.0"`);
|
|
2651
|
+
await initializePackageJson(pm);
|
|
2363
2652
|
const depsService = new DepsService();
|
|
2364
2653
|
await depsService.addScriptsToPackageJson({
|
|
2365
2654
|
dev: "mastra dev",
|
|
@@ -2374,9 +2663,9 @@ var createMastraProject = async ({
|
|
|
2374
2663
|
s2.stop("Project structure created");
|
|
2375
2664
|
s2.start(`Installing ${pm} dependencies`);
|
|
2376
2665
|
try {
|
|
2377
|
-
await
|
|
2378
|
-
await
|
|
2379
|
-
await
|
|
2666
|
+
await exec3(`${pm} ${installCommand} zod@^4`);
|
|
2667
|
+
await exec3(`${pm} ${installCommand} -D typescript @types/node`);
|
|
2668
|
+
await exec3(`echo '{
|
|
2380
2669
|
"compilerOptions": {
|
|
2381
2670
|
"target": "ES2022",
|
|
2382
2671
|
"module": "ES2022",
|
|
@@ -2398,15 +2687,15 @@ var createMastraProject = async ({
|
|
|
2398
2687
|
);
|
|
2399
2688
|
}
|
|
2400
2689
|
s2.stop(`${pm} dependencies installed`);
|
|
2401
|
-
s2.start("Installing
|
|
2690
|
+
s2.start("Installing Mastra CLI");
|
|
2402
2691
|
const versionTag = createVersionTag ? `@${createVersionTag}` : "@latest";
|
|
2403
2692
|
try {
|
|
2404
2693
|
await installMastraDependency(pm, "mastra", versionTag, true, timeout);
|
|
2405
2694
|
} catch (error) {
|
|
2406
2695
|
throw new Error(`Failed to install Mastra CLI: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2407
2696
|
}
|
|
2408
|
-
s2.stop("
|
|
2409
|
-
s2.start("Installing dependencies");
|
|
2697
|
+
s2.stop("Mastra CLI installed");
|
|
2698
|
+
s2.start("Installing Mastra dependencies");
|
|
2410
2699
|
try {
|
|
2411
2700
|
await installMastraDependency(pm, "@mastra/core", versionTag, false, timeout);
|
|
2412
2701
|
await installMastraDependency(pm, "@mastra/libsql", versionTag, false, timeout);
|
|
@@ -2419,58 +2708,80 @@ var createMastraProject = async ({
|
|
|
2419
2708
|
s2.stop("Mastra dependencies installed");
|
|
2420
2709
|
s2.start("Adding .gitignore");
|
|
2421
2710
|
try {
|
|
2422
|
-
await
|
|
2423
|
-
await
|
|
2424
|
-
await
|
|
2425
|
-
await
|
|
2426
|
-
await
|
|
2427
|
-
await
|
|
2428
|
-
await
|
|
2429
|
-
await
|
|
2711
|
+
await exec3(`echo output.txt >> .gitignore`);
|
|
2712
|
+
await exec3(`echo node_modules >> .gitignore`);
|
|
2713
|
+
await exec3(`echo dist >> .gitignore`);
|
|
2714
|
+
await exec3(`echo .mastra >> .gitignore`);
|
|
2715
|
+
await exec3(`echo .env.development >> .gitignore`);
|
|
2716
|
+
await exec3(`echo .env >> .gitignore`);
|
|
2717
|
+
await exec3(`echo *.db >> .gitignore`);
|
|
2718
|
+
await exec3(`echo *.db-* >> .gitignore`);
|
|
2430
2719
|
} catch (error) {
|
|
2431
2720
|
throw new Error(`Failed to create .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2432
2721
|
}
|
|
2433
2722
|
s2.stop(".gitignore added");
|
|
2434
2723
|
Se("Project created successfully");
|
|
2435
|
-
console.
|
|
2436
|
-
return { projectName };
|
|
2724
|
+
console.info("");
|
|
2725
|
+
return { projectName, result };
|
|
2437
2726
|
} catch (error) {
|
|
2438
2727
|
s2.stop();
|
|
2439
2728
|
const errorMessage = error instanceof Error ? error.message : "An unexpected error occurred";
|
|
2440
2729
|
xe(`Project creation failed: ${errorMessage}`);
|
|
2730
|
+
if (projectPath && fs3__default__default.existsSync(projectPath)) {
|
|
2731
|
+
try {
|
|
2732
|
+
process.chdir(originalCwd);
|
|
2733
|
+
await fs4.rm(projectPath, { recursive: true, force: true });
|
|
2734
|
+
} catch (cleanupError) {
|
|
2735
|
+
console.error(
|
|
2736
|
+
`Warning: Failed to clean up project directory: ${cleanupError instanceof Error ? cleanupError.message : "Unknown error"}`
|
|
2737
|
+
);
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2441
2740
|
process.exit(1);
|
|
2442
2741
|
}
|
|
2443
2742
|
};
|
|
2444
|
-
var
|
|
2445
|
-
|
|
2446
|
-
|
|
2743
|
+
var version$1 = package_default.version;
|
|
2744
|
+
var create = async (args) => {
|
|
2745
|
+
if (args.template !== void 0) {
|
|
2746
|
+
await createFromTemplate({
|
|
2747
|
+
projectName: args.projectName,
|
|
2748
|
+
template: args.template,
|
|
2749
|
+
timeout: args.timeout,
|
|
2750
|
+
injectedAnalytics: args.analytics,
|
|
2751
|
+
llmProvider: args.llmProvider
|
|
2752
|
+
});
|
|
2447
2753
|
return;
|
|
2448
2754
|
}
|
|
2449
|
-
const
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2755
|
+
const needsInteractive = args.components === void 0 || args.llmProvider === void 0 || args.addExample === void 0;
|
|
2756
|
+
const { projectName, result } = await createMastraProject({
|
|
2757
|
+
projectName: args?.projectName,
|
|
2758
|
+
createVersionTag: args?.createVersionTag,
|
|
2759
|
+
timeout: args?.timeout,
|
|
2760
|
+
llmProvider: args?.llmProvider,
|
|
2761
|
+
llmApiKey: args?.llmApiKey,
|
|
2762
|
+
needsInteractive
|
|
2453
2763
|
});
|
|
2454
|
-
const directory =
|
|
2455
|
-
if (
|
|
2456
|
-
const result = await interactivePrompt();
|
|
2764
|
+
const directory = args.directory || "src/";
|
|
2765
|
+
if (needsInteractive && result) {
|
|
2457
2766
|
await init({
|
|
2458
2767
|
...result,
|
|
2459
2768
|
llmApiKey: result?.llmApiKey,
|
|
2460
|
-
components: ["agents", "tools", "workflows"],
|
|
2461
|
-
addExample: true
|
|
2769
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2770
|
+
addExample: true,
|
|
2771
|
+
versionTag: args.createVersionTag
|
|
2462
2772
|
});
|
|
2463
2773
|
postCreate({ projectName });
|
|
2464
2774
|
return;
|
|
2465
2775
|
}
|
|
2466
|
-
const { components = [], llmProvider = "openai", addExample = false, llmApiKey } =
|
|
2776
|
+
const { components = [], llmProvider = "openai", addExample = false, llmApiKey } = args;
|
|
2467
2777
|
await init({
|
|
2468
2778
|
directory,
|
|
2469
2779
|
components,
|
|
2470
2780
|
llmProvider,
|
|
2471
2781
|
addExample,
|
|
2472
2782
|
llmApiKey,
|
|
2473
|
-
configureEditorWithDocsMCP:
|
|
2783
|
+
configureEditorWithDocsMCP: args.mcpServer,
|
|
2784
|
+
versionTag: args.createVersionTag
|
|
2474
2785
|
});
|
|
2475
2786
|
postCreate({ projectName });
|
|
2476
2787
|
};
|
|
@@ -2561,9 +2872,9 @@ async function createFromGitHubUrl(url) {
|
|
|
2561
2872
|
workflows: []
|
|
2562
2873
|
};
|
|
2563
2874
|
}
|
|
2564
|
-
async function createFromTemplate(
|
|
2875
|
+
async function createFromTemplate(args) {
|
|
2565
2876
|
let selectedTemplate;
|
|
2566
|
-
if (
|
|
2877
|
+
if (args.template === true) {
|
|
2567
2878
|
const templates = await loadTemplates();
|
|
2568
2879
|
const selected = await selectTemplate(templates);
|
|
2569
2880
|
if (!selected) {
|
|
@@ -2571,26 +2882,26 @@ async function createFromTemplate(args2) {
|
|
|
2571
2882
|
return;
|
|
2572
2883
|
}
|
|
2573
2884
|
selectedTemplate = selected;
|
|
2574
|
-
} else if (
|
|
2575
|
-
if (isGitHubUrl(
|
|
2576
|
-
const
|
|
2577
|
-
|
|
2578
|
-
const validation = await validateGitHubProject(
|
|
2885
|
+
} else if (args.template && typeof args.template === "string") {
|
|
2886
|
+
if (isGitHubUrl(args.template)) {
|
|
2887
|
+
const spinner4 = Y();
|
|
2888
|
+
spinner4.start("Validating GitHub repository...");
|
|
2889
|
+
const validation = await validateGitHubProject(args.template);
|
|
2579
2890
|
if (!validation.isValid) {
|
|
2580
|
-
|
|
2891
|
+
spinner4.stop("Validation failed");
|
|
2581
2892
|
M.error("This does not appear to be a valid Mastra project:");
|
|
2582
2893
|
validation.errors.forEach((error) => M.error(` - ${error}`));
|
|
2583
2894
|
throw new Error("Invalid Mastra project");
|
|
2584
2895
|
}
|
|
2585
|
-
|
|
2586
|
-
selectedTemplate = await createFromGitHubUrl(
|
|
2896
|
+
spinner4.stop("Valid Mastra project \u2713");
|
|
2897
|
+
selectedTemplate = await createFromGitHubUrl(args.template);
|
|
2587
2898
|
} else {
|
|
2588
2899
|
const templates = await loadTemplates();
|
|
2589
|
-
const found = findTemplateByName(templates,
|
|
2900
|
+
const found = findTemplateByName(templates, args.template);
|
|
2590
2901
|
if (!found) {
|
|
2591
|
-
M.error(`Template "${
|
|
2902
|
+
M.error(`Template "${args.template}" not found. Available templates:`);
|
|
2592
2903
|
templates.forEach((t) => M.info(` - ${t.title} (use: ${t.slug.replace("template-", "")})`));
|
|
2593
|
-
throw new Error(`Template "${
|
|
2904
|
+
throw new Error(`Template "${args.template}" not found`);
|
|
2594
2905
|
}
|
|
2595
2906
|
selectedTemplate = found;
|
|
2596
2907
|
}
|
|
@@ -2598,7 +2909,7 @@ async function createFromTemplate(args2) {
|
|
|
2598
2909
|
if (!selectedTemplate) {
|
|
2599
2910
|
throw new Error("No template selected");
|
|
2600
2911
|
}
|
|
2601
|
-
let projectName =
|
|
2912
|
+
let projectName = args.projectName;
|
|
2602
2913
|
if (!projectName) {
|
|
2603
2914
|
const defaultName = getDefaultProjectName(selectedTemplate);
|
|
2604
2915
|
const response = await he({
|
|
@@ -2612,22 +2923,80 @@ async function createFromTemplate(args2) {
|
|
|
2612
2923
|
}
|
|
2613
2924
|
projectName = response;
|
|
2614
2925
|
}
|
|
2926
|
+
let llmProvider = args.llmProvider;
|
|
2927
|
+
if (!llmProvider) {
|
|
2928
|
+
const providerResponse = await ve({
|
|
2929
|
+
message: "Select a default provider:",
|
|
2930
|
+
options: LLM_PROVIDERS
|
|
2931
|
+
});
|
|
2932
|
+
if (pD(providerResponse)) {
|
|
2933
|
+
M.info("Project creation cancelled.");
|
|
2934
|
+
return;
|
|
2935
|
+
}
|
|
2936
|
+
llmProvider = providerResponse;
|
|
2937
|
+
}
|
|
2938
|
+
let initGit = false;
|
|
2939
|
+
const gitConfirmResult = await ye({
|
|
2940
|
+
message: "Initialize a new git repository?",
|
|
2941
|
+
initialValue: true
|
|
2942
|
+
});
|
|
2943
|
+
if (!pD(gitConfirmResult)) {
|
|
2944
|
+
initGit = gitConfirmResult;
|
|
2945
|
+
}
|
|
2946
|
+
let projectPath = null;
|
|
2615
2947
|
try {
|
|
2616
|
-
const analytics = getAnalytics();
|
|
2617
|
-
if (analytics)
|
|
2618
|
-
|
|
2948
|
+
const analytics = args.injectedAnalytics || getAnalytics();
|
|
2949
|
+
if (analytics) {
|
|
2950
|
+
analytics.trackEvent("cli_template_used", {
|
|
2951
|
+
template_slug: selectedTemplate.slug,
|
|
2952
|
+
template_title: selectedTemplate.title
|
|
2953
|
+
});
|
|
2954
|
+
if (llmProvider) {
|
|
2955
|
+
analytics.trackEvent("cli_model_provider_selected", {
|
|
2956
|
+
provider: llmProvider,
|
|
2957
|
+
selection_method: args.llmProvider ? "cli_args" : "interactive"
|
|
2958
|
+
});
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
const isBeta = version$1?.includes("beta") ?? false;
|
|
2962
|
+
const isMastraTemplate = selectedTemplate.githubUrl.includes("github.com/mastra-ai/");
|
|
2963
|
+
const branch = isBeta && isMastraTemplate ? "beta" : void 0;
|
|
2964
|
+
projectPath = await cloneTemplate({
|
|
2619
2965
|
template: selectedTemplate,
|
|
2620
|
-
projectName
|
|
2966
|
+
projectName,
|
|
2967
|
+
branch,
|
|
2968
|
+
llmProvider
|
|
2621
2969
|
});
|
|
2622
2970
|
await installDependencies(projectPath);
|
|
2971
|
+
if (initGit) {
|
|
2972
|
+
const s2 = Y();
|
|
2973
|
+
try {
|
|
2974
|
+
s2.start("Initializing git repository");
|
|
2975
|
+
await gitInit({ cwd: projectPath });
|
|
2976
|
+
s2.stop("Git repository initialized");
|
|
2977
|
+
} catch {
|
|
2978
|
+
s2.stop();
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2623
2981
|
Me(`
|
|
2624
2982
|
${color2.green("Mastra template installed!")}
|
|
2625
2983
|
|
|
2626
|
-
Add the necessary environment
|
|
2984
|
+
Add the necessary environment
|
|
2627
2985
|
variables in your ${color2.cyan(".env")} file
|
|
2628
2986
|
`);
|
|
2629
2987
|
postCreate({ projectName });
|
|
2630
2988
|
} catch (error) {
|
|
2989
|
+
if (projectPath) {
|
|
2990
|
+
try {
|
|
2991
|
+
if (fs3__default__default.existsSync(projectPath)) {
|
|
2992
|
+
await fs4.rm(projectPath, { recursive: true, force: true });
|
|
2993
|
+
}
|
|
2994
|
+
} catch (cleanupError) {
|
|
2995
|
+
console.error(
|
|
2996
|
+
`Warning: Failed to clean up project directory: ${cleanupError instanceof Error ? cleanupError.message : "Unknown error"}`
|
|
2997
|
+
);
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
2631
3000
|
M.error(`Failed to create project from template: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2632
3001
|
throw error;
|
|
2633
3002
|
}
|
|
@@ -2637,13 +3006,13 @@ async function getPackageVersion() {
|
|
|
2637
3006
|
const __filename = fileURLToPath(import.meta.url);
|
|
2638
3007
|
const __dirname = dirname(__filename);
|
|
2639
3008
|
const pkgJsonPath = path3.join(__dirname, "..", "package.json");
|
|
2640
|
-
const content = await fsExtra.readJSON(pkgJsonPath);
|
|
3009
|
+
const content = await fsExtra$1.readJSON(pkgJsonPath);
|
|
2641
3010
|
return content.version;
|
|
2642
3011
|
}
|
|
2643
3012
|
async function getCreateVersionTag() {
|
|
2644
3013
|
try {
|
|
2645
3014
|
const pkgPath = fileURLToPath(import.meta.resolve("create-mastra/package.json"));
|
|
2646
|
-
const json = await fsExtra.readJSON(pkgPath);
|
|
3015
|
+
const json = await fsExtra$1.readJSON(pkgPath);
|
|
2647
3016
|
const { stdout } = await execa("npm", ["dist-tag", "create-mastra"]);
|
|
2648
3017
|
const tagLine = stdout.split("\n").find((distLine) => distLine.endsWith(`: ${json.version}`));
|
|
2649
3018
|
const tag = tagLine ? tagLine.split(":")[0].trim() : "latest";
|
|
@@ -2667,14 +3036,14 @@ program.version(`${version}`, "-v, --version").description(`create-mastra ${vers
|
|
|
2667
3036
|
analytics.trackCommand({
|
|
2668
3037
|
command: "version"
|
|
2669
3038
|
});
|
|
2670
|
-
console.
|
|
3039
|
+
console.info(`create-mastra ${version}`);
|
|
2671
3040
|
} catch {
|
|
2672
3041
|
}
|
|
2673
3042
|
});
|
|
2674
3043
|
program.name("create-mastra").description("Create a new Mastra project").argument("[project-name]", "Directory name of the project").option(
|
|
2675
3044
|
"-p, --project-name <string>",
|
|
2676
3045
|
"Project name that will be used in package.json and as the project directory name."
|
|
2677
|
-
).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(
|
|
3046
|
+
).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, antigravity)").option(
|
|
2678
3047
|
"--template [template-name]",
|
|
2679
3048
|
"Create project from a template (use template name, public GitHub URL, or leave blank to select from list)"
|
|
2680
3049
|
).action(async (projectNameArg, args) => {
|
|
@@ -2682,14 +3051,15 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2682
3051
|
const timeout = args?.timeout ? args?.timeout === true ? 6e4 : parseInt(args?.timeout, 10) : void 0;
|
|
2683
3052
|
if (args.default) {
|
|
2684
3053
|
await create({
|
|
2685
|
-
components: ["agents", "tools", "workflows"],
|
|
3054
|
+
components: ["agents", "tools", "workflows", "scorers"],
|
|
2686
3055
|
llmProvider: "openai",
|
|
2687
3056
|
addExample: true,
|
|
2688
3057
|
createVersionTag,
|
|
2689
3058
|
timeout,
|
|
2690
3059
|
mcpServer: args.mcp,
|
|
2691
3060
|
directory: "src/",
|
|
2692
|
-
template: args.template
|
|
3061
|
+
template: args.template,
|
|
3062
|
+
analytics
|
|
2693
3063
|
});
|
|
2694
3064
|
return;
|
|
2695
3065
|
}
|
|
@@ -2697,13 +3067,14 @@ program.name("create-mastra").description("Create a new Mastra project").argumen
|
|
|
2697
3067
|
components: args.components ? args.components.split(",") : [],
|
|
2698
3068
|
llmProvider: args.llm,
|
|
2699
3069
|
addExample: args.example,
|
|
2700
|
-
llmApiKey: args
|
|
3070
|
+
llmApiKey: args.llmApiKey,
|
|
2701
3071
|
createVersionTag,
|
|
2702
3072
|
timeout,
|
|
2703
3073
|
projectName,
|
|
2704
3074
|
directory: args.dir,
|
|
2705
3075
|
mcpServer: args.mcp,
|
|
2706
|
-
template: args.template
|
|
3076
|
+
template: args.template,
|
|
3077
|
+
analytics
|
|
2707
3078
|
});
|
|
2708
3079
|
});
|
|
2709
3080
|
program.parse(process.argv);
|