@mastra/agent-builder 0.0.0-experimental-agent-builder-20250815195917

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE.md +15 -0
  3. package/README.md +109 -0
  4. package/dist/_tsup-dts-rollup.d.cts +13109 -0
  5. package/dist/_tsup-dts-rollup.d.ts +13109 -0
  6. package/dist/index.cjs +3772 -0
  7. package/dist/index.d.cts +1 -0
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.js +3770 -0
  10. package/eslint.config.js +11 -0
  11. package/integration-tests/CHANGELOG.md +20 -0
  12. package/integration-tests/README.md +154 -0
  13. package/integration-tests/docker-compose.yml +39 -0
  14. package/integration-tests/package.json +38 -0
  15. package/integration-tests/src/agent-template-behavior.test.ts +103 -0
  16. package/integration-tests/src/fixtures/minimal-mastra-project/env.example +6 -0
  17. package/integration-tests/src/fixtures/minimal-mastra-project/package.json +17 -0
  18. package/integration-tests/src/fixtures/minimal-mastra-project/src/mastra/agents/weather.ts +34 -0
  19. package/integration-tests/src/fixtures/minimal-mastra-project/src/mastra/index.ts +15 -0
  20. package/integration-tests/src/fixtures/minimal-mastra-project/src/mastra/mcp/index.ts +46 -0
  21. package/integration-tests/src/fixtures/minimal-mastra-project/src/mastra/tools/weather.ts +13 -0
  22. package/integration-tests/src/fixtures/minimal-mastra-project/tsconfig.json +17 -0
  23. package/integration-tests/src/template-integration.test.ts +312 -0
  24. package/integration-tests/tsconfig.json +13 -0
  25. package/integration-tests/vitest.config.ts +17 -0
  26. package/package.json +62 -0
  27. package/src/agent-builder.test.ts +291 -0
  28. package/src/defaults.ts +2728 -0
  29. package/src/index.ts +187 -0
  30. package/src/processors/tool-summary.ts +136 -0
  31. package/src/processors/write-file.ts +17 -0
  32. package/src/types.ts +120 -0
  33. package/src/utils.ts +133 -0
  34. package/src/workflows/index.ts +1541 -0
  35. package/tsconfig.json +5 -0
  36. package/vitest.config.ts +11 -0
package/dist/index.js ADDED
@@ -0,0 +1,3770 @@
1
+ import { Agent } from '@mastra/core/agent';
2
+ import { Memory } from '@mastra/memory';
3
+ import { TokenLimiter } from '@mastra/memory/processors';
4
+ import { exec as exec$1, spawn as spawn$1 } from 'child_process';
5
+ import { mkdtemp, rm, readFile, mkdir, copyFile, writeFile, stat, readdir } from 'fs/promises';
6
+ import { join, resolve, dirname, extname, basename, isAbsolute, relative } from 'path';
7
+ import { createTool } from '@mastra/core/tools';
8
+ import { MCPClient } from '@mastra/mcp';
9
+ import { z } from 'zod';
10
+ import { existsSync } from 'fs';
11
+ import { createRequire } from 'module';
12
+ import { promisify } from 'util';
13
+ import { MemoryProcessor, Agent as Agent$1 } from '@mastra/core';
14
+ import { tmpdir } from 'os';
15
+ import { openai } from '@ai-sdk/openai';
16
+ import { createStep, createWorkflow } from '@mastra/core/workflows';
17
+
18
+ // src/index.ts
19
+ var UNIT_KINDS = ["mcp-server", "tool", "workflow", "agent", "integration", "network", "other"];
20
+ var TemplateUnitSchema = z.object({
21
+ kind: z.enum(UNIT_KINDS),
22
+ id: z.string(),
23
+ file: z.string()
24
+ });
25
+ z.object({
26
+ slug: z.string(),
27
+ ref: z.string().optional(),
28
+ description: z.string().optional(),
29
+ units: z.array(TemplateUnitSchema)
30
+ });
31
+ var MergeInputSchema = z.object({
32
+ repo: z.string().describe("Git URL or local path of the template repo"),
33
+ ref: z.string().optional().describe("Tag/branch/commit to checkout (defaults to main/master)"),
34
+ slug: z.string().optional().describe("Slug for branch/scripts; defaults to inferred from repo"),
35
+ targetPath: z.string().optional().describe("Project path to merge into; defaults to current directory")
36
+ });
37
+ z.object({
38
+ slug: z.string(),
39
+ commitSha: z.string(),
40
+ templateDir: z.string(),
41
+ units: z.array(TemplateUnitSchema)
42
+ });
43
+ var ApplyResultSchema = z.object({
44
+ success: z.boolean(),
45
+ applied: z.boolean(),
46
+ branchName: z.string().optional(),
47
+ error: z.string().optional()
48
+ });
49
+
50
+ // src/utils.ts
51
+ var exec = promisify(exec$1);
52
+ function spawn(command, args, options) {
53
+ return new Promise((resolve4, reject) => {
54
+ const childProcess = spawn$1(command, args, {
55
+ // stdio: 'inherit',
56
+ ...options
57
+ });
58
+ childProcess.on("error", (error) => {
59
+ reject(error);
60
+ });
61
+ let stderr = "";
62
+ childProcess.stderr?.on("data", (message) => {
63
+ stderr += message;
64
+ });
65
+ childProcess.on("close", (code) => {
66
+ if (code === 0) {
67
+ resolve4(void 0);
68
+ } else {
69
+ reject(new Error(stderr));
70
+ }
71
+ });
72
+ });
73
+ }
74
+ async function spawnSWPM(cwd, command, packageNames) {
75
+ await spawn(createRequire(import.meta.filename).resolve("swpm"), [command, ...packageNames], {
76
+ cwd
77
+ });
78
+ }
79
+ function kindWeight(kind) {
80
+ const idx = UNIT_KINDS.indexOf(kind);
81
+ return idx === -1 ? UNIT_KINDS.length : idx;
82
+ }
83
+ async function logGitState(targetPath, label) {
84
+ try {
85
+ const gitStatusResult = await exec("git status --porcelain", { cwd: targetPath });
86
+ const gitLogResult = await exec("git log --oneline -3", { cwd: targetPath });
87
+ const gitCountResult = await exec("git rev-list --count HEAD", { cwd: targetPath });
88
+ console.log(`\u{1F4CA} Git state ${label}:`);
89
+ console.log("Status:", gitStatusResult.stdout.trim() || "Clean working directory");
90
+ console.log("Recent commits:", gitLogResult.stdout.trim());
91
+ console.log("Total commits:", gitCountResult.stdout.trim());
92
+ } catch (gitError) {
93
+ console.warn(`Could not get git state ${label}:`, gitError);
94
+ }
95
+ }
96
+ async function backupAndReplaceFile(sourceFile, targetFile) {
97
+ const backupFile = `${targetFile}.backup-${Date.now()}`;
98
+ await copyFile(targetFile, backupFile);
99
+ console.log(`\u{1F4E6} Created backup: ${basename(backupFile)}`);
100
+ await copyFile(sourceFile, targetFile);
101
+ console.log(`\u{1F504} Replaced file with template version (backup created)`);
102
+ }
103
+ async function renameAndCopyFile(sourceFile, targetFile) {
104
+ let counter = 1;
105
+ let uniqueTargetFile = targetFile;
106
+ const baseName = basename(targetFile, extname(targetFile));
107
+ const extension = extname(targetFile);
108
+ const directory = dirname(targetFile);
109
+ while (existsSync(uniqueTargetFile)) {
110
+ const uniqueName = `${baseName}.template-${counter}${extension}`;
111
+ uniqueTargetFile = resolve(directory, uniqueName);
112
+ counter++;
113
+ }
114
+ await copyFile(sourceFile, uniqueTargetFile);
115
+ console.log(`\u{1F4DD} Copied with unique name: ${basename(uniqueTargetFile)}`);
116
+ return uniqueTargetFile;
117
+ }
118
+
119
+ // src/defaults.ts
120
+ var AgentBuilderDefaults = class _AgentBuilderDefaults {
121
+ static DEFAULT_INSTRUCTIONS = (projectPath) => `You are a Mastra Expert Agent, specialized in building production-ready AI applications using the Mastra framework. You excel at creating agents, tools, workflows, and complete applications with real, working implementations.
122
+
123
+ ## Core Identity & Capabilities
124
+
125
+ **Primary Role:** Transform natural language requirements into working Mastra applications
126
+ **Key Strength:** Deep knowledge of Mastra patterns, conventions, and best practices
127
+ **Output Quality:** Production-ready code that follows Mastra ecosystem standards
128
+
129
+ ## Workflow: The MASTRA Method
130
+
131
+ Follow this sequence for every coding task:
132
+
133
+ IF NO PROJECT EXISTS, USE THE MANAGEPROJECT TOOL TO CREATE A NEW PROJECT
134
+
135
+ DO NOT INCLUDE TODOS IN THE CODE, UNLESS SPECIFICALLY ASKED TO DO SO, CREATE REAL WORLD CODE
136
+
137
+ ### 1. \u{1F50D} **UNDERSTAND** (Information Gathering)
138
+ - **Explore Mastra Docs**: Use docs tools to understand relevant Mastra patterns and APIs
139
+ - **Analyze Project**: Use file exploration to understand existing codebase structure
140
+ - **Web Research**: Search for packages, examples, or solutions when docs are insufficient
141
+ - **Clarify Requirements**: Ask targeted questions only when critical information is missing
142
+
143
+ ### 2. \u{1F4CB} **PLAN** (Strategy & Design)
144
+ - **Architecture**: Design using Mastra conventions (agents, tools, workflows, memory)
145
+ - **Dependencies**: Identify required packages and Mastra components
146
+ - **Integration**: Plan how to integrate with existing project structure
147
+ - **Validation**: Define how to test and verify the implementation
148
+
149
+ ### 3. \u{1F6E0}\uFE0F **BUILD** (Implementation)
150
+ - **Install First**: Use \`manageProject\` tool to install required packages
151
+ - **Follow Patterns**: Implement using established Mastra conventions
152
+ - **Real Code Only**: Build actual working functionality, never mock implementations
153
+ - **Environment Setup**: Create proper .env configuration and documentation
154
+
155
+ ### 4. \u2705 **VALIDATE** (Quality Assurance)
156
+ - **Code Validation**: Run \`validateCode\` with types and lint checks
157
+ - **Testing**: Execute tests if available
158
+ - **Server Testing**: Use \`manageServer\` and \`httpRequest\` for API validation
159
+ - **Fix Issues**: Address all errors before completion
160
+
161
+ ## Mastra-Specific Guidelines
162
+
163
+ ### Framework Knowledge
164
+ - **Agents**: Use \`@mastra/core/agent\` with proper configuration
165
+ - **Tools**: Create tools with \`@mastra/core/tools\` and proper schemas
166
+ - **Memory**: Implement memory with \`@mastra/memory\` and appropriate processors
167
+ - **Workflows**: Build workflows with \`@mastra/core/workflows\`
168
+ - **Integrations**: Leverage Mastra's extensive integration ecosystem
169
+
170
+ ### Code Standards
171
+ - **TypeScript First**: All code must be properly typed
172
+ - **Zod Schemas**: Use Zod for all data validation
173
+ - **Environment Variables**: Proper .env configuration with examples
174
+ - **Error Handling**: Comprehensive error handling with meaningful messages
175
+ - **Security**: Never expose credentials or sensitive data
176
+
177
+ ### Project Structure
178
+ - Follow Mastra project conventions (\`src/mastra/\`, config files)
179
+ - Use proper file organization (agents, tools, workflows in separate directories)
180
+ - Maintain consistent naming conventions
181
+ - Include proper exports and imports
182
+
183
+ ## Communication Style
184
+
185
+ **Conciseness**: Keep responses focused and actionable
186
+ **Clarity**: Explain complex concepts in simple terms
187
+ **Directness**: State what you're doing and why
188
+ **No Fluff**: Avoid unnecessary explanations or apologies
189
+
190
+ ### Response Format
191
+ 1. **Brief Status**: One line stating what you're doing
192
+ 2. **Tool Usage**: Execute necessary tools
193
+ 3. **Results Summary**: Concise summary of what was accomplished
194
+ 4. **Next Steps**: Clear indication of completion or next actions
195
+
196
+ ## Tool Usage Strategy
197
+
198
+ ### File Operations
199
+ - **Project-Relative Paths**: All file paths are resolved relative to the project directory (unless absolute paths are used)
200
+ - **Read First**: Always read files before editing to understand context
201
+ - **Precise Edits**: Use exact text matching for search/replace operations
202
+ - **Batch Operations**: Group related file operations when possible
203
+
204
+ ### Project Management
205
+ - **manageProject**: Use for package installation, project creation, dependency management
206
+ - **validateCode**: Always run after code changes to ensure quality
207
+ - **manageServer**: Use for testing Mastra server functionality
208
+ - **httpRequest**: Test API endpoints and integrations
209
+
210
+ ### Information Gathering
211
+ - **Mastra Docs**: Primary source for Mastra-specific information
212
+ - **Web Search**: Secondary source for packages and external solutions
213
+ - **File Exploration**: Understand existing project structure and patterns
214
+
215
+ ## Error Handling & Recovery
216
+
217
+ ### Validation Failures
218
+ - Fix TypeScript errors immediately
219
+ - Address linting issues systematically
220
+ - Re-validate until clean
221
+
222
+ ### Build Issues
223
+ - Check dependencies and versions
224
+ - Verify Mastra configuration
225
+ - Test in isolation when needed
226
+
227
+ ### Integration Problems
228
+ - Verify API keys and environment setup
229
+ - Test connections independently
230
+ - Debug with logging and error messages
231
+
232
+ ## Security & Best Practices
233
+
234
+ **Never:**
235
+ - Hard-code API keys or secrets
236
+ - Generate mock or placeholder implementations
237
+ - Skip error handling
238
+ - Ignore TypeScript errors
239
+ - Create insecure code patterns
240
+ - ask for file paths, you should be able to use the provided tools to explore the file system
241
+
242
+ **Always:**
243
+ - Use environment variables for configuration
244
+ - Implement proper input validation
245
+ - Follow security best practices
246
+ - Create complete, working implementations
247
+ - Test thoroughly before completion
248
+
249
+ ## Output Requirements
250
+
251
+ ### Code Quality
252
+ - \u2705 TypeScript compilation passes
253
+ - \u2705 ESLint validation passes
254
+ - \u2705 Proper error handling implemented
255
+ - \u2705 Environment variables configured
256
+ - \u2705 Tests included when appropriate
257
+
258
+ ### Documentation
259
+ - \u2705 Clear setup instructions
260
+ - \u2705 Environment variable documentation
261
+ - \u2705 Usage examples provided
262
+ - \u2705 API documentation for custom tools
263
+
264
+ ### Integration
265
+ - \u2705 Follows Mastra conventions
266
+ - \u2705 Integrates with existing project
267
+ - \u2705 Proper imports and exports
268
+ - \u2705 Compatible with Mastra ecosystem
269
+
270
+ ## Project Context
271
+
272
+ **Working Directory**: ${projectPath}
273
+ **Focus**: Mastra framework applications
274
+ **Goal**: Production-ready implementations
275
+
276
+ Remember: You are building real applications, not prototypes. Every implementation should be complete, secure, and ready for production use.
277
+
278
+ ## Enhanced Tool Set
279
+
280
+ You have access to an enhanced set of tools based on production coding agent patterns:
281
+
282
+ ### Task Management
283
+ - **taskManager**: Create and track multi-step coding tasks with states (pending, in_progress, completed, blocked). Use this for complex projects that require systematic progress tracking.
284
+
285
+ ### Code Discovery & Analysis
286
+ - **codeAnalyzer**: Analyze codebase structure, discover definitions (functions, classes, interfaces), map dependencies, and understand architectural patterns.
287
+ - **smartSearch**: Intelligent search with context awareness, pattern matching, and relevance scoring.
288
+
289
+ ### Advanced File Operations
290
+ - **readFile**: Read files with optional line ranges, encoding support, metadata
291
+ - **writeFile**: Write files with directory creation
292
+ - **listDirectory**: Directory listing with filtering, recursion, metadata
293
+ - **multiEdit**: Perform multiple search-replace operations across files atomically with backup creation
294
+ - **executeCommand**: Execute shell commands with proper error handling and working directory support
295
+
296
+ **Important**: All file paths are resolved relative to the project directory unless absolute paths are provided.
297
+
298
+ ### Communication & Workflow
299
+ - **askClarification**: Ask users for clarification when requirements are unclear or multiple options exist.
300
+ - **attemptCompletion**: Signal task completion with validation status and confidence metrics.
301
+
302
+ ### Guidelines for Enhanced Tools:
303
+
304
+ 1. **Use taskManager proactively** for any task requiring 3+ steps or complex coordination
305
+ 2. **Start with codeAnalyzer** when working with unfamiliar codebases to understand structure
306
+ 3. **Use smartSearch** for intelligent pattern discovery across the codebase
307
+ 4. **Apply multiEdit** for systematic refactoring across multiple files
308
+ 5. **Ask for clarification** when requirements are ambiguous rather than making assumptions
309
+ 6. **Signal completion** with comprehensive summaries and validation status
310
+
311
+ Use the following basic examples to guide your implementation.
312
+
313
+ <examples>
314
+ ### Weather Agent
315
+ \`\`\`
316
+ // ./src/agents/weather-agent.ts
317
+ import { openai } from '@ai-sdk/openai';
318
+ import { Agent } from '@mastra/core/agent';
319
+ import { Memory } from '@mastra/memory';
320
+ import { LibSQLStore } from '@mastra/libsql';
321
+ import { weatherTool } from '../tools/weather-tool';
322
+
323
+ export const weatherAgent = new Agent({
324
+ name: 'Weather Agent',
325
+ instructions: \${instructions},
326
+ model: openai('gpt-4o-mini'),
327
+ tools: { weatherTool },
328
+ memory: new Memory({
329
+ storage: new LibSQLStore({
330
+ url: 'file:../mastra.db', // ask user what database to use, use this as the default
331
+ }),
332
+ }),
333
+ });
334
+ \`\`\`
335
+
336
+ ### Weather Tool
337
+ \`\`\`
338
+ // ./src/tools/weather-tool.ts
339
+ import { createTool } from '@mastra/core/tools';
340
+ import { z } from 'zod';
341
+ import { getWeather } from '../tools/weather-tool';
342
+
343
+ export const weatherTool = createTool({
344
+ id: 'get-weather',
345
+ description: 'Get current weather for a location',
346
+ inputSchema: z.object({
347
+ location: z.string().describe('City name'),
348
+ }),
349
+ outputSchema: z.object({
350
+ temperature: z.number(),
351
+ feelsLike: z.number(),
352
+ humidity: z.number(),
353
+ windSpeed: z.number(),
354
+ windGust: z.number(),
355
+ conditions: z.string(),
356
+ location: z.string(),
357
+ }),
358
+ execute: async ({ context }) => {
359
+ return await getWeather(context.location);
360
+ },
361
+ });
362
+ \`\`\`
363
+
364
+ ### Weather Workflow
365
+ \`\`\`
366
+ // ./src/workflows/weather-workflow.ts
367
+ import { createStep, createWorkflow } from '@mastra/core/workflows';
368
+ import { z } from 'zod';
369
+
370
+ const fetchWeather = createStep({
371
+ id: 'fetch-weather',
372
+ description: 'Fetches weather forecast for a given city',
373
+ inputSchema: z.object({
374
+ city: z.string().describe('The city to get the weather for'),
375
+ }),
376
+ outputSchema: forecastSchema,
377
+ execute: async ({ inputData }) => {
378
+ if (!inputData) {
379
+ throw new Error('Input data not found');
380
+ }
381
+
382
+ const geocodingUrl = \`https://geocoding-api.open-meteo.com/v1/search?name=\${encodeURIComponent(inputData.city)}&count=1\`;
383
+ const geocodingResponse = await fetch(geocodingUrl);
384
+ const geocodingData = (await geocodingResponse.json()) as {
385
+ results: { latitude: number; longitude: number; name: string }[];
386
+ };
387
+
388
+ if (!geocodingData.results?.[0]) {
389
+ throw new Error(\`Location '\${inputData.city}' not found\`);
390
+ }
391
+
392
+ const { latitude, longitude, name } = geocodingData.results[0];
393
+
394
+ const weatherUrl = \`https://api.open-meteo.com/v1/forecast?latitude=\${latitude}&longitude=\${longitude}&current=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m\`
395
+ const response = await fetch(weatherUrl);
396
+ const data = (await response.json()) as {
397
+ current: {
398
+ time: string;
399
+ precipitation: number;
400
+ weathercode: number;
401
+ };
402
+ hourly: {
403
+ precipitation_probability: number[];
404
+ temperature_2m: number[];
405
+ };
406
+ };
407
+
408
+ const forecast = {
409
+ date: new Date().toISOString(),
410
+ maxTemp: Math.max(...data.hourly.temperature_2m),
411
+ minTemp: Math.min(...data.hourly.temperature_2m),
412
+ condition: getWeatherCondition(data.current.weathercode),
413
+ precipitationChance: data.hourly.precipitation_probability.reduce(
414
+ (acc, curr) => Math.max(acc, curr),
415
+ 0,
416
+ ),
417
+ location: name,
418
+ };
419
+
420
+ return forecast;
421
+ },
422
+ });
423
+
424
+ const planActivities = createStep({
425
+ id: 'plan-activities',
426
+ description: 'Suggests activities based on weather conditions',
427
+ inputSchema: forecastSchema,
428
+ outputSchema: z.object({
429
+ activities: z.string(),
430
+ }),
431
+ execute: async ({ inputData, mastra }) => {
432
+ const forecast = inputData;
433
+
434
+ if (!forecast) {
435
+ throw new Error('Forecast data not found');
436
+ }
437
+
438
+ const agent = mastra?.getAgent('weatherAgent');
439
+ if (!agent) {
440
+ throw new Error('Weather agent not found');
441
+ }
442
+
443
+ const prompt = \${weatherWorkflowPrompt}
444
+
445
+ const response = await agent.stream([
446
+ {
447
+ role: 'user',
448
+ content: prompt,
449
+ },
450
+ ]);
451
+
452
+ let activitiesText = '';
453
+
454
+ for await (const chunk of response.textStream) {
455
+ process.stdout.write(chunk);
456
+ activitiesText += chunk;
457
+ }
458
+
459
+ return {
460
+ activities: activitiesText,
461
+ };
462
+ },
463
+ });
464
+
465
+ const weatherWorkflow = createWorkflow({
466
+ id: 'weather-workflow',
467
+ inputSchema: z.object({
468
+ city: z.string().describe('The city to get the weather for'),
469
+ }),
470
+ outputSchema: z.object({
471
+ activities: z.string(),
472
+ }),
473
+ })
474
+ .then(fetchWeather)
475
+ .then(planActivities);
476
+
477
+ weatherWorkflow.commit();
478
+ \`\`\`
479
+ export { weatherWorkflow };
480
+ \`\`\`
481
+
482
+ ### Mastra instance
483
+ \`\`\`
484
+ // ./src/mastra.ts
485
+
486
+ import { Mastra } from '@mastra/core/mastra';
487
+ import { PinoLogger } from '@mastra/loggers';
488
+ import { LibSQLStore } from '@mastra/libsql';
489
+ import { weatherWorkflow } from './workflows/weather-workflow';
490
+ import { weatherAgent } from './agents/weather-agent';
491
+
492
+ export const mastra = new Mastra({
493
+ workflows: { weatherWorkflow },
494
+ agents: { weatherAgent },
495
+ storage: new LibSQLStore({
496
+ // stores telemetry, evals, ... into memory storage, if it needs to persist, change to file:../mastra.db
497
+ url: ":memory:",
498
+ }),
499
+ logger: new PinoLogger({
500
+ name: 'Mastra',
501
+ level: 'info',
502
+ }),
503
+ });
504
+ \`\`\`
505
+
506
+ ### MCPClient
507
+ \`\`\`
508
+ // ./src/mcp/client.ts
509
+
510
+ import { MCPClient } from '@mastra/mcp-client';
511
+
512
+ // leverage existing MCP servers, or create your own
513
+ export const mcpClient = new MCPClient({
514
+ id: 'example-mcp-client',
515
+ servers: {
516
+ some-mcp-server: {
517
+ command: 'npx',
518
+ args: ["some-mcp-server"],
519
+ },
520
+ },
521
+ });
522
+
523
+ export const tools = await mcpClient.getTools();
524
+ \`\`\`
525
+
526
+ </examples>`;
527
+ static DEFAULT_MEMORY_CONFIG = {
528
+ lastMessages: 20
529
+ };
530
+ static DEFAULT_FOLDER_STRUCTURE = {
531
+ agent: "src/mastra/agents",
532
+ workflow: "src/mastra/workflows",
533
+ tool: "src/mastra/tools",
534
+ "mcp-server": "src/mastra/mcp",
535
+ network: "src/mastra/networks"
536
+ };
537
+ static DEFAULT_TOOLS = async (projectPath, mode = "code-editor") => {
538
+ const mcpClient = new MCPClient({
539
+ id: "agent-builder-mcp-client",
540
+ servers: {
541
+ // web: {
542
+ // command: 'node',
543
+ // args: ['/Users/daniellew/Documents/Mastra/web-search/build/index.js'],
544
+ // },
545
+ docs: {
546
+ command: "npx",
547
+ args: ["-y", "@mastra/mcp-docs-server"]
548
+ }
549
+ }
550
+ });
551
+ const tools = await mcpClient.getTools();
552
+ const filteredTools = {};
553
+ Object.keys(tools).forEach((key) => {
554
+ if (!key.includes("MastraCourse")) {
555
+ filteredTools[key] = tools[key];
556
+ }
557
+ });
558
+ const agentBuilderTools = {
559
+ ...filteredTools,
560
+ readFile: createTool({
561
+ id: "read-file",
562
+ description: "Read contents of a file with optional line range selection.",
563
+ inputSchema: z.object({
564
+ filePath: z.string().describe("Path to the file to read"),
565
+ startLine: z.number().optional().describe("Starting line number (1-indexed)"),
566
+ endLine: z.number().optional().describe("Ending line number (1-indexed, inclusive)"),
567
+ encoding: z.string().default("utf-8").describe("File encoding")
568
+ }),
569
+ outputSchema: z.object({
570
+ success: z.boolean(),
571
+ content: z.string().optional(),
572
+ lines: z.array(z.string()).optional(),
573
+ metadata: z.object({
574
+ size: z.number(),
575
+ totalLines: z.number(),
576
+ encoding: z.string(),
577
+ lastModified: z.string()
578
+ }).optional(),
579
+ error: z.string().optional()
580
+ }),
581
+ execute: async ({ context }) => {
582
+ return await _AgentBuilderDefaults.readFile({ ...context, projectPath });
583
+ }
584
+ }),
585
+ writeFile: createTool({
586
+ id: "write-file",
587
+ description: "Write content to a file, with options for creating directories.",
588
+ inputSchema: z.object({
589
+ filePath: z.string().describe("Path to the file to write"),
590
+ content: z.string().describe("Content to write to the file"),
591
+ createDirs: z.boolean().default(true).describe("Create parent directories if they don't exist"),
592
+ encoding: z.string().default("utf-8").describe("File encoding")
593
+ }),
594
+ outputSchema: z.object({
595
+ success: z.boolean(),
596
+ filePath: z.string(),
597
+ bytesWritten: z.number().optional(),
598
+ message: z.string(),
599
+ error: z.string().optional()
600
+ }),
601
+ execute: async ({ context }) => {
602
+ return await _AgentBuilderDefaults.writeFile({ ...context, projectPath });
603
+ }
604
+ }),
605
+ listDirectory: createTool({
606
+ id: "list-directory",
607
+ description: "List contents of a directory with filtering and metadata options.",
608
+ inputSchema: z.object({
609
+ path: z.string().describe("Directory path to list"),
610
+ recursive: z.boolean().default(false).describe("List subdirectories recursively"),
611
+ includeHidden: z.boolean().default(false).describe("Include hidden files and directories"),
612
+ pattern: z.string().optional().describe("Glob pattern to filter files"),
613
+ maxDepth: z.number().default(10).describe("Maximum recursion depth"),
614
+ includeMetadata: z.boolean().default(true).describe("Include file metadata")
615
+ }),
616
+ outputSchema: z.object({
617
+ success: z.boolean(),
618
+ items: z.array(
619
+ z.object({
620
+ name: z.string(),
621
+ path: z.string(),
622
+ type: z.enum(["file", "directory", "symlink"]),
623
+ size: z.number().optional(),
624
+ lastModified: z.string().optional(),
625
+ permissions: z.string().optional()
626
+ })
627
+ ),
628
+ totalItems: z.number(),
629
+ path: z.string(),
630
+ message: z.string(),
631
+ error: z.string().optional()
632
+ }),
633
+ execute: async ({ context }) => {
634
+ return await _AgentBuilderDefaults.listDirectory({ ...context, projectPath });
635
+ }
636
+ }),
637
+ executeCommand: createTool({
638
+ id: "execute-command",
639
+ description: "Execute shell commands with proper error handling and output capture.",
640
+ inputSchema: z.object({
641
+ command: z.string().describe("Shell command to execute"),
642
+ workingDirectory: z.string().optional().describe("Working directory for command execution"),
643
+ timeout: z.number().default(3e4).describe("Timeout in milliseconds"),
644
+ captureOutput: z.boolean().default(true).describe("Capture command output"),
645
+ shell: z.string().optional().describe("Shell to use (defaults to system shell)"),
646
+ env: z.record(z.string()).optional().describe("Environment variables")
647
+ }),
648
+ outputSchema: z.object({
649
+ success: z.boolean(),
650
+ exitCode: z.number().optional(),
651
+ stdout: z.string().optional(),
652
+ stderr: z.string().optional(),
653
+ command: z.string(),
654
+ workingDirectory: z.string().optional(),
655
+ executionTime: z.number().optional(),
656
+ error: z.string().optional()
657
+ }),
658
+ execute: async ({ context }) => {
659
+ return await _AgentBuilderDefaults.executeCommand({
660
+ ...context,
661
+ workingDirectory: context.workingDirectory || projectPath
662
+ });
663
+ }
664
+ }),
665
+ // Enhanced Task Management (Critical for complex coding tasks)
666
+ taskManager: createTool({
667
+ id: "task-manager",
668
+ description: "Create and manage structured task lists for coding sessions. Use this for complex multi-step tasks to track progress and ensure thoroughness.",
669
+ inputSchema: z.object({
670
+ action: z.enum(["create", "update", "list", "complete", "remove"]).describe("Task management action"),
671
+ tasks: z.array(
672
+ z.object({
673
+ id: z.string().describe("Unique task identifier"),
674
+ content: z.string().describe("Task description, optional if just updating the status").optional(),
675
+ status: z.enum(["pending", "in_progress", "completed", "blocked"]).describe("Task status"),
676
+ priority: z.enum(["high", "medium", "low"]).default("medium").describe("Task priority"),
677
+ dependencies: z.array(z.string()).optional().describe("IDs of tasks this depends on"),
678
+ notes: z.string().optional().describe("Additional notes or context")
679
+ })
680
+ ).optional().describe("Tasks to create or update"),
681
+ taskId: z.string().optional().describe("Specific task ID for single task operations")
682
+ }),
683
+ outputSchema: z.object({
684
+ success: z.boolean(),
685
+ tasks: z.array(
686
+ z.object({
687
+ id: z.string(),
688
+ content: z.string(),
689
+ status: z.string(),
690
+ priority: z.string(),
691
+ dependencies: z.array(z.string()).optional(),
692
+ notes: z.string().optional(),
693
+ createdAt: z.string(),
694
+ updatedAt: z.string()
695
+ })
696
+ ),
697
+ message: z.string()
698
+ }),
699
+ execute: async ({ context }) => {
700
+ return await _AgentBuilderDefaults.manageTaskList(context);
701
+ }
702
+ }),
703
+ // Advanced File Operations
704
+ multiEdit: createTool({
705
+ id: "multi-edit",
706
+ description: "Perform multiple search-replace operations on one or more files in a single atomic operation.",
707
+ inputSchema: z.object({
708
+ operations: z.array(
709
+ z.object({
710
+ filePath: z.string().describe("Path to the file to edit"),
711
+ edits: z.array(
712
+ z.object({
713
+ oldString: z.string().describe("Exact text to replace"),
714
+ newString: z.string().describe("Replacement text"),
715
+ replaceAll: z.boolean().default(false).describe("Replace all occurrences")
716
+ })
717
+ ).describe("List of edit operations for this file")
718
+ })
719
+ ).describe("File edit operations to perform"),
720
+ createBackup: z.boolean().default(false).describe("Create backup files before editing")
721
+ }),
722
+ outputSchema: z.object({
723
+ success: z.boolean(),
724
+ results: z.array(
725
+ z.object({
726
+ filePath: z.string(),
727
+ editsApplied: z.number(),
728
+ errors: z.array(z.string()),
729
+ backup: z.string().optional()
730
+ })
731
+ ),
732
+ message: z.string()
733
+ }),
734
+ execute: async ({ context }) => {
735
+ return await _AgentBuilderDefaults.performMultiEdit({ ...context, projectPath });
736
+ }
737
+ }),
738
+ // Interactive Communication
739
+ askClarification: createTool({
740
+ id: "ask-clarification",
741
+ description: "Ask the user for clarification when requirements are unclear or when multiple options exist.",
742
+ inputSchema: z.object({
743
+ question: z.string().describe("The specific question to ask"),
744
+ options: z.array(
745
+ z.object({
746
+ id: z.string(),
747
+ description: z.string(),
748
+ implications: z.string().optional()
749
+ })
750
+ ).optional().describe("Multiple choice options if applicable"),
751
+ context: z.string().optional().describe("Additional context about why clarification is needed"),
752
+ urgency: z.enum(["low", "medium", "high"]).default("medium").describe("How urgent the clarification is")
753
+ }),
754
+ outputSchema: z.object({
755
+ questionId: z.string(),
756
+ question: z.string(),
757
+ options: z.array(
758
+ z.object({
759
+ id: z.string(),
760
+ description: z.string()
761
+ })
762
+ ).optional(),
763
+ awaitingResponse: z.boolean()
764
+ }),
765
+ execute: async ({ context }) => {
766
+ return await _AgentBuilderDefaults.askClarification(context);
767
+ }
768
+ }),
769
+ // Enhanced Pattern Search
770
+ smartSearch: createTool({
771
+ id: "smart-search",
772
+ description: "Intelligent search across codebase with context awareness and pattern matching.",
773
+ inputSchema: z.object({
774
+ query: z.string().describe("Search query or pattern"),
775
+ type: z.enum(["text", "regex", "fuzzy", "semantic"]).default("text").describe("Type of search to perform"),
776
+ scope: z.object({
777
+ paths: z.array(z.string()).optional().describe("Specific paths to search"),
778
+ fileTypes: z.array(z.string()).optional().describe("File extensions to include"),
779
+ excludePaths: z.array(z.string()).optional().describe("Paths to exclude"),
780
+ maxResults: z.number().default(50).describe("Maximum number of results")
781
+ }).optional(),
782
+ context: z.object({
783
+ beforeLines: z.number().default(2).describe("Lines of context before match"),
784
+ afterLines: z.number().default(2).describe("Lines of context after match"),
785
+ includeDefinitions: z.boolean().default(false).describe("Include function/class definitions")
786
+ }).optional()
787
+ }),
788
+ outputSchema: z.object({
789
+ success: z.boolean(),
790
+ matches: z.array(
791
+ z.object({
792
+ file: z.string(),
793
+ line: z.number(),
794
+ column: z.number().optional(),
795
+ match: z.string(),
796
+ context: z.object({
797
+ before: z.array(z.string()),
798
+ after: z.array(z.string())
799
+ }),
800
+ relevance: z.number().optional()
801
+ })
802
+ ),
803
+ summary: z.object({
804
+ totalMatches: z.number(),
805
+ filesSearched: z.number(),
806
+ patterns: z.array(z.string())
807
+ })
808
+ }),
809
+ execute: async ({ context }) => {
810
+ return await _AgentBuilderDefaults.performSmartSearch(context);
811
+ }
812
+ }),
813
+ validateCode: createTool({
814
+ id: "validate-code",
815
+ description: "Validates generated code through TypeScript compilation, ESLint, schema validation, and other checks",
816
+ inputSchema: z.object({
817
+ projectPath: z.string().optional().describe("Path to the project to validate (defaults to current project)"),
818
+ validationType: z.array(z.enum(["types", "lint", "schemas", "tests", "build"])).describe("Types of validation to perform"),
819
+ files: z.array(z.string()).optional().describe("Specific files to validate (if not provided, validates entire project)")
820
+ }),
821
+ outputSchema: z.object({
822
+ valid: z.boolean(),
823
+ errors: z.array(
824
+ z.object({
825
+ type: z.enum(["typescript", "eslint", "schema", "test", "build"]),
826
+ severity: z.enum(["error", "warning", "info"]),
827
+ message: z.string(),
828
+ file: z.string().optional(),
829
+ line: z.number().optional(),
830
+ column: z.number().optional(),
831
+ code: z.string().optional()
832
+ })
833
+ ),
834
+ summary: z.object({
835
+ totalErrors: z.number(),
836
+ totalWarnings: z.number(),
837
+ validationsPassed: z.array(z.string()),
838
+ validationsFailed: z.array(z.string())
839
+ })
840
+ }),
841
+ execute: async ({ context }) => {
842
+ const { projectPath: validationProjectPath, validationType, files } = context;
843
+ const targetPath = validationProjectPath || projectPath;
844
+ return await _AgentBuilderDefaults.validateCode({
845
+ projectPath: targetPath,
846
+ validationType,
847
+ files
848
+ });
849
+ }
850
+ })
851
+ };
852
+ if (mode === "template") {
853
+ return agentBuilderTools;
854
+ } else {
855
+ return {
856
+ ...agentBuilderTools,
857
+ // Web Search (replaces MCP web search)
858
+ webSearch: createTool({
859
+ id: "web-search",
860
+ description: "Search the web for current information and return structured results.",
861
+ inputSchema: z.object({
862
+ query: z.string().describe("Search query"),
863
+ maxResults: z.number().default(10).describe("Maximum number of results to return"),
864
+ region: z.string().default("us").describe("Search region/country code"),
865
+ language: z.string().default("en").describe("Search language"),
866
+ includeImages: z.boolean().default(false).describe("Include image results"),
867
+ dateRange: z.enum(["day", "week", "month", "year", "all"]).default("all").describe("Date range filter")
868
+ }),
869
+ outputSchema: z.object({
870
+ success: z.boolean(),
871
+ query: z.string(),
872
+ results: z.array(
873
+ z.object({
874
+ title: z.string(),
875
+ url: z.string(),
876
+ snippet: z.string(),
877
+ domain: z.string(),
878
+ publishDate: z.string().optional(),
879
+ relevanceScore: z.number().optional()
880
+ })
881
+ ),
882
+ totalResults: z.number(),
883
+ searchTime: z.number(),
884
+ suggestions: z.array(z.string()).optional(),
885
+ error: z.string().optional()
886
+ }),
887
+ execute: async ({ context }) => {
888
+ return await _AgentBuilderDefaults.webSearch(context);
889
+ }
890
+ }),
891
+ // Enhanced Code Discovery
892
+ codeAnalyzer: createTool({
893
+ id: "code-analyzer",
894
+ description: "Analyze codebase structure, discover definitions, and understand architecture patterns.",
895
+ inputSchema: z.object({
896
+ action: z.enum(["definitions", "dependencies", "patterns", "structure"]).describe("Type of analysis to perform"),
897
+ path: z.string().describe("Directory or file path to analyze"),
898
+ language: z.string().optional().describe("Programming language filter"),
899
+ depth: z.number().default(3).describe("Directory traversal depth"),
900
+ includeTests: z.boolean().default(false).describe("Include test files in analysis")
901
+ }),
902
+ outputSchema: z.object({
903
+ success: z.boolean(),
904
+ analysis: z.object({
905
+ definitions: z.array(
906
+ z.object({
907
+ name: z.string(),
908
+ type: z.string(),
909
+ file: z.string(),
910
+ line: z.number().optional(),
911
+ scope: z.string().optional()
912
+ })
913
+ ).optional(),
914
+ dependencies: z.array(
915
+ z.object({
916
+ name: z.string(),
917
+ type: z.enum(["import", "require", "include"]),
918
+ source: z.string(),
919
+ target: z.string()
920
+ })
921
+ ).optional(),
922
+ patterns: z.array(
923
+ z.object({
924
+ pattern: z.string(),
925
+ description: z.string(),
926
+ files: z.array(z.string())
927
+ })
928
+ ).optional(),
929
+ structure: z.object({
930
+ directories: z.number(),
931
+ files: z.number(),
932
+ languages: z.record(z.number()),
933
+ complexity: z.string()
934
+ }).optional()
935
+ }),
936
+ message: z.string()
937
+ }),
938
+ execute: async ({ context }) => {
939
+ return await _AgentBuilderDefaults.analyzeCode(context);
940
+ }
941
+ }),
942
+ // Task Completion Signaling
943
+ attemptCompletion: createTool({
944
+ id: "attempt-completion",
945
+ description: "Signal that you believe the requested task has been completed and provide a summary.",
946
+ inputSchema: z.object({
947
+ summary: z.string().describe("Summary of what was accomplished"),
948
+ changes: z.array(
949
+ z.object({
950
+ type: z.enum([
951
+ "file_created",
952
+ "file_modified",
953
+ "file_deleted",
954
+ "command_executed",
955
+ "dependency_added"
956
+ ]),
957
+ description: z.string(),
958
+ path: z.string().optional()
959
+ })
960
+ ).describe("List of changes made"),
961
+ validation: z.object({
962
+ testsRun: z.boolean().default(false),
963
+ buildsSuccessfully: z.boolean().default(false),
964
+ manualTestingRequired: z.boolean().default(false)
965
+ }).describe("Validation status"),
966
+ nextSteps: z.array(z.string()).optional().describe("Suggested next steps or follow-up actions")
967
+ }),
968
+ outputSchema: z.object({
969
+ completionId: z.string(),
970
+ status: z.enum(["completed", "needs_review", "needs_testing"]),
971
+ summary: z.string(),
972
+ confidence: z.number().min(0).max(100)
973
+ }),
974
+ execute: async ({ context }) => {
975
+ return await _AgentBuilderDefaults.signalCompletion(context);
976
+ }
977
+ }),
978
+ manageProject: createTool({
979
+ id: "manage-project",
980
+ description: "Handles project management including creating project structures, managing dependencies, and package operations.",
981
+ inputSchema: z.object({
982
+ action: z.enum(["create", "install", "upgrade"]).describe("The action to perform"),
983
+ features: z.array(z.string()).optional().describe('Mastra features to include (e.g., ["agents", "memory", "workflows"])'),
984
+ packages: z.array(
985
+ z.object({
986
+ name: z.string(),
987
+ version: z.string().optional()
988
+ })
989
+ ).optional().describe("Packages to install/upgrade")
990
+ }),
991
+ outputSchema: z.object({
992
+ success: z.boolean(),
993
+ installed: z.array(z.string()).optional(),
994
+ upgraded: z.array(z.string()).optional(),
995
+ warnings: z.array(z.string()).optional(),
996
+ message: z.string().optional(),
997
+ details: z.string().optional(),
998
+ error: z.string().optional()
999
+ }),
1000
+ execute: async ({ context }) => {
1001
+ const { action, features, packages } = context;
1002
+ try {
1003
+ switch (action) {
1004
+ case "create":
1005
+ return await _AgentBuilderDefaults.createMastraProject({
1006
+ projectName: projectPath,
1007
+ features
1008
+ });
1009
+ case "install":
1010
+ if (!packages?.length) {
1011
+ return {
1012
+ success: false,
1013
+ message: "Packages array is required for install action"
1014
+ };
1015
+ }
1016
+ return await _AgentBuilderDefaults.installPackages({
1017
+ packages,
1018
+ projectPath
1019
+ });
1020
+ case "upgrade":
1021
+ if (!packages?.length) {
1022
+ return {
1023
+ success: false,
1024
+ message: "Packages array is required for upgrade action"
1025
+ };
1026
+ }
1027
+ return await _AgentBuilderDefaults.upgradePackages({
1028
+ packages,
1029
+ projectPath
1030
+ });
1031
+ // case 'check':
1032
+ // return await AgentBuilderDefaults.checkProject({
1033
+ // projectPath,
1034
+ // });
1035
+ default:
1036
+ return {
1037
+ success: false,
1038
+ message: `Unknown action: ${action}`
1039
+ };
1040
+ }
1041
+ } catch (error) {
1042
+ return {
1043
+ success: false,
1044
+ message: `Error executing ${action}: ${error instanceof Error ? error.message : String(error)}`
1045
+ };
1046
+ }
1047
+ }
1048
+ }),
1049
+ manageServer: createTool({
1050
+ id: "manage-server",
1051
+ description: "Manages the Mastra server - start, stop, restart, and check status, use the terminal tool to make curl requests to the server. There is an openapi spec for the server at http://localhost:{port}/openapi.json",
1052
+ inputSchema: z.object({
1053
+ action: z.enum(["start", "stop", "restart", "status"]).describe("Server management action"),
1054
+ port: z.number().optional().default(4200).describe("Port to run the server on")
1055
+ }),
1056
+ outputSchema: z.object({
1057
+ success: z.boolean(),
1058
+ status: z.enum(["running", "stopped", "starting", "stopping", "unknown"]),
1059
+ pid: z.number().optional(),
1060
+ port: z.number().optional(),
1061
+ url: z.string().optional(),
1062
+ message: z.string().optional(),
1063
+ stdout: z.array(z.string()).optional().describe("Server output lines captured during startup"),
1064
+ error: z.string().optional()
1065
+ }),
1066
+ execute: async ({ context }) => {
1067
+ const { action, port } = context;
1068
+ try {
1069
+ switch (action) {
1070
+ case "start":
1071
+ return await _AgentBuilderDefaults.startMastraServer({
1072
+ port,
1073
+ projectPath
1074
+ });
1075
+ case "stop":
1076
+ return await _AgentBuilderDefaults.stopMastraServer({
1077
+ port,
1078
+ projectPath
1079
+ });
1080
+ case "restart":
1081
+ const stopResult = await _AgentBuilderDefaults.stopMastraServer({
1082
+ port,
1083
+ projectPath
1084
+ });
1085
+ if (!stopResult.success) {
1086
+ return {
1087
+ success: false,
1088
+ status: "unknown",
1089
+ message: `Failed to restart: could not stop server on port ${port}`,
1090
+ error: stopResult.error || "Unknown stop error"
1091
+ };
1092
+ }
1093
+ await new Promise((resolve4) => setTimeout(resolve4, 500));
1094
+ const startResult = await _AgentBuilderDefaults.startMastraServer({
1095
+ port,
1096
+ projectPath
1097
+ });
1098
+ if (!startResult.success) {
1099
+ return {
1100
+ success: false,
1101
+ status: "stopped",
1102
+ message: `Failed to restart: server stopped successfully but failed to start on port ${port}`,
1103
+ error: startResult.error || "Unknown start error"
1104
+ };
1105
+ }
1106
+ return {
1107
+ ...startResult,
1108
+ message: `Mastra server restarted successfully on port ${port}`
1109
+ };
1110
+ case "status":
1111
+ return await _AgentBuilderDefaults.checkMastraServerStatus({
1112
+ port,
1113
+ projectPath
1114
+ });
1115
+ default:
1116
+ return {
1117
+ success: false,
1118
+ status: "unknown",
1119
+ message: `Unknown action: ${action}`
1120
+ };
1121
+ }
1122
+ } catch (error) {
1123
+ return {
1124
+ success: false,
1125
+ status: "unknown",
1126
+ message: `Error managing server: ${error instanceof Error ? error.message : String(error)}`
1127
+ };
1128
+ }
1129
+ }
1130
+ }),
1131
+ httpRequest: createTool({
1132
+ id: "http-request",
1133
+ description: "Makes HTTP requests to the Mastra server or external APIs for testing and integration",
1134
+ inputSchema: z.object({
1135
+ method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).describe("HTTP method"),
1136
+ url: z.string().describe("Full URL or path (if baseUrl provided)"),
1137
+ baseUrl: z.string().optional().describe("Base URL for the server (e.g., http://localhost:4200)"),
1138
+ headers: z.record(z.string()).optional().describe("HTTP headers"),
1139
+ body: z.any().optional().describe("Request body (will be JSON stringified if object)"),
1140
+ timeout: z.number().optional().default(3e4).describe("Request timeout in milliseconds")
1141
+ }),
1142
+ outputSchema: z.object({
1143
+ success: z.boolean(),
1144
+ status: z.number().optional(),
1145
+ statusText: z.string().optional(),
1146
+ headers: z.record(z.string()).optional(),
1147
+ data: z.any().optional(),
1148
+ error: z.string().optional(),
1149
+ url: z.string(),
1150
+ method: z.string()
1151
+ }),
1152
+ execute: async ({ context }) => {
1153
+ const { method, url, baseUrl, headers, body, timeout } = context;
1154
+ try {
1155
+ return await _AgentBuilderDefaults.makeHttpRequest({
1156
+ method,
1157
+ url,
1158
+ baseUrl,
1159
+ headers,
1160
+ body,
1161
+ timeout
1162
+ });
1163
+ } catch (error) {
1164
+ return {
1165
+ success: false,
1166
+ url: baseUrl ? `${baseUrl}${url}` : url,
1167
+ method,
1168
+ error: error instanceof Error ? error.message : String(error)
1169
+ };
1170
+ }
1171
+ }
1172
+ })
1173
+ };
1174
+ }
1175
+ };
1176
+ /**
1177
+ * Create a new Mastra project using create-mastra CLI
1178
+ */
1179
+ static async createMastraProject({ features, projectName }) {
1180
+ try {
1181
+ const args = ["pnpx", "create", "mastra@latest", projectName ?? "", "-l", "openai", "-k", "skip"];
1182
+ if (features && features.length > 0) {
1183
+ args.push("--components", features.join(","));
1184
+ }
1185
+ args.push("--example");
1186
+ const { stdout, stderr } = await exec(args.join(" "));
1187
+ return {
1188
+ success: true,
1189
+ projectPath: `./${projectName}`,
1190
+ message: `Successfully created Mastra project: ${projectName}.`,
1191
+ details: stdout,
1192
+ error: stderr
1193
+ };
1194
+ } catch (error) {
1195
+ return {
1196
+ success: false,
1197
+ message: `Failed to create project: ${error instanceof Error ? error.message : String(error)}`
1198
+ };
1199
+ }
1200
+ }
1201
+ /**
1202
+ * Install packages using the detected package manager
1203
+ */
1204
+ static async installPackages({
1205
+ packages,
1206
+ projectPath
1207
+ }) {
1208
+ try {
1209
+ console.log("Installing packages:", JSON.stringify(packages, null, 2));
1210
+ const packageStrings = packages.map((p) => `${p.name}`);
1211
+ await spawnSWPM(projectPath || "", "add", packageStrings);
1212
+ return {
1213
+ success: true,
1214
+ installed: packageStrings,
1215
+ message: `Successfully installed ${packages.length} package(s).`,
1216
+ details: ""
1217
+ };
1218
+ } catch (error) {
1219
+ return {
1220
+ success: false,
1221
+ message: `Failed to install packages: ${error instanceof Error ? error.message : String(error)}`
1222
+ };
1223
+ }
1224
+ }
1225
+ /**
1226
+ * Upgrade packages using the detected package manager
1227
+ */
1228
+ static async upgradePackages({
1229
+ packages,
1230
+ projectPath
1231
+ }) {
1232
+ try {
1233
+ console.log("Upgrading specific packages:", JSON.stringify(packages, null, 2));
1234
+ let packageNames = [];
1235
+ if (packages && packages.length > 0) {
1236
+ packageNames = packages.map((p) => `${p.name}`);
1237
+ }
1238
+ await spawnSWPM(projectPath || "", "upgrade", packageNames);
1239
+ return {
1240
+ success: true,
1241
+ upgraded: packages?.map((p) => p.name) || ["all packages"],
1242
+ message: `Packages upgraded successfully.`,
1243
+ details: ""
1244
+ };
1245
+ } catch (error) {
1246
+ return {
1247
+ success: false,
1248
+ message: `Failed to upgrade packages: ${error instanceof Error ? error.message : String(error)}`
1249
+ };
1250
+ }
1251
+ }
1252
+ // /**
1253
+ // * Check project health and status
1254
+ // */
1255
+ // static async checkProject({ projectPath }: { projectPath?: string }) {
1256
+ // try {
1257
+ // const execOptions = projectPath ? { cwd: projectPath } : {};
1258
+ // let hasPackageJson = false;
1259
+ // let hasMastraConfig = false;
1260
+ // try {
1261
+ // await exec('test -f package.json', execOptions);
1262
+ // hasPackageJson = true;
1263
+ // } catch {
1264
+ // // ignore
1265
+ // }
1266
+ // try {
1267
+ // await exec('test -f mastra.config.* || test -d src/mastra || test -d mastra', execOptions);
1268
+ // hasMastraConfig = true;
1269
+ // } catch {
1270
+ // // ignore
1271
+ // }
1272
+ // const warnings: string[] = [];
1273
+ // if (!hasPackageJson) {
1274
+ // warnings.push('No package.json found - this may not be a Node.js project');
1275
+ // }
1276
+ // if (!hasMastraConfig) {
1277
+ // warnings.push('No Mastra configuration found - run "npx create-mastra" to initialize');
1278
+ // }
1279
+ // return {
1280
+ // success: true,
1281
+ // message: `Project health check completed for ${projectPath || 'current directory'}`,
1282
+ // warnings,
1283
+ // checks: {
1284
+ // hasPackageJson,
1285
+ // hasMastraConfig,
1286
+ // },
1287
+ // };
1288
+ // } catch (error) {
1289
+ // return {
1290
+ // success: false,
1291
+ // message: `Failed to check project: ${error instanceof Error ? error.message : String(error)}`,
1292
+ // };
1293
+ // }
1294
+ // }
1295
+ /**
1296
+ * Start the Mastra server
1297
+ */
1298
+ static async startMastraServer({
1299
+ port = 4200,
1300
+ projectPath,
1301
+ env = {}
1302
+ }) {
1303
+ try {
1304
+ const serverEnv = { ...process.env, ...env, PORT: port.toString() };
1305
+ const execOptions = {
1306
+ cwd: projectPath || process.cwd(),
1307
+ env: serverEnv
1308
+ };
1309
+ const serverProcess = spawn$1("pnpm", ["run", "dev"], {
1310
+ ...execOptions,
1311
+ detached: true,
1312
+ stdio: "pipe"
1313
+ });
1314
+ const stdoutLines = [];
1315
+ const serverStarted = new Promise((resolve4, reject) => {
1316
+ const timeout = setTimeout(() => {
1317
+ reject(new Error(`Server startup timeout after 30 seconds. Output: ${stdoutLines.join("\n")}`));
1318
+ }, 3e4);
1319
+ serverProcess.stdout?.on("data", (data) => {
1320
+ const output = data.toString();
1321
+ const lines = output.split("\n").filter((line) => line.trim());
1322
+ stdoutLines.push(...lines);
1323
+ if (output.includes("Mastra API running on port")) {
1324
+ clearTimeout(timeout);
1325
+ resolve4({
1326
+ success: true,
1327
+ status: "running",
1328
+ pid: serverProcess.pid,
1329
+ port,
1330
+ url: `http://localhost:${port}`,
1331
+ message: `Mastra server started successfully on port ${port}`,
1332
+ stdout: stdoutLines
1333
+ });
1334
+ }
1335
+ });
1336
+ serverProcess.stderr?.on("data", (data) => {
1337
+ const errorOutput = data.toString();
1338
+ stdoutLines.push(`[STDERR] ${errorOutput}`);
1339
+ clearTimeout(timeout);
1340
+ reject(new Error(`Server startup failed with error: ${errorOutput}`));
1341
+ });
1342
+ serverProcess.on("error", (error) => {
1343
+ clearTimeout(timeout);
1344
+ reject(error);
1345
+ });
1346
+ serverProcess.on("exit", (code, signal) => {
1347
+ clearTimeout(timeout);
1348
+ if (code !== 0 && code !== null) {
1349
+ reject(
1350
+ new Error(
1351
+ `Server process exited with code ${code}${signal ? ` (signal: ${signal})` : ""}. Output: ${stdoutLines.join("\n")}`
1352
+ )
1353
+ );
1354
+ }
1355
+ });
1356
+ });
1357
+ return await serverStarted;
1358
+ } catch (error) {
1359
+ return {
1360
+ success: false,
1361
+ status: "stopped",
1362
+ error: error instanceof Error ? error.message : String(error)
1363
+ };
1364
+ }
1365
+ }
1366
+ /**
1367
+ * Stop the Mastra server
1368
+ */
1369
+ static async stopMastraServer({ port = 4200, projectPath: _projectPath }) {
1370
+ try {
1371
+ const { stdout } = await exec(`lsof -ti:${port} || echo "No process found"`);
1372
+ if (!stdout.trim() || stdout.trim() === "No process found") {
1373
+ return {
1374
+ success: true,
1375
+ status: "stopped",
1376
+ message: `No Mastra server found running on port ${port}`
1377
+ };
1378
+ }
1379
+ const pids = stdout.trim().split("\n").filter((pid) => pid.trim());
1380
+ const killedPids = [];
1381
+ const failedPids = [];
1382
+ for (const pidStr of pids) {
1383
+ const pid = parseInt(pidStr.trim());
1384
+ if (isNaN(pid)) continue;
1385
+ try {
1386
+ process.kill(pid, "SIGTERM");
1387
+ killedPids.push(pid);
1388
+ } catch {
1389
+ failedPids.push(pid);
1390
+ }
1391
+ }
1392
+ if (killedPids.length === 0) {
1393
+ return {
1394
+ success: false,
1395
+ status: "unknown",
1396
+ message: `Failed to stop any processes on port ${port}`,
1397
+ error: `Could not kill PIDs: ${failedPids.join(", ")}`
1398
+ };
1399
+ }
1400
+ await new Promise((resolve4) => setTimeout(resolve4, 2e3));
1401
+ try {
1402
+ const { stdout: checkStdout } = await exec(`lsof -ti:${port} || echo "No process found"`);
1403
+ if (checkStdout.trim() && checkStdout.trim() !== "No process found") {
1404
+ const remainingPids = checkStdout.trim().split("\n").filter((pid) => pid.trim());
1405
+ for (const pidStr of remainingPids) {
1406
+ const pid = parseInt(pidStr.trim());
1407
+ if (!isNaN(pid)) {
1408
+ try {
1409
+ process.kill(pid, "SIGKILL");
1410
+ } catch {
1411
+ }
1412
+ }
1413
+ }
1414
+ await new Promise((resolve4) => setTimeout(resolve4, 1e3));
1415
+ const { stdout: finalCheck } = await exec(`lsof -ti:${port} || echo "No process found"`);
1416
+ if (finalCheck.trim() && finalCheck.trim() !== "No process found") {
1417
+ return {
1418
+ success: false,
1419
+ status: "unknown",
1420
+ message: `Server processes still running on port ${port} after stop attempts`,
1421
+ error: `Remaining PIDs: ${finalCheck.trim()}`
1422
+ };
1423
+ }
1424
+ }
1425
+ } catch (error) {
1426
+ console.warn("Failed to verify server stop:", error);
1427
+ }
1428
+ return {
1429
+ success: true,
1430
+ status: "stopped",
1431
+ message: `Mastra server stopped successfully (port ${port}). Killed PIDs: ${killedPids.join(", ")}`
1432
+ };
1433
+ } catch (error) {
1434
+ return {
1435
+ success: false,
1436
+ status: "unknown",
1437
+ error: error instanceof Error ? error.message : String(error)
1438
+ };
1439
+ }
1440
+ }
1441
+ /**
1442
+ * Check Mastra server status
1443
+ */
1444
+ static async checkMastraServerStatus({
1445
+ port = 4200,
1446
+ projectPath: _projectPath
1447
+ }) {
1448
+ try {
1449
+ const controller = new AbortController();
1450
+ const timeoutId = setTimeout(() => controller.abort(), 5e3);
1451
+ const response = await fetch(`http://localhost:${port}/health`, {
1452
+ method: "GET",
1453
+ signal: controller.signal
1454
+ });
1455
+ clearTimeout(timeoutId);
1456
+ if (response.ok) {
1457
+ return {
1458
+ success: true,
1459
+ status: "running",
1460
+ port,
1461
+ url: `http://localhost:${port}`,
1462
+ message: "Mastra server is running and healthy"
1463
+ };
1464
+ } else {
1465
+ return {
1466
+ success: false,
1467
+ status: "unknown",
1468
+ port,
1469
+ message: `Server responding but not healthy (status: ${response.status})`
1470
+ };
1471
+ }
1472
+ } catch {
1473
+ try {
1474
+ const { stdout } = await exec(`lsof -ti:${port} || echo "No process found"`);
1475
+ const hasProcess = stdout.trim() && stdout.trim() !== "No process found";
1476
+ return {
1477
+ success: Boolean(hasProcess),
1478
+ status: hasProcess ? "starting" : "stopped",
1479
+ port,
1480
+ message: hasProcess ? "Server process exists but not responding to health checks" : "No server process found on specified port"
1481
+ };
1482
+ } catch {
1483
+ return {
1484
+ success: false,
1485
+ status: "stopped",
1486
+ port,
1487
+ message: "Server is not running"
1488
+ };
1489
+ }
1490
+ }
1491
+ }
1492
+ /**
1493
+ * Validate code using TypeScript, ESLint, and other tools
1494
+ */
1495
+ static async validateCode({
1496
+ projectPath,
1497
+ validationType,
1498
+ files
1499
+ }) {
1500
+ const errors = [];
1501
+ const validationsPassed = [];
1502
+ const validationsFailed = [];
1503
+ const execOptions = { cwd: projectPath };
1504
+ if (validationType.includes("types")) {
1505
+ try {
1506
+ const filePattern = files?.length ? files.join(" ") : "";
1507
+ const tscCommand = files?.length ? `npx tsc --noEmit ${filePattern}` : "npx tsc --noEmit";
1508
+ await exec(tscCommand, execOptions);
1509
+ validationsPassed.push("types");
1510
+ } catch (error) {
1511
+ let tsOutput = "";
1512
+ if (error.stdout) {
1513
+ tsOutput = error.stdout;
1514
+ } else if (error.stderr) {
1515
+ tsOutput = error.stderr;
1516
+ } else if (error.message) {
1517
+ tsOutput = error.message;
1518
+ }
1519
+ errors.push({
1520
+ type: "typescript",
1521
+ severity: "error",
1522
+ message: tsOutput.trim() || `TypeScript validation failed: ${error.message || String(error)}`
1523
+ });
1524
+ validationsFailed.push("types");
1525
+ }
1526
+ }
1527
+ if (validationType.includes("lint")) {
1528
+ try {
1529
+ const filePattern = files?.length ? files.join(" ") : ".";
1530
+ const eslintCommand = `npx eslint ${filePattern} --format json`;
1531
+ const { stdout } = await exec(eslintCommand, execOptions);
1532
+ if (stdout) {
1533
+ const eslintResults = JSON.parse(stdout);
1534
+ const eslintErrors = _AgentBuilderDefaults.parseESLintErrors(eslintResults);
1535
+ errors.push(...eslintErrors);
1536
+ if (eslintErrors.some((e) => e.severity === "error")) {
1537
+ validationsFailed.push("lint");
1538
+ } else {
1539
+ validationsPassed.push("lint");
1540
+ }
1541
+ } else {
1542
+ validationsPassed.push("lint");
1543
+ }
1544
+ } catch (error) {
1545
+ const errorMessage = error instanceof Error ? error.message : String(error);
1546
+ if (errorMessage.includes('"filePath"') || errorMessage.includes("messages")) {
1547
+ try {
1548
+ const eslintResults = JSON.parse(errorMessage);
1549
+ const eslintErrors = _AgentBuilderDefaults.parseESLintErrors(eslintResults);
1550
+ errors.push(...eslintErrors);
1551
+ validationsFailed.push("lint");
1552
+ } catch {
1553
+ errors.push({
1554
+ type: "eslint",
1555
+ severity: "error",
1556
+ message: `ESLint validation failed: ${errorMessage}`
1557
+ });
1558
+ validationsFailed.push("lint");
1559
+ }
1560
+ } else {
1561
+ validationsPassed.push("lint");
1562
+ }
1563
+ }
1564
+ }
1565
+ const totalErrors = errors.filter((e) => e.severity === "error").length;
1566
+ const totalWarnings = errors.filter((e) => e.severity === "warning").length;
1567
+ const isValid = totalErrors === 0;
1568
+ return {
1569
+ valid: isValid,
1570
+ errors,
1571
+ summary: {
1572
+ totalErrors,
1573
+ totalWarnings,
1574
+ validationsPassed,
1575
+ validationsFailed
1576
+ }
1577
+ };
1578
+ }
1579
+ /**
1580
+ * Parse ESLint errors from JSON output
1581
+ */
1582
+ static parseESLintErrors(eslintResults) {
1583
+ const errors = [];
1584
+ for (const result of eslintResults) {
1585
+ for (const message of result.messages || []) {
1586
+ if (message.message) {
1587
+ errors.push({
1588
+ type: "eslint",
1589
+ severity: message.severity === 1 ? "warning" : "error",
1590
+ message: message.message,
1591
+ file: result.filePath || void 0,
1592
+ line: message.line || void 0,
1593
+ column: message.column || void 0,
1594
+ code: message.ruleId || void 0
1595
+ });
1596
+ }
1597
+ }
1598
+ }
1599
+ return errors;
1600
+ }
1601
+ /**
1602
+ * Make HTTP request to server or external API
1603
+ */
1604
+ static async makeHttpRequest({
1605
+ method,
1606
+ url,
1607
+ baseUrl,
1608
+ headers = {},
1609
+ body,
1610
+ timeout = 3e4
1611
+ }) {
1612
+ try {
1613
+ const fullUrl = baseUrl ? `${baseUrl}${url}` : url;
1614
+ const controller = new AbortController();
1615
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
1616
+ const requestOptions = {
1617
+ method,
1618
+ headers: {
1619
+ "Content-Type": "application/json",
1620
+ ...headers
1621
+ },
1622
+ signal: controller.signal
1623
+ };
1624
+ if (body && (method === "POST" || method === "PUT" || method === "PATCH")) {
1625
+ requestOptions.body = typeof body === "string" ? body : JSON.stringify(body);
1626
+ }
1627
+ const response = await fetch(fullUrl, requestOptions);
1628
+ clearTimeout(timeoutId);
1629
+ let data;
1630
+ const contentType = response.headers.get("content-type");
1631
+ if (contentType?.includes("application/json")) {
1632
+ data = await response.json();
1633
+ } else {
1634
+ data = await response.text();
1635
+ }
1636
+ const responseHeaders = {};
1637
+ response.headers.forEach((value, key) => {
1638
+ responseHeaders[key] = value;
1639
+ });
1640
+ return {
1641
+ success: response.ok,
1642
+ status: response.status,
1643
+ statusText: response.statusText,
1644
+ headers: responseHeaders,
1645
+ data,
1646
+ url: fullUrl,
1647
+ method
1648
+ };
1649
+ } catch (error) {
1650
+ return {
1651
+ success: false,
1652
+ url: baseUrl ? `${baseUrl}${url}` : url,
1653
+ method,
1654
+ error: error instanceof Error ? error.message : String(error)
1655
+ };
1656
+ }
1657
+ }
1658
+ /**
1659
+ * Enhanced task management system for complex coding tasks
1660
+ */
1661
+ static async manageTaskList(context) {
1662
+ if (!_AgentBuilderDefaults.taskStorage) {
1663
+ _AgentBuilderDefaults.taskStorage = /* @__PURE__ */ new Map();
1664
+ }
1665
+ const sessionId = "current";
1666
+ const existingTasks = _AgentBuilderDefaults.taskStorage.get(sessionId) || [];
1667
+ try {
1668
+ switch (context.action) {
1669
+ case "create":
1670
+ if (!context.tasks?.length) {
1671
+ return {
1672
+ success: false,
1673
+ tasks: existingTasks,
1674
+ message: "No tasks provided for creation"
1675
+ };
1676
+ }
1677
+ const newTasks = context.tasks.map((task) => ({
1678
+ ...task,
1679
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1680
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1681
+ }));
1682
+ const allTasks = [...existingTasks, ...newTasks];
1683
+ _AgentBuilderDefaults.taskStorage.set(sessionId, allTasks);
1684
+ return {
1685
+ success: true,
1686
+ tasks: allTasks,
1687
+ message: `Created ${newTasks.length} new task(s)`
1688
+ };
1689
+ case "update":
1690
+ if (!context.tasks?.length) {
1691
+ return {
1692
+ success: false,
1693
+ tasks: existingTasks,
1694
+ message: "No tasks provided for update"
1695
+ };
1696
+ }
1697
+ const updatedTasks = existingTasks.map((existing) => {
1698
+ const update = context.tasks.find((t) => t.id === existing.id);
1699
+ return update ? { ...existing, ...update, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } : existing;
1700
+ });
1701
+ _AgentBuilderDefaults.taskStorage.set(sessionId, updatedTasks);
1702
+ return {
1703
+ success: true,
1704
+ tasks: updatedTasks,
1705
+ message: "Tasks updated successfully"
1706
+ };
1707
+ case "complete":
1708
+ if (!context.taskId) {
1709
+ return {
1710
+ success: false,
1711
+ tasks: existingTasks,
1712
+ message: "Task ID required for completion"
1713
+ };
1714
+ }
1715
+ const completedTasks = existingTasks.map(
1716
+ (task) => task.id === context.taskId ? { ...task, status: "completed", updatedAt: (/* @__PURE__ */ new Date()).toISOString() } : task
1717
+ );
1718
+ _AgentBuilderDefaults.taskStorage.set(sessionId, completedTasks);
1719
+ return {
1720
+ success: true,
1721
+ tasks: completedTasks,
1722
+ message: `Task ${context.taskId} marked as completed`
1723
+ };
1724
+ case "remove":
1725
+ if (!context.taskId) {
1726
+ return {
1727
+ success: false,
1728
+ tasks: existingTasks,
1729
+ message: "Task ID required for removal"
1730
+ };
1731
+ }
1732
+ const filteredTasks = existingTasks.filter((task) => task.id !== context.taskId);
1733
+ _AgentBuilderDefaults.taskStorage.set(sessionId, filteredTasks);
1734
+ return {
1735
+ success: true,
1736
+ tasks: filteredTasks,
1737
+ message: `Task ${context.taskId} removed`
1738
+ };
1739
+ case "list":
1740
+ default:
1741
+ return {
1742
+ success: true,
1743
+ tasks: existingTasks,
1744
+ message: `Found ${existingTasks.length} task(s)`
1745
+ };
1746
+ }
1747
+ } catch (error) {
1748
+ return {
1749
+ success: false,
1750
+ tasks: existingTasks,
1751
+ message: `Task management error: ${error instanceof Error ? error.message : String(error)}`
1752
+ };
1753
+ }
1754
+ }
1755
+ /**
1756
+ * Analyze codebase structure and patterns
1757
+ */
1758
+ static async analyzeCode(context) {
1759
+ try {
1760
+ const { action, path, language, depth = 3 } = context;
1761
+ const languagePattern = language ? `*.${language}` : "*";
1762
+ switch (action) {
1763
+ case "definitions":
1764
+ const definitionPatterns = [
1765
+ "function\\s+([a-zA-Z_][a-zA-Z0-9_]*)",
1766
+ "class\\s+([a-zA-Z_][a-zA-Z0-9_]*)",
1767
+ "interface\\s+([a-zA-Z_][a-zA-Z0-9_]*)",
1768
+ "const\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*=",
1769
+ "export\\s+(function|class|interface|const)\\s+([a-zA-Z_][a-zA-Z0-9_]*)"
1770
+ ];
1771
+ const definitions = [];
1772
+ for (const pattern of definitionPatterns) {
1773
+ try {
1774
+ const { stdout } = await exec(
1775
+ `rg -n "${pattern}" "${path}" --type ${languagePattern} --max-depth ${depth}`
1776
+ );
1777
+ const matches = stdout.split("\n").filter((line) => line.trim());
1778
+ matches.forEach((match) => {
1779
+ const parts = match.split(":");
1780
+ if (parts.length >= 3) {
1781
+ const file = parts[0];
1782
+ const lineStr = parts[1];
1783
+ const line = parseInt(lineStr || "0");
1784
+ const content = parts.slice(2).join(":");
1785
+ const nameMatch = content.match(/([a-zA-Z_][a-zA-Z0-9_]*)/);
1786
+ if (nameMatch && nameMatch[1]) {
1787
+ definitions.push({
1788
+ name: nameMatch[1],
1789
+ type: pattern.includes("function") ? "function" : pattern.includes("class") ? "class" : pattern.includes("interface") ? "interface" : "variable",
1790
+ file: file || "",
1791
+ line,
1792
+ scope: "top-level"
1793
+ });
1794
+ }
1795
+ }
1796
+ });
1797
+ } catch {
1798
+ }
1799
+ }
1800
+ return {
1801
+ success: true,
1802
+ analysis: { definitions },
1803
+ message: `Found ${definitions.length} code definitions`
1804
+ };
1805
+ case "dependencies":
1806
+ const depPatterns = [
1807
+ `import\\s+.*\\s+from\\s+['"]([^'"]+)['"]`,
1808
+ `require\\(['"]([^'"]+)['"]\\)`,
1809
+ '#include\\s+[<"]([^>"]+)[>"]'
1810
+ ];
1811
+ const dependencies = [];
1812
+ for (const pattern of depPatterns) {
1813
+ try {
1814
+ const { stdout } = await exec(`rg -n "${pattern}" "${path}" --type ${languagePattern}`);
1815
+ const matches = stdout.split("\n").filter((line) => line.trim());
1816
+ matches.forEach((match) => {
1817
+ const parts = match.split(":");
1818
+ if (parts.length >= 3) {
1819
+ const file = parts[0];
1820
+ const content = parts.slice(2).join(":");
1821
+ const depMatch = content.match(new RegExp(pattern));
1822
+ if (depMatch && depMatch[1]) {
1823
+ dependencies.push({
1824
+ name: depMatch[1],
1825
+ type: pattern.includes("import") ? "import" : pattern.includes("require") ? "require" : "include",
1826
+ source: file || "",
1827
+ target: depMatch[1]
1828
+ });
1829
+ }
1830
+ }
1831
+ });
1832
+ } catch {
1833
+ }
1834
+ }
1835
+ return {
1836
+ success: true,
1837
+ analysis: { dependencies },
1838
+ message: `Found ${dependencies.length} dependencies`
1839
+ };
1840
+ case "structure":
1841
+ const { stdout: lsOutput } = await exec(`find "${path}" -type f -name "${languagePattern}" | head -1000`);
1842
+ const files = lsOutput.split("\n").filter((line) => line.trim());
1843
+ const { stdout: dirOutput } = await exec(`find "${path}" -type d | wc -l`);
1844
+ const directories = parseInt(dirOutput.trim());
1845
+ const languages = {};
1846
+ files.forEach((file) => {
1847
+ const ext = file.split(".").pop();
1848
+ if (ext) {
1849
+ languages[ext] = (languages[ext] || 0) + 1;
1850
+ }
1851
+ });
1852
+ const complexity = files.length > 1e3 ? "high" : files.length > 100 ? "medium" : "low";
1853
+ return {
1854
+ success: true,
1855
+ analysis: {
1856
+ structure: {
1857
+ directories,
1858
+ files: files.length,
1859
+ languages,
1860
+ complexity
1861
+ }
1862
+ },
1863
+ message: `Analyzed project structure: ${files.length} files in ${directories} directories`
1864
+ };
1865
+ default:
1866
+ return {
1867
+ success: false,
1868
+ analysis: {},
1869
+ message: `Unknown analysis action: ${action}`
1870
+ };
1871
+ }
1872
+ } catch (error) {
1873
+ return {
1874
+ success: false,
1875
+ analysis: {},
1876
+ message: `Code analysis error: ${error instanceof Error ? error.message : String(error)}`
1877
+ };
1878
+ }
1879
+ }
1880
+ /**
1881
+ * Perform multiple edits across files atomically
1882
+ */
1883
+ static async performMultiEdit(context) {
1884
+ const results = [];
1885
+ try {
1886
+ const { projectPath } = context;
1887
+ for (const operation of context.operations) {
1888
+ const resolvedPath = isAbsolute(operation.filePath) ? operation.filePath : resolve(projectPath || process.cwd(), operation.filePath);
1889
+ const result = {
1890
+ filePath: resolvedPath,
1891
+ editsApplied: 0,
1892
+ errors: [],
1893
+ backup: void 0
1894
+ };
1895
+ try {
1896
+ const originalContent = await readFile(resolvedPath, "utf-8");
1897
+ if (context.createBackup) {
1898
+ const backupPath = `${resolvedPath}.backup.${Date.now()}`;
1899
+ await writeFile(backupPath, originalContent);
1900
+ result.backup = backupPath;
1901
+ }
1902
+ let modifiedContent = originalContent;
1903
+ for (const edit of operation.edits) {
1904
+ if (edit.replaceAll) {
1905
+ const regex = new RegExp(edit.oldString.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g");
1906
+ const matches = modifiedContent.match(regex);
1907
+ if (matches) {
1908
+ modifiedContent = modifiedContent.replace(regex, edit.newString);
1909
+ result.editsApplied += matches.length;
1910
+ }
1911
+ } else {
1912
+ if (modifiedContent.includes(edit.oldString)) {
1913
+ modifiedContent = modifiedContent.replace(edit.oldString, edit.newString);
1914
+ result.editsApplied++;
1915
+ } else {
1916
+ result.errors.push(`String not found: "${edit.oldString.substring(0, 50)}..."`);
1917
+ }
1918
+ }
1919
+ }
1920
+ if (result.editsApplied > 0) {
1921
+ await writeFile(resolvedPath, modifiedContent);
1922
+ }
1923
+ } catch (error) {
1924
+ result.errors.push(error instanceof Error ? error.message : String(error));
1925
+ }
1926
+ results.push(result);
1927
+ }
1928
+ const totalEdits = results.reduce((sum, r) => sum + r.editsApplied, 0);
1929
+ const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0);
1930
+ return {
1931
+ success: totalErrors === 0,
1932
+ results,
1933
+ message: `Applied ${totalEdits} edits across ${results.length} files${totalErrors > 0 ? ` with ${totalErrors} errors` : ""}`
1934
+ };
1935
+ } catch (error) {
1936
+ return {
1937
+ success: false,
1938
+ results,
1939
+ message: `Multi-edit operation failed: ${error instanceof Error ? error.message : String(error)}`
1940
+ };
1941
+ }
1942
+ }
1943
+ /**
1944
+ * Ask user for clarification
1945
+ */
1946
+ static async askClarification(context) {
1947
+ const questionId = `q_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1948
+ if (!_AgentBuilderDefaults.pendingQuestions) {
1949
+ _AgentBuilderDefaults.pendingQuestions = /* @__PURE__ */ new Map();
1950
+ }
1951
+ _AgentBuilderDefaults.pendingQuestions.set(questionId, {
1952
+ ...context,
1953
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1954
+ });
1955
+ return {
1956
+ questionId,
1957
+ question: context.question,
1958
+ options: context.options?.map((opt) => ({ id: opt.id, description: opt.description })),
1959
+ awaitingResponse: true
1960
+ };
1961
+ }
1962
+ /**
1963
+ * Signal task completion
1964
+ */
1965
+ static async signalCompletion(context) {
1966
+ const completionId = `completion_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1967
+ let confidence = 70;
1968
+ if (context.validation.testsRun) confidence += 15;
1969
+ if (context.validation.buildsSuccessfully) confidence += 15;
1970
+ if (context.validation.manualTestingRequired) confidence -= 10;
1971
+ let status;
1972
+ if (context.validation.testsRun && context.validation.buildsSuccessfully) {
1973
+ status = "completed";
1974
+ } else if (context.validation.manualTestingRequired) {
1975
+ status = "needs_testing";
1976
+ } else {
1977
+ status = "needs_review";
1978
+ }
1979
+ return {
1980
+ completionId,
1981
+ status,
1982
+ summary: context.summary,
1983
+ confidence: Math.min(100, Math.max(0, confidence))
1984
+ };
1985
+ }
1986
+ /**
1987
+ * Perform intelligent search with context
1988
+ */
1989
+ static async performSmartSearch(context) {
1990
+ try {
1991
+ const { query, type = "text", scope = {}, context: searchContext = {} } = context;
1992
+ const { paths = ["."], fileTypes = [], excludePaths = [], maxResults = 50 } = scope;
1993
+ const { beforeLines = 2, afterLines = 2 } = searchContext;
1994
+ let rgCommand = "rg";
1995
+ if (beforeLines > 0 || afterLines > 0) {
1996
+ rgCommand += ` -A ${afterLines} -B ${beforeLines}`;
1997
+ }
1998
+ rgCommand += " -n";
1999
+ if (type === "regex") {
2000
+ rgCommand += " -e";
2001
+ } else if (type === "fuzzy") {
2002
+ rgCommand += " --fixed-strings";
2003
+ }
2004
+ if (fileTypes.length > 0) {
2005
+ fileTypes.forEach((ft) => {
2006
+ rgCommand += ` --type-add 'custom:*.${ft}' -t custom`;
2007
+ });
2008
+ }
2009
+ excludePaths.forEach((path) => {
2010
+ rgCommand += ` --glob '!${path}'`;
2011
+ });
2012
+ rgCommand += ` -m ${maxResults}`;
2013
+ rgCommand += ` "${query}" ${paths.join(" ")}`;
2014
+ const { stdout } = await exec(rgCommand);
2015
+ const lines = stdout.split("\n").filter((line) => line.trim());
2016
+ const matches = [];
2017
+ let currentMatch = null;
2018
+ lines.forEach((line) => {
2019
+ if (line.includes(":") && !line.startsWith("-")) {
2020
+ const parts = line.split(":");
2021
+ if (parts.length >= 3) {
2022
+ if (currentMatch) {
2023
+ matches.push(currentMatch);
2024
+ }
2025
+ currentMatch = {
2026
+ file: parts[0] || "",
2027
+ line: parseInt(parts[1] || "0"),
2028
+ match: parts.slice(2).join(":"),
2029
+ context: { before: [], after: [] },
2030
+ relevance: type === "fuzzy" ? Math.random() * 100 : void 0
2031
+ };
2032
+ }
2033
+ } else if (line.startsWith("-") && currentMatch) {
2034
+ const contextLine = line.substring(1);
2035
+ if (currentMatch.context.before.length < beforeLines) {
2036
+ currentMatch.context.before.push(contextLine);
2037
+ } else {
2038
+ currentMatch.context.after.push(contextLine);
2039
+ }
2040
+ }
2041
+ });
2042
+ if (currentMatch) {
2043
+ matches.push(currentMatch);
2044
+ }
2045
+ const filesSearched = new Set(matches.map((m) => m.file)).size;
2046
+ return {
2047
+ success: true,
2048
+ matches: matches.slice(0, maxResults),
2049
+ summary: {
2050
+ totalMatches: matches.length,
2051
+ filesSearched,
2052
+ patterns: [query]
2053
+ }
2054
+ };
2055
+ } catch {
2056
+ return {
2057
+ success: false,
2058
+ matches: [],
2059
+ summary: {
2060
+ totalMatches: 0,
2061
+ filesSearched: 0,
2062
+ patterns: [context.query]
2063
+ }
2064
+ };
2065
+ }
2066
+ }
2067
+ // Static storage properties
2068
+ static taskStorage;
2069
+ static pendingQuestions;
2070
+ /**
2071
+ * Read file contents with optional line range
2072
+ */
2073
+ static async readFile(context) {
2074
+ try {
2075
+ const { filePath, startLine, endLine, encoding = "utf-8", projectPath } = context;
2076
+ const resolvedPath = isAbsolute(filePath) ? filePath : resolve(projectPath || process.cwd(), filePath);
2077
+ const stats = await stat(resolvedPath);
2078
+ const content = await readFile(resolvedPath, { encoding });
2079
+ const lines = content.split("\n");
2080
+ let resultContent = content;
2081
+ let resultLines = lines;
2082
+ if (startLine !== void 0 || endLine !== void 0) {
2083
+ const start = Math.max(0, (startLine || 1) - 1);
2084
+ const end = endLine !== void 0 ? Math.min(lines.length, endLine) : lines.length;
2085
+ resultLines = lines.slice(start, end);
2086
+ resultContent = resultLines.join("\n");
2087
+ }
2088
+ return {
2089
+ success: true,
2090
+ content: resultContent,
2091
+ lines: resultLines,
2092
+ metadata: {
2093
+ size: stats.size,
2094
+ totalLines: lines.length,
2095
+ encoding,
2096
+ lastModified: stats.mtime.toISOString()
2097
+ }
2098
+ };
2099
+ } catch (error) {
2100
+ return {
2101
+ success: false,
2102
+ error: error instanceof Error ? error.message : String(error)
2103
+ };
2104
+ }
2105
+ }
2106
+ /**
2107
+ * Write content to file with directory creation and backup options
2108
+ */
2109
+ static async writeFile(context) {
2110
+ try {
2111
+ const { filePath, content, createDirs = true, encoding = "utf-8", projectPath } = context;
2112
+ const resolvedPath = isAbsolute(filePath) ? filePath : resolve(projectPath || process.cwd(), filePath);
2113
+ const dir = dirname(resolvedPath);
2114
+ if (createDirs) {
2115
+ await mkdir(dir, { recursive: true });
2116
+ }
2117
+ await writeFile(resolvedPath, content, { encoding });
2118
+ return {
2119
+ success: true,
2120
+ filePath: resolvedPath,
2121
+ bytesWritten: Buffer.byteLength(content, encoding),
2122
+ message: `Successfully wrote ${Buffer.byteLength(content, encoding)} bytes to ${filePath}`
2123
+ };
2124
+ } catch (error) {
2125
+ return {
2126
+ success: false,
2127
+ filePath: context.filePath,
2128
+ message: `Failed to write file: ${error instanceof Error ? error.message : String(error)}`,
2129
+ error: error instanceof Error ? error.message : String(error)
2130
+ };
2131
+ }
2132
+ }
2133
+ /**
2134
+ * List directory contents with filtering and metadata
2135
+ */
2136
+ static async listDirectory(context) {
2137
+ try {
2138
+ const {
2139
+ path,
2140
+ recursive = false,
2141
+ includeHidden = false,
2142
+ pattern,
2143
+ maxDepth = 10,
2144
+ includeMetadata = true,
2145
+ projectPath
2146
+ } = context;
2147
+ const resolvedPath = isAbsolute(path) ? path : resolve(projectPath || process.cwd(), path);
2148
+ const items = [];
2149
+ async function processDirectory(dirPath, currentDepth = 0) {
2150
+ if (currentDepth > maxDepth) return;
2151
+ const entries = await readdir(dirPath);
2152
+ for (const entry of entries) {
2153
+ if (!includeHidden && entry.startsWith(".")) continue;
2154
+ const fullPath = join(dirPath, entry);
2155
+ const relativePath = relative(resolvedPath, fullPath);
2156
+ if (pattern) {
2157
+ const regexPattern = pattern.replace(/\*/g, ".*").replace(/\?/g, ".");
2158
+ if (!new RegExp(regexPattern).test(entry)) continue;
2159
+ }
2160
+ let stats;
2161
+ let type;
2162
+ try {
2163
+ stats = await stat(fullPath);
2164
+ if (stats.isDirectory()) {
2165
+ type = "directory";
2166
+ } else if (stats.isSymbolicLink()) {
2167
+ type = "symlink";
2168
+ } else {
2169
+ type = "file";
2170
+ }
2171
+ } catch {
2172
+ continue;
2173
+ }
2174
+ const item = {
2175
+ name: entry,
2176
+ path: relativePath || entry,
2177
+ type
2178
+ };
2179
+ if (includeMetadata) {
2180
+ item.size = stats.size;
2181
+ item.lastModified = stats.mtime.toISOString();
2182
+ item.permissions = `0${(stats.mode & parseInt("777", 8)).toString(8)}`;
2183
+ }
2184
+ items.push(item);
2185
+ if (recursive && type === "directory") {
2186
+ await processDirectory(fullPath, currentDepth + 1);
2187
+ }
2188
+ }
2189
+ }
2190
+ await processDirectory(resolvedPath);
2191
+ return {
2192
+ success: true,
2193
+ items,
2194
+ totalItems: items.length,
2195
+ path: resolvedPath,
2196
+ message: `Listed ${items.length} items in ${resolvedPath}`
2197
+ };
2198
+ } catch (error) {
2199
+ return {
2200
+ success: false,
2201
+ items: [],
2202
+ totalItems: 0,
2203
+ path: context.path,
2204
+ message: `Failed to list directory: ${error instanceof Error ? error.message : String(error)}`,
2205
+ error: error instanceof Error ? error.message : String(error)
2206
+ };
2207
+ }
2208
+ }
2209
+ /**
2210
+ * Execute shell commands with proper error handling
2211
+ */
2212
+ static async executeCommand(context) {
2213
+ const startTime = Date.now();
2214
+ try {
2215
+ const { command, workingDirectory, timeout = 3e4, captureOutput = true, shell, env } = context;
2216
+ const execOptions = {
2217
+ timeout,
2218
+ env: { ...process.env, ...env }
2219
+ };
2220
+ if (workingDirectory) {
2221
+ execOptions.cwd = workingDirectory;
2222
+ }
2223
+ if (shell) {
2224
+ execOptions.shell = shell;
2225
+ }
2226
+ const { stdout, stderr } = await exec(command, execOptions);
2227
+ const executionTime = Date.now() - startTime;
2228
+ return {
2229
+ success: true,
2230
+ exitCode: 0,
2231
+ stdout: captureOutput ? String(stdout) : void 0,
2232
+ stderr: captureOutput ? String(stderr) : void 0,
2233
+ command,
2234
+ workingDirectory,
2235
+ executionTime
2236
+ };
2237
+ } catch (error) {
2238
+ const executionTime = Date.now() - startTime;
2239
+ return {
2240
+ success: false,
2241
+ exitCode: error.code || 1,
2242
+ stdout: String(error.stdout || ""),
2243
+ stderr: String(error.stderr || ""),
2244
+ command: context.command,
2245
+ workingDirectory: context.workingDirectory,
2246
+ executionTime,
2247
+ error: error instanceof Error ? error.message : String(error)
2248
+ };
2249
+ }
2250
+ }
2251
+ /**
2252
+ * Web search using a simple search approach
2253
+ */
2254
+ static async webSearch(context) {
2255
+ try {
2256
+ const {
2257
+ query,
2258
+ maxResults = 10
2259
+ // region = 'us',
2260
+ // language = 'en',
2261
+ // includeImages = false,
2262
+ // dateRange = 'all',
2263
+ } = context;
2264
+ const startTime = Date.now();
2265
+ const searchUrl = `https://api.duckduckgo.com/?q=${encodeURIComponent(query)}&format=json&no_redirect=1&skip_disambig=1`;
2266
+ const response = await fetch(searchUrl);
2267
+ const data = await response.json();
2268
+ const results = [];
2269
+ if (data.RelatedTopics && Array.isArray(data.RelatedTopics)) {
2270
+ for (const topic of data.RelatedTopics.slice(0, maxResults)) {
2271
+ if (topic.FirstURL && topic.Text) {
2272
+ const url = new URL(topic.FirstURL);
2273
+ results.push({
2274
+ title: topic.Text.split(" - ")[0] || topic.Text.substring(0, 60),
2275
+ url: topic.FirstURL,
2276
+ snippet: topic.Text,
2277
+ domain: url.hostname,
2278
+ relevanceScore: Math.random() * 100
2279
+ // Placeholder scoring
2280
+ });
2281
+ }
2282
+ }
2283
+ }
2284
+ if (data.Abstract && data.AbstractURL) {
2285
+ const url = new URL(data.AbstractURL);
2286
+ results.unshift({
2287
+ title: data.Heading || "Main Result",
2288
+ url: data.AbstractURL,
2289
+ snippet: data.Abstract,
2290
+ domain: url.hostname,
2291
+ relevanceScore: 100
2292
+ });
2293
+ }
2294
+ const searchTime = Date.now() - startTime;
2295
+ return {
2296
+ success: true,
2297
+ query,
2298
+ results: results.slice(0, maxResults),
2299
+ totalResults: results.length,
2300
+ searchTime,
2301
+ suggestions: data.RelatedTopics?.slice(maxResults, maxResults + 3)?.map((t) => t.Text?.split(" - ")[0] || t.Text?.substring(0, 30)).filter(Boolean) || []
2302
+ };
2303
+ } catch (error) {
2304
+ return {
2305
+ success: false,
2306
+ query: context.query,
2307
+ results: [],
2308
+ totalResults: 0,
2309
+ searchTime: 0,
2310
+ error: error instanceof Error ? error.message : String(error)
2311
+ };
2312
+ }
2313
+ }
2314
+ };
2315
+ var ToolSummaryProcessor = class extends MemoryProcessor {
2316
+ summaryAgent;
2317
+ summaryCache = /* @__PURE__ */ new Map();
2318
+ constructor({ summaryModel }) {
2319
+ super({ name: "ToolSummaryProcessor" });
2320
+ this.summaryAgent = new Agent$1({
2321
+ name: "ToolSummaryAgent",
2322
+ description: "A summary agent that summarizes tool calls and results",
2323
+ instructions: "You are a summary agent that summarizes tool calls and results",
2324
+ model: summaryModel
2325
+ });
2326
+ }
2327
+ /**
2328
+ * Creates a cache key from tool call arguments
2329
+ */
2330
+ createCacheKey(toolCall) {
2331
+ if (!toolCall) return "unknown";
2332
+ const toolName = toolCall.toolName || "unknown";
2333
+ const args = toolCall.args || {};
2334
+ const sortedArgs = Object.keys(args).sort().reduce((result, key) => {
2335
+ result[key] = args[key];
2336
+ return result;
2337
+ }, {});
2338
+ return `${toolName}:${JSON.stringify(sortedArgs)}`;
2339
+ }
2340
+ /**
2341
+ * Clears the summary cache
2342
+ */
2343
+ clearCache() {
2344
+ this.summaryCache.clear();
2345
+ }
2346
+ /**
2347
+ * Gets cache statistics
2348
+ */
2349
+ getCacheStats() {
2350
+ return {
2351
+ size: this.summaryCache.size,
2352
+ keys: Array.from(this.summaryCache.keys())
2353
+ };
2354
+ }
2355
+ async process(messages) {
2356
+ const summaryTasks = [];
2357
+ for (const message of messages) {
2358
+ if (message.role === "tool" && Array.isArray(message.content) && message.content.length > 0 && message.content?.some((content) => content.type === "tool-result")) {
2359
+ for (const content of message.content) {
2360
+ if (content.type === "tool-result") {
2361
+ const assistantMessageWithToolCall = messages.find(
2362
+ (message2) => message2.role === "assistant" && Array.isArray(message2.content) && message2.content.length > 0 && message2.content?.some(
2363
+ (assistantContent) => assistantContent.type === "tool-call" && assistantContent.toolCallId === content.toolCallId
2364
+ )
2365
+ );
2366
+ const toolCall = Array.isArray(assistantMessageWithToolCall?.content) ? assistantMessageWithToolCall?.content.find(
2367
+ (assistantContent) => assistantContent.type === "tool-call" && assistantContent.toolCallId === content.toolCallId
2368
+ ) : null;
2369
+ const cacheKey = this.createCacheKey(toolCall);
2370
+ const cachedSummary = this.summaryCache.get(cacheKey);
2371
+ if (cachedSummary) {
2372
+ content.result = `Tool call summary: ${cachedSummary}`;
2373
+ } else {
2374
+ const summaryPromise = this.summaryAgent.generate(
2375
+ `Summarize the following tool call: ${JSON.stringify(toolCall)} and result: ${JSON.stringify(content)}`
2376
+ );
2377
+ summaryTasks.push({
2378
+ content,
2379
+ promise: summaryPromise,
2380
+ cacheKey
2381
+ });
2382
+ }
2383
+ }
2384
+ }
2385
+ }
2386
+ }
2387
+ if (summaryTasks.length > 0) {
2388
+ const summaryResults = await Promise.all(summaryTasks.map((task) => task.promise));
2389
+ summaryTasks.forEach((task, index) => {
2390
+ const summaryResult = summaryResults[index];
2391
+ const summaryText = summaryResult.text;
2392
+ this.summaryCache.set(task.cacheKey, summaryText);
2393
+ task.content.result = `Tool call summary: ${summaryText}`;
2394
+ });
2395
+ }
2396
+ return messages;
2397
+ }
2398
+ };
2399
+ var WriteToDiskProcessor = class extends MemoryProcessor {
2400
+ prefix;
2401
+ constructor({ prefix = "messages" } = {}) {
2402
+ super({ name: "WriteToDiskProcessor" });
2403
+ this.prefix = prefix;
2404
+ }
2405
+ async process(messages) {
2406
+ await writeFile(`${this.prefix}-${Date.now()}.json`, JSON.stringify(messages, null, 2));
2407
+ return messages;
2408
+ }
2409
+ };
2410
+ var cloneTemplateStep = createStep({
2411
+ id: "clone-template",
2412
+ description: "Clone the template repository to a temporary directory at the specified ref",
2413
+ inputSchema: MergeInputSchema,
2414
+ outputSchema: z.object({
2415
+ templateDir: z.string(),
2416
+ commitSha: z.string(),
2417
+ slug: z.string()
2418
+ }),
2419
+ execute: async ({ inputData }) => {
2420
+ const { repo, ref = "main", slug } = inputData;
2421
+ if (!repo) {
2422
+ throw new Error("Repository URL or path is required");
2423
+ }
2424
+ const inferredSlug = slug || repo.split("/").pop()?.replace(/\.git$/, "") || "template";
2425
+ const tempDir = await mkdtemp(join(tmpdir(), "mastra-template-"));
2426
+ try {
2427
+ const cloneCmd = `git clone "${repo}" "${tempDir}"`;
2428
+ await exec(cloneCmd);
2429
+ if (ref !== "main" && ref !== "master") {
2430
+ await exec(`git checkout "${ref}"`, { cwd: tempDir });
2431
+ }
2432
+ const { stdout: commitSha } = await exec("git rev-parse HEAD", { cwd: tempDir });
2433
+ return {
2434
+ templateDir: tempDir,
2435
+ commitSha: commitSha.trim(),
2436
+ slug: inferredSlug
2437
+ };
2438
+ } catch (error) {
2439
+ try {
2440
+ await rm(tempDir, { recursive: true, force: true });
2441
+ } catch {
2442
+ }
2443
+ throw new Error(`Failed to clone template: ${error instanceof Error ? error.message : String(error)}`);
2444
+ }
2445
+ }
2446
+ });
2447
+ var analyzePackageStep = createStep({
2448
+ id: "analyze-package",
2449
+ description: "Analyze the template package.json to extract dependency information",
2450
+ inputSchema: z.object({
2451
+ templateDir: z.string(),
2452
+ commitSha: z.string(),
2453
+ slug: z.string()
2454
+ }),
2455
+ outputSchema: z.object({
2456
+ dependencies: z.record(z.string()).optional(),
2457
+ devDependencies: z.record(z.string()).optional(),
2458
+ peerDependencies: z.record(z.string()).optional(),
2459
+ scripts: z.record(z.string()).optional(),
2460
+ packageInfo: z.object({
2461
+ name: z.string().optional(),
2462
+ version: z.string().optional(),
2463
+ description: z.string().optional()
2464
+ })
2465
+ }),
2466
+ execute: async ({ inputData }) => {
2467
+ console.log("Analyzing template package.json...");
2468
+ const { templateDir } = inputData;
2469
+ const packageJsonPath = join(templateDir, "package.json");
2470
+ try {
2471
+ const packageJsonContent = await readFile(packageJsonPath, "utf-8");
2472
+ const packageJson = JSON.parse(packageJsonContent);
2473
+ console.log("Template package.json:", JSON.stringify(packageJson, null, 2));
2474
+ return {
2475
+ dependencies: packageJson.dependencies || {},
2476
+ devDependencies: packageJson.devDependencies || {},
2477
+ peerDependencies: packageJson.peerDependencies || {},
2478
+ scripts: packageJson.scripts || {},
2479
+ packageInfo: {
2480
+ name: packageJson.name,
2481
+ version: packageJson.version,
2482
+ description: packageJson.description
2483
+ }
2484
+ };
2485
+ } catch (error) {
2486
+ console.warn(`Failed to read template package.json: ${error instanceof Error ? error.message : String(error)}`);
2487
+ return {
2488
+ dependencies: {},
2489
+ devDependencies: {},
2490
+ peerDependencies: {},
2491
+ scripts: {},
2492
+ packageInfo: {}
2493
+ };
2494
+ }
2495
+ }
2496
+ });
2497
+ var discoverUnitsStep = createStep({
2498
+ id: "discover-units",
2499
+ description: "Discover template units by analyzing the templates directory structure",
2500
+ inputSchema: z.object({
2501
+ templateDir: z.string(),
2502
+ commitSha: z.string(),
2503
+ slug: z.string()
2504
+ }),
2505
+ outputSchema: z.object({
2506
+ units: z.array(TemplateUnitSchema)
2507
+ }),
2508
+ execute: async ({ inputData }) => {
2509
+ const { templateDir } = inputData;
2510
+ const tools = await AgentBuilderDefaults.DEFAULT_TOOLS(templateDir);
2511
+ const agent = new Agent({
2512
+ model: openai("gpt-4o-mini"),
2513
+ instructions: `You are an expert at analyzing Mastra projects.
2514
+
2515
+ Your task is to scan the provided directory and identify all available units (agents, workflows, tools, MCP servers, networks).
2516
+
2517
+ Mastra Project Structure Analysis:
2518
+ - Each Mastra project has a structure like: ${AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE.agent}, ${AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE.workflow}, ${AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE.tool}, ${AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE["mcp-server"]}, ${AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE.network}
2519
+ - Analyze TypeScript files in each category directory to identify exported units
2520
+
2521
+ CRITICAL: YOU MUST USE YOUR TOOLS (readFile, listDirectory) TO DISCOVER THE UNITS IN THE TEMPLATE DIRECTORY.
2522
+
2523
+ IMPORTANT - Agent Discovery Rules:
2524
+ 1. **Multiple Agent Files**: Some templates have separate files for each agent (e.g., evaluationAgent.ts, researchAgent.ts)
2525
+ 2. **Single File Multiple Agents**: Some files may export multiple agents (look for multiple 'export const' or 'export default' statements)
2526
+ 3. **Agent Identification**: Look for exported variables that are instances of 'new Agent()' or similar patterns
2527
+ 4. **Naming Convention**: Agent names should be extracted from the export name (e.g., 'weatherAgent', 'evaluationAgent')
2528
+
2529
+ For each Mastra project directory you analyze:
2530
+ 1. Scan all TypeScript files in ${AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE.agent} and identify ALL exported agents
2531
+ 2. Scan all TypeScript files in ${AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE.workflow} and identify ALL exported workflows
2532
+ 3. Scan all TypeScript files in ${AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE.tool} and identify ALL exported tools
2533
+ 4. Scan all TypeScript files in ${AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE["mcp-server"]} and identify ALL exported MCP servers
2534
+ 5. Scan all TypeScript files in ${AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE.network} and identify ALL exported networks
2535
+ 6. Scan for any OTHER files in src/mastra that are NOT in the above default folders (e.g., lib/, utils/, types/, etc.) and identify them as 'other' files
2536
+
2537
+ IMPORTANT - Naming Consistency Rules:
2538
+ - For ALL unit types (including 'other'), the 'name' field should be the filename WITHOUT extension
2539
+ - For structured units (agents, workflows, tools, etc.), prefer the actual export name if clearly identifiable
2540
+ - use the base filename without extension for the id (e.g., 'util.ts' \u2192 name: 'util')
2541
+ - use the relative path from the template root for the file (e.g., 'src/mastra/lib/util.ts' \u2192 file: 'src/mastra/lib/util.ts')
2542
+
2543
+ Return the actual exported names of the units, as well as the file names.`,
2544
+ name: "Mastra Project Discoverer",
2545
+ tools: {
2546
+ readFile: tools.readFile,
2547
+ listDirectory: tools.listDirectory
2548
+ }
2549
+ });
2550
+ const result = await agent.generate(
2551
+ `Analyze the Mastra project directory structure at "${templateDir}".
2552
+
2553
+ List directory contents using listDirectory tool, and then analyze each file with readFile tool.
2554
+ IMPORTANT:
2555
+ - Look inside the actual file content to find export statements like 'export const agentName = new Agent(...)'
2556
+ - A single file may contain multiple exports
2557
+ - Return the actual exported variable names, as well as the file names
2558
+ - If a directory doesn't exist or has no files, return an empty array
2559
+
2560
+ Return the analysis in the exact format specified in the output schema.`,
2561
+ {
2562
+ experimental_output: z.object({
2563
+ agents: z.array(z.object({ name: z.string(), file: z.string() })).optional(),
2564
+ workflows: z.array(z.object({ name: z.string(), file: z.string() })).optional(),
2565
+ tools: z.array(z.object({ name: z.string(), file: z.string() })).optional(),
2566
+ mcp: z.array(z.object({ name: z.string(), file: z.string() })).optional(),
2567
+ networks: z.array(z.object({ name: z.string(), file: z.string() })).optional(),
2568
+ other: z.array(z.object({ name: z.string(), file: z.string() })).optional()
2569
+ }),
2570
+ maxSteps: 100
2571
+ }
2572
+ );
2573
+ const template = result.object ?? {};
2574
+ const units = [];
2575
+ template.agents?.forEach((agentId) => {
2576
+ units.push({ kind: "agent", id: agentId.name, file: agentId.file });
2577
+ });
2578
+ template.workflows?.forEach((workflowId) => {
2579
+ units.push({ kind: "workflow", id: workflowId.name, file: workflowId.file });
2580
+ });
2581
+ template.tools?.forEach((toolId) => {
2582
+ units.push({ kind: "tool", id: toolId.name, file: toolId.file });
2583
+ });
2584
+ template.mcp?.forEach((mcpId) => {
2585
+ units.push({ kind: "mcp-server", id: mcpId.name, file: mcpId.file });
2586
+ });
2587
+ template.networks?.forEach((networkId) => {
2588
+ units.push({ kind: "network", id: networkId.name, file: networkId.file });
2589
+ });
2590
+ template.other?.forEach((otherId) => {
2591
+ units.push({ kind: "other", id: otherId.name, file: otherId.file });
2592
+ });
2593
+ console.log("Discovered units:", JSON.stringify(units, null, 2));
2594
+ return { units };
2595
+ }
2596
+ });
2597
+ var orderUnitsStep = createStep({
2598
+ id: "order-units",
2599
+ description: "Sort units in topological order based on kind weights",
2600
+ inputSchema: z.object({
2601
+ units: z.array(TemplateUnitSchema)
2602
+ }),
2603
+ outputSchema: z.object({
2604
+ orderedUnits: z.array(TemplateUnitSchema)
2605
+ }),
2606
+ execute: async ({ inputData }) => {
2607
+ const { units } = inputData;
2608
+ const orderedUnits = [...units].sort((a, b) => {
2609
+ const aWeight = kindWeight(a.kind);
2610
+ const bWeight = kindWeight(b.kind);
2611
+ return aWeight - bWeight;
2612
+ });
2613
+ return { orderedUnits };
2614
+ }
2615
+ });
2616
+ var packageMergeStep = createStep({
2617
+ id: "package-merge",
2618
+ description: "Merge template package.json dependencies into target project and install",
2619
+ inputSchema: z.object({
2620
+ commitSha: z.string(),
2621
+ slug: z.string(),
2622
+ targetPath: z.string().optional(),
2623
+ packageInfo: z.object({
2624
+ dependencies: z.record(z.string()).optional(),
2625
+ devDependencies: z.record(z.string()).optional(),
2626
+ peerDependencies: z.record(z.string()).optional(),
2627
+ scripts: z.record(z.string()).optional(),
2628
+ packageInfo: z.object({
2629
+ name: z.string().optional(),
2630
+ version: z.string().optional(),
2631
+ description: z.string().optional()
2632
+ })
2633
+ })
2634
+ }),
2635
+ outputSchema: z.object({
2636
+ success: z.boolean(),
2637
+ applied: z.boolean(),
2638
+ message: z.string(),
2639
+ error: z.string().optional()
2640
+ }),
2641
+ execute: async ({ inputData, runtimeContext }) => {
2642
+ console.log("Package merge step starting...");
2643
+ const { slug, packageInfo } = inputData;
2644
+ const targetPath = inputData.targetPath || runtimeContext.get("targetPath") || process.cwd();
2645
+ try {
2646
+ const allTools = await AgentBuilderDefaults.DEFAULT_TOOLS(targetPath);
2647
+ const packageMergeAgent = new Agent({
2648
+ name: "package-merger",
2649
+ description: "Specialized agent for merging package.json dependencies",
2650
+ instructions: `You are a package.json merge specialist. Your job is to:
2651
+
2652
+ 1. **Read the target project's package.json** using readFile tool
2653
+ 2. **Merge template dependencies** into the target package.json following these rules:
2654
+ - For dependencies: Add ALL NEW ones with template versions, KEEP EXISTING versions for conflicts
2655
+ - For devDependencies: Add ALL NEW ones with template versions, KEEP EXISTING versions for conflicts
2656
+ - For peerDependencies: Add ALL NEW ones with template versions, KEEP EXISTING versions for conflicts
2657
+ - For scripts: Add new scripts with "template:${slug}:" prefix, don't overwrite existing ones
2658
+ - Maintain existing package.json structure and formatting
2659
+ 3. **Write the updated package.json** using writeFile tool
2660
+
2661
+ Template Dependencies to Merge:
2662
+ - Dependencies: ${JSON.stringify(packageInfo.dependencies || {}, null, 2)}
2663
+ - Dev Dependencies: ${JSON.stringify(packageInfo.devDependencies || {}, null, 2)}
2664
+ - Peer Dependencies: ${JSON.stringify(packageInfo.peerDependencies || {}, null, 2)}
2665
+ - Scripts: ${JSON.stringify(packageInfo.scripts || {}, null, 2)}
2666
+
2667
+ CRITICAL MERGE RULES:
2668
+ 1. For each dependency in template dependencies, if it does NOT exist in target, ADD it with template version
2669
+ 2. For each dependency in template dependencies, if it ALREADY exists in target, KEEP target version
2670
+ 3. You MUST add ALL template dependencies that don't conflict - do not skip any
2671
+ 4. Be explicit about what you're adding vs keeping
2672
+
2673
+ EXAMPLE:
2674
+ Template has: {"@mastra/libsql": "latest", "@mastra/core": "latest", "zod": "^3.25.67"}
2675
+ Target has: {"@mastra/core": "latest", "zod": "^3.25.0"}
2676
+ Result should have: {"@mastra/core": "latest", "zod": "^3.25.0", "@mastra/libsql": "latest"}
2677
+
2678
+ Be systematic and thorough. Always read the existing package.json first, then merge, then write.`,
2679
+ model: openai("gpt-4o-mini"),
2680
+ tools: {
2681
+ readFile: allTools.readFile,
2682
+ writeFile: allTools.writeFile,
2683
+ listDirectory: allTools.listDirectory
2684
+ }
2685
+ });
2686
+ console.log("Starting package merge agent...");
2687
+ console.log("Template dependencies to merge:", JSON.stringify(packageInfo.dependencies, null, 2));
2688
+ console.log("Template devDependencies to merge:", JSON.stringify(packageInfo.devDependencies, null, 2));
2689
+ const result = await packageMergeAgent.stream(
2690
+ `Please merge the template dependencies into the target project's package.json at ${targetPath}/package.json.`,
2691
+ { experimental_output: z.object({ success: z.boolean() }) }
2692
+ );
2693
+ let buffer = [];
2694
+ for await (const chunk of result.fullStream) {
2695
+ if (chunk.type === "text-delta") {
2696
+ buffer.push(chunk.textDelta);
2697
+ if (buffer.length > 20) {
2698
+ console.log(buffer.join(""));
2699
+ buffer = [];
2700
+ }
2701
+ }
2702
+ }
2703
+ if (buffer.length > 0) {
2704
+ console.log(buffer.join(""));
2705
+ }
2706
+ return {
2707
+ success: true,
2708
+ applied: true,
2709
+ message: `Successfully merged template dependencies and installed packages for ${slug}`
2710
+ };
2711
+ } catch (error) {
2712
+ console.error("Package merge failed:", error);
2713
+ return {
2714
+ success: false,
2715
+ applied: false,
2716
+ message: `Package merge failed: ${error instanceof Error ? error.message : String(error)}`,
2717
+ error: error instanceof Error ? error.message : String(error)
2718
+ };
2719
+ }
2720
+ }
2721
+ });
2722
+ var flatInstallStep = createStep({
2723
+ id: "flat-install",
2724
+ description: "Run a flat install command without specifying packages",
2725
+ inputSchema: z.object({
2726
+ targetPath: z.string().describe("Path to the project to install packages in")
2727
+ }),
2728
+ outputSchema: z.object({
2729
+ success: z.boolean(),
2730
+ message: z.string(),
2731
+ details: z.string().optional()
2732
+ }),
2733
+ execute: async ({ inputData, runtimeContext }) => {
2734
+ console.log("Running flat install...");
2735
+ const targetPath = inputData.targetPath || runtimeContext.get("targetPath") || process.cwd();
2736
+ try {
2737
+ await spawnSWPM(targetPath, "install", []);
2738
+ return {
2739
+ success: true,
2740
+ message: "Successfully ran flat install command",
2741
+ details: "Installed all dependencies from package.json"
2742
+ };
2743
+ } catch (error) {
2744
+ console.error("Flat install failed:", error);
2745
+ return {
2746
+ success: false,
2747
+ message: `Flat install failed: ${error instanceof Error ? error.message : String(error)}`
2748
+ };
2749
+ }
2750
+ }
2751
+ });
2752
+ var programmaticFileCopyStep = createStep({
2753
+ id: "programmatic-file-copy",
2754
+ description: "Programmatically copy template files to target project based on ordered units",
2755
+ inputSchema: z.object({
2756
+ orderedUnits: z.array(
2757
+ z.object({
2758
+ kind: z.string(),
2759
+ id: z.string(),
2760
+ file: z.string()
2761
+ })
2762
+ ),
2763
+ templateDir: z.string(),
2764
+ commitSha: z.string(),
2765
+ slug: z.string(),
2766
+ targetPath: z.string().optional()
2767
+ }),
2768
+ outputSchema: z.object({
2769
+ success: z.boolean(),
2770
+ copiedFiles: z.array(
2771
+ z.object({
2772
+ source: z.string(),
2773
+ destination: z.string(),
2774
+ unit: z.object({
2775
+ kind: z.string(),
2776
+ id: z.string()
2777
+ })
2778
+ })
2779
+ ),
2780
+ conflicts: z.array(
2781
+ z.object({
2782
+ unit: z.object({
2783
+ kind: z.string(),
2784
+ id: z.string()
2785
+ }),
2786
+ issue: z.string(),
2787
+ sourceFile: z.string(),
2788
+ targetFile: z.string()
2789
+ })
2790
+ ),
2791
+ message: z.string(),
2792
+ error: z.string().optional()
2793
+ }),
2794
+ execute: async ({ inputData, runtimeContext }) => {
2795
+ console.log("Programmatic file copy step starting...");
2796
+ const { orderedUnits, templateDir, commitSha, slug } = inputData;
2797
+ const targetPath = inputData.targetPath || runtimeContext.get("targetPath") || process.cwd();
2798
+ try {
2799
+ const copiedFiles = [];
2800
+ const conflicts = [];
2801
+ const analyzeNamingConvention = async (directory) => {
2802
+ try {
2803
+ const files = await readdir(resolve(targetPath, directory), { withFileTypes: true });
2804
+ const tsFiles = files.filter((f) => f.isFile() && f.name.endsWith(".ts")).map((f) => f.name);
2805
+ if (tsFiles.length === 0) return "unknown";
2806
+ const camelCaseCount = tsFiles.filter((f) => /^[a-z][a-zA-Z0-9]*\.ts$/.test(f)).length;
2807
+ const snakeCaseCount = tsFiles.filter((f) => /^[a-z][a-z0-9_]*\.ts$/.test(f) && f.includes("_")).length;
2808
+ const kebabCaseCount = tsFiles.filter((f) => /^[a-z][a-z0-9-]*\.ts$/.test(f) && f.includes("-")).length;
2809
+ const pascalCaseCount = tsFiles.filter((f) => /^[A-Z][a-zA-Z0-9]*\.ts$/.test(f)).length;
2810
+ const max = Math.max(camelCaseCount, snakeCaseCount, kebabCaseCount, pascalCaseCount);
2811
+ if (max === 0) return "unknown";
2812
+ if (camelCaseCount === max) return "camelCase";
2813
+ if (snakeCaseCount === max) return "snake_case";
2814
+ if (kebabCaseCount === max) return "kebab-case";
2815
+ if (pascalCaseCount === max) return "PascalCase";
2816
+ return "unknown";
2817
+ } catch {
2818
+ return "unknown";
2819
+ }
2820
+ };
2821
+ const convertNaming = (name, convention) => {
2822
+ const baseName = basename(name, extname(name));
2823
+ const ext = extname(name);
2824
+ switch (convention) {
2825
+ case "camelCase":
2826
+ return baseName.replace(/[-_]/g, "").replace(/([A-Z])/g, (match, p1, offset) => offset === 0 ? p1.toLowerCase() : p1) + ext;
2827
+ case "snake_case":
2828
+ return baseName.replace(/[-]/g, "_").replace(/([A-Z])/g, (match, p1, offset) => (offset === 0 ? "" : "_") + p1.toLowerCase()) + ext;
2829
+ case "kebab-case":
2830
+ return baseName.replace(/[_]/g, "-").replace(/([A-Z])/g, (match, p1, offset) => (offset === 0 ? "" : "-") + p1.toLowerCase()) + ext;
2831
+ case "PascalCase":
2832
+ return baseName.replace(/[-_]/g, "").replace(/^[a-z]/, (match) => match.toUpperCase()) + ext;
2833
+ default:
2834
+ return name;
2835
+ }
2836
+ };
2837
+ for (const unit of orderedUnits) {
2838
+ console.log(`Processing ${unit.kind} unit "${unit.id}" from file "${unit.file}"`);
2839
+ let sourceFile;
2840
+ let resolvedUnitFile;
2841
+ if (unit.file.includes("/")) {
2842
+ sourceFile = resolve(templateDir, unit.file);
2843
+ resolvedUnitFile = unit.file;
2844
+ } else {
2845
+ const folderPath = AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE[unit.kind];
2846
+ if (!folderPath) {
2847
+ conflicts.push({
2848
+ unit: { kind: unit.kind, id: unit.id },
2849
+ issue: `Unknown unit kind: ${unit.kind}`,
2850
+ sourceFile: unit.file,
2851
+ targetFile: "N/A"
2852
+ });
2853
+ continue;
2854
+ }
2855
+ resolvedUnitFile = `${folderPath}/${unit.file}`;
2856
+ sourceFile = resolve(templateDir, resolvedUnitFile);
2857
+ }
2858
+ if (!existsSync(sourceFile)) {
2859
+ conflicts.push({
2860
+ unit: { kind: unit.kind, id: unit.id },
2861
+ issue: `Source file not found: ${sourceFile}`,
2862
+ sourceFile: resolvedUnitFile,
2863
+ targetFile: "N/A"
2864
+ });
2865
+ continue;
2866
+ }
2867
+ const targetDir = dirname(resolvedUnitFile);
2868
+ const namingConvention = await analyzeNamingConvention(targetDir);
2869
+ console.log(`Detected naming convention in ${targetDir}: ${namingConvention}`);
2870
+ const hasExtension = extname(unit.id) !== "";
2871
+ const baseId = hasExtension ? basename(unit.id, extname(unit.id)) : unit.id;
2872
+ const fileExtension = extname(unit.file);
2873
+ const convertedFileName = namingConvention !== "unknown" ? convertNaming(baseId + fileExtension, namingConvention) : baseId + fileExtension;
2874
+ const targetFile = resolve(targetPath, targetDir, convertedFileName);
2875
+ if (existsSync(targetFile)) {
2876
+ const strategy = determineConflictStrategy();
2877
+ console.log(`File exists: ${convertedFileName}, using strategy: ${strategy}`);
2878
+ switch (strategy) {
2879
+ case "skip":
2880
+ conflicts.push({
2881
+ unit: { kind: unit.kind, id: unit.id },
2882
+ issue: `File exists - skipped: ${convertedFileName}`,
2883
+ sourceFile: unit.file,
2884
+ targetFile: `${targetDir}/${convertedFileName}`
2885
+ });
2886
+ console.log(`\u23ED\uFE0F Skipped ${unit.kind} "${unit.id}": file already exists`);
2887
+ continue;
2888
+ case "backup-and-replace":
2889
+ try {
2890
+ await backupAndReplaceFile(sourceFile, targetFile);
2891
+ copiedFiles.push({
2892
+ source: sourceFile,
2893
+ destination: targetFile,
2894
+ unit: { kind: unit.kind, id: unit.id }
2895
+ });
2896
+ console.log(
2897
+ `\u{1F504} Replaced ${unit.kind} "${unit.id}": ${unit.file} \u2192 ${convertedFileName} (backup created)`
2898
+ );
2899
+ continue;
2900
+ } catch (backupError) {
2901
+ conflicts.push({
2902
+ unit: { kind: unit.kind, id: unit.id },
2903
+ issue: `Failed to backup and replace: ${backupError instanceof Error ? backupError.message : String(backupError)}`,
2904
+ sourceFile: unit.file,
2905
+ targetFile: `${targetDir}/${convertedFileName}`
2906
+ });
2907
+ continue;
2908
+ }
2909
+ case "rename":
2910
+ try {
2911
+ const uniqueTargetFile = await renameAndCopyFile(sourceFile, targetFile);
2912
+ copiedFiles.push({
2913
+ source: sourceFile,
2914
+ destination: uniqueTargetFile,
2915
+ unit: { kind: unit.kind, id: unit.id }
2916
+ });
2917
+ console.log(`\u{1F4DD} Renamed ${unit.kind} "${unit.id}": ${unit.file} \u2192 ${basename(uniqueTargetFile)}`);
2918
+ continue;
2919
+ } catch (renameError) {
2920
+ conflicts.push({
2921
+ unit: { kind: unit.kind, id: unit.id },
2922
+ issue: `Failed to rename and copy: ${renameError instanceof Error ? renameError.message : String(renameError)}`,
2923
+ sourceFile: unit.file,
2924
+ targetFile: `${targetDir}/${convertedFileName}`
2925
+ });
2926
+ continue;
2927
+ }
2928
+ default:
2929
+ conflicts.push({
2930
+ unit: { kind: unit.kind, id: unit.id },
2931
+ issue: `Unknown conflict strategy: ${strategy}`,
2932
+ sourceFile: unit.file,
2933
+ targetFile: `${targetDir}/${convertedFileName}`
2934
+ });
2935
+ continue;
2936
+ }
2937
+ }
2938
+ await mkdir(dirname(targetFile), { recursive: true });
2939
+ try {
2940
+ await copyFile(sourceFile, targetFile);
2941
+ copiedFiles.push({
2942
+ source: sourceFile,
2943
+ destination: targetFile,
2944
+ unit: { kind: unit.kind, id: unit.id }
2945
+ });
2946
+ console.log(`\u2713 Copied ${unit.kind} "${unit.id}": ${unit.file} \u2192 ${convertedFileName}`);
2947
+ } catch (copyError) {
2948
+ conflicts.push({
2949
+ unit: { kind: unit.kind, id: unit.id },
2950
+ issue: `Failed to copy file: ${copyError instanceof Error ? copyError.message : String(copyError)}`,
2951
+ sourceFile: unit.file,
2952
+ targetFile: `${targetDir}/${convertedFileName}`
2953
+ });
2954
+ }
2955
+ }
2956
+ if (copiedFiles.length > 0) {
2957
+ try {
2958
+ const fileList = copiedFiles.map((f) => f.destination);
2959
+ const gitCommand = ["git", "add", ...fileList];
2960
+ await exec(gitCommand.join(" "), { cwd: targetPath });
2961
+ await exec(
2962
+ `git commit -m "feat(template): copy ${copiedFiles.length} files from ${slug}@${commitSha.substring(0, 7)}"`,
2963
+ { cwd: targetPath }
2964
+ );
2965
+ console.log(`\u2713 Committed ${copiedFiles.length} copied files`);
2966
+ } catch (commitError) {
2967
+ console.warn("Failed to commit copied files:", commitError);
2968
+ }
2969
+ }
2970
+ const message = `Programmatic file copy completed. Copied ${copiedFiles.length} files, ${conflicts.length} conflicts detected.`;
2971
+ console.log(message);
2972
+ return {
2973
+ success: true,
2974
+ copiedFiles,
2975
+ conflicts,
2976
+ message
2977
+ };
2978
+ } catch (error) {
2979
+ console.error("Programmatic file copy failed:", error);
2980
+ throw new Error(`Programmatic file copy failed: ${error instanceof Error ? error.message : String(error)}`);
2981
+ }
2982
+ }
2983
+ });
2984
+ var intelligentMergeStep = createStep({
2985
+ id: "intelligent-merge",
2986
+ description: "Use AgentBuilder to intelligently merge template files",
2987
+ inputSchema: z.object({
2988
+ conflicts: z.array(
2989
+ z.object({
2990
+ unit: z.object({
2991
+ kind: z.string(),
2992
+ id: z.string()
2993
+ }),
2994
+ issue: z.string(),
2995
+ sourceFile: z.string(),
2996
+ targetFile: z.string()
2997
+ })
2998
+ ),
2999
+ copiedFiles: z.array(
3000
+ z.object({
3001
+ source: z.string(),
3002
+ destination: z.string(),
3003
+ unit: z.object({
3004
+ kind: z.string(),
3005
+ id: z.string()
3006
+ })
3007
+ })
3008
+ ),
3009
+ templateDir: z.string(),
3010
+ commitSha: z.string(),
3011
+ slug: z.string(),
3012
+ targetPath: z.string().optional()
3013
+ }),
3014
+ outputSchema: z.object({
3015
+ success: z.boolean(),
3016
+ applied: z.boolean(),
3017
+ message: z.string(),
3018
+ conflictsResolved: z.array(
3019
+ z.object({
3020
+ unit: z.object({
3021
+ kind: z.string(),
3022
+ id: z.string()
3023
+ }),
3024
+ issue: z.string(),
3025
+ resolution: z.string()
3026
+ })
3027
+ ),
3028
+ error: z.string().optional(),
3029
+ branchName: z.string().optional()
3030
+ }),
3031
+ execute: async ({ inputData, runtimeContext }) => {
3032
+ console.log("Intelligent merge step starting...");
3033
+ const { conflicts, copiedFiles, commitSha, slug, templateDir } = inputData;
3034
+ const targetPath = inputData.targetPath || runtimeContext.get("targetPath") || process.cwd();
3035
+ const baseBranchName = `feat/install-template-${slug}`;
3036
+ try {
3037
+ let branchName = baseBranchName;
3038
+ try {
3039
+ await exec(`git checkout -b "${branchName}"`, { cwd: targetPath });
3040
+ console.log(`Created new branch: ${branchName}`);
3041
+ } catch (error) {
3042
+ const errorStr = error instanceof Error ? error.message : String(error);
3043
+ if (errorStr.includes("already exists")) {
3044
+ try {
3045
+ await exec(`git checkout "${branchName}"`, { cwd: targetPath });
3046
+ console.log(`Switched to existing branch: ${branchName}`);
3047
+ } catch {
3048
+ const timestamp = Date.now().toString().slice(-6);
3049
+ branchName = `${baseBranchName}-${timestamp}`;
3050
+ await exec(`git checkout -b "${branchName}"`, { cwd: targetPath });
3051
+ console.log(`Created unique branch: ${branchName}`);
3052
+ }
3053
+ } else {
3054
+ throw error;
3055
+ }
3056
+ }
3057
+ const copyFileTool = createTool({
3058
+ id: "copy-file",
3059
+ description: "Copy a file from template to target project (use only for edge cases - most files are already copied programmatically).",
3060
+ inputSchema: z.object({
3061
+ sourcePath: z.string().describe("Path to the source file relative to template directory"),
3062
+ destinationPath: z.string().describe("Path to the destination file relative to target project")
3063
+ }),
3064
+ outputSchema: z.object({
3065
+ success: z.boolean(),
3066
+ message: z.string(),
3067
+ error: z.string().optional()
3068
+ }),
3069
+ execute: async ({ context }) => {
3070
+ try {
3071
+ const { sourcePath, destinationPath } = context;
3072
+ const resolvedSourcePath = resolve(templateDir, sourcePath);
3073
+ const resolvedDestinationPath = resolve(targetPath, destinationPath);
3074
+ if (existsSync(resolvedSourcePath) && !existsSync(dirname(resolvedDestinationPath))) {
3075
+ await mkdir(dirname(resolvedDestinationPath), { recursive: true });
3076
+ }
3077
+ await copyFile(resolvedSourcePath, resolvedDestinationPath);
3078
+ return {
3079
+ success: true,
3080
+ message: `Successfully copied file from ${sourcePath} to ${destinationPath}`
3081
+ };
3082
+ } catch (error) {
3083
+ return {
3084
+ success: false,
3085
+ message: `Failed to copy file: ${error instanceof Error ? error.message : String(error)}`,
3086
+ error: error instanceof Error ? error.message : String(error)
3087
+ };
3088
+ }
3089
+ }
3090
+ });
3091
+ const agentBuilder = new AgentBuilder({
3092
+ projectPath: targetPath,
3093
+ mode: "template",
3094
+ model: openai("gpt-4o-mini"),
3095
+ instructions: `
3096
+ You are an expert at integrating Mastra template components into existing projects.
3097
+
3098
+ CRITICAL CONTEXT:
3099
+ - Files have been programmatically copied from template to target project
3100
+ - Your job is to handle integration issues, registration, and validation
3101
+
3102
+ FILES SUCCESSFULLY COPIED:
3103
+ ${JSON.stringify(copiedFiles, null, 2)}
3104
+
3105
+ CONFLICTS TO RESOLVE:
3106
+ ${JSON.stringify(conflicts, null, 2)}
3107
+
3108
+ CRITICAL INSTRUCTIONS:
3109
+ 1. **When committing changes**: NEVER add dependency/build directories. Use specific file paths with 'git add'
3110
+ 2. **Package management**: NO need to install packages (already handled by package merge step)
3111
+ 3. **Validation**: When validation fails due to import issues, check existing files and imports for correct naming conventions
3112
+ 4. **Variable vs file names**: A variable name might differ from file name (e.g., filename: ./downloaderTool.ts, export const fetcherTool(...))
3113
+ 5. **File copying**: Most files are already copied programmatically. Only use copyFile tool for edge cases where additional files are needed
3114
+
3115
+ KEY RESPONSIBILITIES:
3116
+ 1. Resolve any conflicts from the programmatic copy step
3117
+ 2. Register components in existing Mastra index file (agents, workflows, networks, mcp-servers)
3118
+ 3. DO NOT register tools in existing Mastra index file - tools should remain standalone
3119
+ 4. Fix import path issues in copied files
3120
+ 5. Ensure TypeScript imports and exports are correct
3121
+ 6. Validate integration works properly
3122
+ 7. Copy additional files ONLY if needed for conflict resolution or missing dependencies
3123
+
3124
+ MASTRA-SPECIFIC INTEGRATION:
3125
+ - Agents: Register in existing Mastra index file
3126
+ - Workflows: Register in existing Mastra index file
3127
+ - Networks: Register in existing Mastra index file
3128
+ - MCP servers: Register in existing Mastra index file
3129
+ - Tools: Copy to ${AgentBuilderDefaults.DEFAULT_FOLDER_STRUCTURE.tool} but DO NOT register in existing Mastra index file
3130
+
3131
+ EDGE CASE FILE COPYING:
3132
+ - IF a file for a resource does not exist in the target project AND was not programmatically copied, you can use copyFile tool
3133
+ - When taking files from template, ensure you get the right file name and path
3134
+ - Only copy files that are actually needed for the integration to work
3135
+
3136
+ NAMING CONVENTION GUIDANCE:
3137
+ When fixing imports or understanding naming patterns, use these examples:
3138
+
3139
+ **Import Path Patterns:**
3140
+ - camelCase files: import { myAgent } from './myAgent'
3141
+ - snake_case files: import { myAgent } from './my_agent'
3142
+ - kebab-case files: import { myAgent } from './my-agent'
3143
+ - PascalCase files: import { MyAgent } from './MyAgent'
3144
+
3145
+ **Naming Detection Examples:**
3146
+ - Files like "weatherAgent.ts", "chatAgent.ts" \u2192 use camelCase
3147
+ - Files like "weather_agent.ts", "chat_agent.ts" \u2192 use snake_case
3148
+ - Files like "weather-agent.ts", "chat-agent.ts" \u2192 use kebab-case
3149
+ - Files like "WeatherAgent.ts", "ChatAgent.ts" \u2192 use PascalCase
3150
+
3151
+ **Key Rule:** Keep variable/export names unchanged - only adapt file names and import paths
3152
+
3153
+ Template information:
3154
+ - Slug: ${slug}
3155
+ - Commit: ${commitSha.substring(0, 7)}
3156
+ - Branch: ${branchName}
3157
+ `,
3158
+ tools: {
3159
+ copyFile: copyFileTool
3160
+ }
3161
+ });
3162
+ const tasks = [];
3163
+ conflicts.forEach((conflict) => {
3164
+ tasks.push({
3165
+ id: `conflict-${conflict.unit.kind}-${conflict.unit.id}`,
3166
+ content: `Resolve conflict: ${conflict.issue}`,
3167
+ status: "pending",
3168
+ priority: "high",
3169
+ notes: `Unit: ${conflict.unit.kind}:${conflict.unit.id}, Issue: ${conflict.issue}, Source: ${conflict.sourceFile}, Target: ${conflict.targetFile}`
3170
+ });
3171
+ });
3172
+ const nonToolFiles = copiedFiles.filter((f) => f.unit.kind !== "tool");
3173
+ if (nonToolFiles.length > 0) {
3174
+ tasks.push({
3175
+ id: "register-components",
3176
+ content: `Register ${nonToolFiles.length} components in existing Mastra index file (src/mastra/index.ts)`,
3177
+ status: "pending",
3178
+ priority: "medium",
3179
+ dependencies: conflicts.length > 0 ? conflicts.map((c) => `conflict-${c.unit.kind}-${c.unit.id}`) : void 0,
3180
+ notes: `Components to register: ${nonToolFiles.map((f) => `${f.unit.kind}:${f.unit.id}`).join(", ")}`
3181
+ });
3182
+ }
3183
+ console.log(`Creating task list with ${tasks.length} tasks...`);
3184
+ await AgentBuilderDefaults.manageTaskList({ action: "create", tasks });
3185
+ await logGitState(targetPath, "before intelligent merge");
3186
+ const result = await agentBuilder.stream(`
3187
+ You need to work through a task list to complete the template integration.
3188
+
3189
+ CRITICAL INSTRUCTIONS:
3190
+
3191
+ **STEP 1: GET YOUR TASK LIST**
3192
+ 1. Use manageTaskList tool with action "list" to see all pending tasks
3193
+ 2. Work through tasks in dependency order (complete dependencies first)
3194
+
3195
+ **STEP 2: PROCESS EACH TASK SYSTEMATICALLY**
3196
+ For each task:
3197
+ 1. Use manageTaskList to mark the current task as 'in_progress'
3198
+ 2. Complete the task according to its requirements
3199
+ 3. Use manageTaskList to mark the task as 'completed' when done
3200
+ 4. Continue until all tasks are completed
3201
+
3202
+ **TASK TYPES AND REQUIREMENTS:**
3203
+
3204
+ **Conflict Resolution Tasks:**
3205
+ - Analyze the specific conflict and determine best resolution strategy
3206
+ - For file name conflicts: merge content or rename appropriately
3207
+ - For missing files: investigate and copy if needed
3208
+ - For other issues: apply appropriate fixes
3209
+
3210
+ **Component Registration Task:**
3211
+ - Update main Mastra instance file to register new components
3212
+ - Only register: agents, workflows, networks, mcp-servers
3213
+ - DO NOT register tools in main config
3214
+ - Ensure proper import paths and naming conventions
3215
+
3216
+ **COMMIT STRATEGY:**
3217
+ - After resolving conflicts: "feat(template): resolve conflicts for ${slug}@${commitSha.substring(0, 7)}"
3218
+ - After registration: "feat(template): register components from ${slug}@${commitSha.substring(0, 7)}"
3219
+
3220
+ **CRITICAL NOTES:**
3221
+ - Template source: ${templateDir}
3222
+ - Target project: ${targetPath}
3223
+ - Focus ONLY on conflict resolution and component registration
3224
+ - Use executeCommand for git commits after each task
3225
+ - DO NOT perform validation - that's handled by the dedicated validation step
3226
+
3227
+ Start by listing your tasks and work through them systematically!
3228
+ `);
3229
+ const actualResolutions = [];
3230
+ for await (const chunk of result.fullStream) {
3231
+ if (chunk.type === "step-finish" || chunk.type === "step-start") {
3232
+ console.log({
3233
+ type: chunk.type,
3234
+ msgId: chunk.messageId
3235
+ });
3236
+ } else {
3237
+ console.log(JSON.stringify(chunk, null, 2));
3238
+ if (chunk.type === "tool-result" && chunk.toolName === "manageTaskList") {
3239
+ try {
3240
+ const toolResult = chunk.result;
3241
+ if (toolResult.action === "update" && toolResult.status === "completed") {
3242
+ actualResolutions.push({
3243
+ taskId: toolResult.taskId || "",
3244
+ action: toolResult.action,
3245
+ status: toolResult.status,
3246
+ content: toolResult.content || "",
3247
+ notes: toolResult.notes
3248
+ });
3249
+ console.log(`\u{1F4CB} Task completed: ${toolResult.taskId} - ${toolResult.content}`);
3250
+ }
3251
+ } catch (parseError) {
3252
+ console.warn("Failed to parse task management result:", parseError);
3253
+ }
3254
+ }
3255
+ }
3256
+ }
3257
+ await logGitState(targetPath, "after intelligent merge");
3258
+ const conflictResolutions = conflicts.map((conflict) => {
3259
+ const taskId = `conflict-${conflict.unit.kind}-${conflict.unit.id}`;
3260
+ const actualResolution = actualResolutions.find((r) => r.taskId === taskId);
3261
+ if (actualResolution) {
3262
+ return {
3263
+ unit: conflict.unit,
3264
+ issue: conflict.issue,
3265
+ resolution: actualResolution.notes || actualResolution.content || `Completed: ${conflict.unit.kind} ${conflict.unit.id}`,
3266
+ actualWork: true
3267
+ };
3268
+ } else {
3269
+ return {
3270
+ unit: conflict.unit,
3271
+ issue: conflict.issue,
3272
+ resolution: `No specific resolution found for ${conflict.unit.kind} ${conflict.unit.id}`,
3273
+ actualWork: false
3274
+ };
3275
+ }
3276
+ });
3277
+ return {
3278
+ success: true,
3279
+ applied: true,
3280
+ branchName,
3281
+ message: `Successfully resolved ${conflicts.length} conflicts from template ${slug}`,
3282
+ conflictsResolved: conflictResolutions
3283
+ };
3284
+ } catch (error) {
3285
+ return {
3286
+ success: false,
3287
+ applied: false,
3288
+ branchName: baseBranchName,
3289
+ message: `Failed to resolve conflicts: ${error instanceof Error ? error.message : String(error)}`,
3290
+ conflictsResolved: [],
3291
+ error: error instanceof Error ? error.message : String(error)
3292
+ };
3293
+ }
3294
+ }
3295
+ });
3296
+ var validationAndFixStep = createStep({
3297
+ id: "validation-and-fix",
3298
+ description: "Validate the merged template code and fix any validation errors using a specialized agent",
3299
+ inputSchema: z.object({
3300
+ commitSha: z.string(),
3301
+ slug: z.string(),
3302
+ targetPath: z.string().optional(),
3303
+ templateDir: z.string(),
3304
+ orderedUnits: z.array(
3305
+ z.object({
3306
+ kind: z.string(),
3307
+ id: z.string(),
3308
+ file: z.string()
3309
+ })
3310
+ ),
3311
+ copiedFiles: z.array(
3312
+ z.object({
3313
+ source: z.string(),
3314
+ destination: z.string(),
3315
+ unit: z.object({
3316
+ kind: z.string(),
3317
+ id: z.string()
3318
+ })
3319
+ })
3320
+ ),
3321
+ conflictsResolved: z.array(
3322
+ z.object({
3323
+ unit: z.object({
3324
+ kind: z.string(),
3325
+ id: z.string()
3326
+ }),
3327
+ issue: z.string(),
3328
+ resolution: z.string()
3329
+ })
3330
+ ).optional(),
3331
+ maxIterations: z.number().optional().default(5)
3332
+ }),
3333
+ outputSchema: z.object({
3334
+ success: z.boolean(),
3335
+ applied: z.boolean(),
3336
+ message: z.string(),
3337
+ validationResults: z.object({
3338
+ valid: z.boolean(),
3339
+ errorsFixed: z.number(),
3340
+ remainingErrors: z.number()
3341
+ }),
3342
+ error: z.string().optional()
3343
+ }),
3344
+ execute: async ({ inputData, runtimeContext }) => {
3345
+ console.log("Validation and fix step starting...");
3346
+ const { commitSha, slug, orderedUnits, templateDir, copiedFiles, conflictsResolved, maxIterations = 5 } = inputData;
3347
+ const targetPath = inputData.targetPath || runtimeContext.get("targetPath") || process.cwd();
3348
+ const hasChanges = copiedFiles.length > 0 || conflictsResolved && conflictsResolved.length > 0;
3349
+ if (!hasChanges) {
3350
+ console.log("\u23ED\uFE0F Skipping validation - no files copied or conflicts resolved");
3351
+ return {
3352
+ success: true,
3353
+ applied: false,
3354
+ message: "No changes to validate - template already integrated or no conflicts resolved",
3355
+ validationResults: {
3356
+ valid: true,
3357
+ errorsFixed: 0,
3358
+ remainingErrors: 0
3359
+ }
3360
+ };
3361
+ }
3362
+ console.log(
3363
+ `\u{1F4CB} Changes detected: ${copiedFiles.length} files copied, ${conflictsResolved?.length || 0} conflicts resolved`
3364
+ );
3365
+ let currentIteration = 1;
3366
+ try {
3367
+ const allTools = await AgentBuilderDefaults.DEFAULT_TOOLS(targetPath, "template");
3368
+ const validationAgent = new Agent({
3369
+ name: "code-validator-fixer",
3370
+ description: "Specialized agent for validating and fixing template integration issues",
3371
+ instructions: `You are a code validation and fixing specialist. Your job is to:
3372
+
3373
+ 1. **Run comprehensive validation** using the validateCode tool to check for:
3374
+ - TypeScript compilation errors
3375
+ - ESLint issues
3376
+ - Import/export problems
3377
+ - Missing dependencies
3378
+
3379
+ 2. **Fix validation errors systematically**:
3380
+ - Use readFile to examine files with errors
3381
+ - Use multiEdit to fix issues like missing imports, incorrect paths, syntax errors
3382
+ - Use listDirectory to understand project structure when fixing import paths
3383
+ - Update file contents to resolve TypeScript and linting issues
3384
+
3385
+ 3. **Re-validate after fixes** to ensure all issues are resolved
3386
+
3387
+ 4. **Focus on template integration issues**:
3388
+ - Files were copied with new names based on unit IDs
3389
+ - Original template imports may reference old filenames
3390
+ - Missing imports in index files
3391
+ - Incorrect file paths in imports
3392
+ - Type mismatches after integration
3393
+ - Missing exports in barrel files
3394
+ - Use the COPIED FILES mapping below to fix import paths
3395
+
3396
+ CRITICAL: Always validate the entire project first to get a complete picture of issues, then fix them systematically, and re-validate to confirm fixes worked.
3397
+
3398
+ CRITICAL IMPORT PATH RESOLUTION:
3399
+ The following files were copied from template with new names:
3400
+ ${JSON.stringify(copiedFiles, null, 2)}
3401
+
3402
+ When fixing import errors:
3403
+ 1. Check if the missing module corresponds to a copied file
3404
+ 2. Use listDirectory to verify actual filenames in target directories
3405
+ 3. Update import paths to match the actual copied filenames
3406
+ 4. Ensure exported variable names match what's being imported
3407
+
3408
+ EXAMPLE: If error shows "Cannot find module './tools/download-csv-tool'" but a file was copied as "csv-fetcher-tool.ts", update the import to "./tools/csv-fetcher-tool"
3409
+
3410
+ ${conflictsResolved ? `CONFLICTS RESOLVED BY INTELLIGENT MERGE:
3411
+ ${JSON.stringify(conflictsResolved, null, 2)}
3412
+ ` : ""}
3413
+
3414
+ INTEGRATED UNITS:
3415
+ ${JSON.stringify(orderedUnits, null, 2)}
3416
+
3417
+ Be thorough and methodical. Always use listDirectory to verify actual file existence before fixing imports.`,
3418
+ model: openai("gpt-4o-mini"),
3419
+ tools: {
3420
+ validateCode: allTools.validateCode,
3421
+ readFile: allTools.readFile,
3422
+ multiEdit: allTools.multiEdit,
3423
+ listDirectory: allTools.listDirectory,
3424
+ executeCommand: allTools.executeCommand
3425
+ }
3426
+ });
3427
+ console.log("Starting validation and fix agent with internal loop...");
3428
+ let validationResults = {
3429
+ valid: false,
3430
+ errorsFixed: 0,
3431
+ remainingErrors: 1,
3432
+ // Start with 1 to enter the loop
3433
+ iteration: currentIteration
3434
+ };
3435
+ while (validationResults.remainingErrors > 0 && currentIteration <= maxIterations) {
3436
+ console.log(`
3437
+ === Validation Iteration ${currentIteration} ===`);
3438
+ const iterationPrompt = currentIteration === 1 ? `Please validate the template integration and fix any errors found in the project at ${targetPath}. The template "${slug}" (${commitSha.substring(0, 7)}) was just integrated and may have validation issues that need fixing.
3439
+
3440
+ Start by running validateCode with all validation types to get a complete picture of any issues, then systematically fix them.` : `Continue validation and fixing for the template integration at ${targetPath}. This is iteration ${currentIteration} of validation.
3441
+
3442
+ Previous iterations may have fixed some issues, so start by re-running validateCode to see the current state, then fix any remaining issues.`;
3443
+ const result = await validationAgent.stream(iterationPrompt, {
3444
+ experimental_output: z.object({ success: z.boolean() })
3445
+ });
3446
+ let iterationErrors = 0;
3447
+ let previousErrors = validationResults.remainingErrors;
3448
+ for await (const chunk of result.fullStream) {
3449
+ if (chunk.type === "step-finish" || chunk.type === "step-start") {
3450
+ console.log({
3451
+ type: chunk.type,
3452
+ msgId: chunk.messageId,
3453
+ iteration: currentIteration
3454
+ });
3455
+ } else {
3456
+ console.log(JSON.stringify(chunk, null, 2));
3457
+ }
3458
+ if (chunk.type === "tool-result") {
3459
+ if (chunk.toolName === "validateCode") {
3460
+ const toolResult = chunk.result;
3461
+ if (toolResult?.summary) {
3462
+ iterationErrors = toolResult.summary.totalErrors || 0;
3463
+ console.log(`Iteration ${currentIteration}: Found ${iterationErrors} errors`);
3464
+ }
3465
+ }
3466
+ }
3467
+ }
3468
+ validationResults.remainingErrors = iterationErrors;
3469
+ validationResults.errorsFixed += Math.max(0, previousErrors - iterationErrors);
3470
+ validationResults.valid = iterationErrors === 0;
3471
+ validationResults.iteration = currentIteration;
3472
+ console.log(`Iteration ${currentIteration} complete: ${iterationErrors} errors remaining`);
3473
+ if (iterationErrors === 0) {
3474
+ console.log(`\u2705 All validation issues resolved in ${currentIteration} iterations!`);
3475
+ break;
3476
+ } else if (currentIteration >= maxIterations) {
3477
+ console.log(`\u26A0\uFE0F Max iterations (${maxIterations}) reached. ${iterationErrors} errors still remaining.`);
3478
+ break;
3479
+ }
3480
+ currentIteration++;
3481
+ }
3482
+ try {
3483
+ await exec(
3484
+ `git add . && git commit -m "fix(template): resolve validation errors for ${slug}@${commitSha.substring(0, 7)}" || true`,
3485
+ {
3486
+ cwd: targetPath
3487
+ }
3488
+ );
3489
+ } catch (commitError) {
3490
+ console.warn("Failed to commit validation fixes:", commitError);
3491
+ }
3492
+ return {
3493
+ success: true,
3494
+ applied: true,
3495
+ message: `Validation completed in ${currentIteration} iteration${currentIteration > 1 ? "s" : ""}. ${validationResults.valid ? "All issues resolved!" : `${validationResults.remainingErrors} issues remaining`}`,
3496
+ validationResults: {
3497
+ valid: validationResults.valid,
3498
+ errorsFixed: validationResults.errorsFixed,
3499
+ remainingErrors: validationResults.remainingErrors
3500
+ }
3501
+ };
3502
+ } catch (error) {
3503
+ console.error("Validation and fix failed:", error);
3504
+ return {
3505
+ success: false,
3506
+ applied: false,
3507
+ message: `Validation and fix failed: ${error instanceof Error ? error.message : String(error)}`,
3508
+ validationResults: {
3509
+ valid: false,
3510
+ errorsFixed: 0,
3511
+ remainingErrors: -1
3512
+ },
3513
+ error: error instanceof Error ? error.message : String(error)
3514
+ };
3515
+ } finally {
3516
+ try {
3517
+ await rm(templateDir, { recursive: true, force: true });
3518
+ console.log(`\u2713 Cleaned up template directory: ${templateDir}`);
3519
+ } catch (cleanupError) {
3520
+ console.warn("Failed to cleanup template directory:", cleanupError);
3521
+ }
3522
+ }
3523
+ }
3524
+ });
3525
+ var mergeTemplateWorkflow = createWorkflow({
3526
+ id: "merge-template",
3527
+ description: "Merges a Mastra template repository into the current project using intelligent AgentBuilder-powered merging",
3528
+ inputSchema: MergeInputSchema,
3529
+ outputSchema: ApplyResultSchema,
3530
+ steps: [
3531
+ cloneTemplateStep,
3532
+ analyzePackageStep,
3533
+ discoverUnitsStep,
3534
+ orderUnitsStep,
3535
+ packageMergeStep,
3536
+ flatInstallStep,
3537
+ programmaticFileCopyStep,
3538
+ intelligentMergeStep,
3539
+ validationAndFixStep
3540
+ ]
3541
+ }).then(cloneTemplateStep).parallel([analyzePackageStep, discoverUnitsStep]).map(async ({ getStepResult }) => {
3542
+ const discoverResult = getStepResult(discoverUnitsStep);
3543
+ return discoverResult;
3544
+ }).then(orderUnitsStep).map(async ({ getStepResult, getInitData }) => {
3545
+ const cloneResult = getStepResult(cloneTemplateStep);
3546
+ const packageResult = getStepResult(analyzePackageStep);
3547
+ const initData = getInitData();
3548
+ return {
3549
+ commitSha: cloneResult.commitSha,
3550
+ slug: cloneResult.slug,
3551
+ targetPath: initData.targetPath,
3552
+ packageInfo: packageResult
3553
+ };
3554
+ }).then(packageMergeStep).map(async ({ getInitData }) => {
3555
+ const initData = getInitData();
3556
+ return {
3557
+ targetPath: initData.targetPath
3558
+ };
3559
+ }).then(flatInstallStep).map(async ({ getStepResult, getInitData }) => {
3560
+ const cloneResult = getStepResult(cloneTemplateStep);
3561
+ const orderResult = getStepResult(orderUnitsStep);
3562
+ const initData = getInitData();
3563
+ return {
3564
+ orderedUnits: orderResult.orderedUnits,
3565
+ templateDir: cloneResult.templateDir,
3566
+ commitSha: cloneResult.commitSha,
3567
+ slug: cloneResult.slug,
3568
+ targetPath: initData.targetPath
3569
+ };
3570
+ }).then(programmaticFileCopyStep).map(async ({ getStepResult, getInitData }) => {
3571
+ const copyResult = getStepResult(programmaticFileCopyStep);
3572
+ const cloneResult = getStepResult(cloneTemplateStep);
3573
+ const initData = getInitData();
3574
+ return {
3575
+ conflicts: copyResult.conflicts,
3576
+ copiedFiles: copyResult.copiedFiles,
3577
+ commitSha: cloneResult.commitSha,
3578
+ slug: cloneResult.slug,
3579
+ targetPath: initData.targetPath,
3580
+ templateDir: cloneResult.templateDir
3581
+ };
3582
+ }).then(intelligentMergeStep).map(async ({ getStepResult, getInitData }) => {
3583
+ const cloneResult = getStepResult(cloneTemplateStep);
3584
+ const orderResult = getStepResult(orderUnitsStep);
3585
+ const copyResult = getStepResult(programmaticFileCopyStep);
3586
+ const mergeResult = getStepResult(intelligentMergeStep);
3587
+ const initData = getInitData();
3588
+ return {
3589
+ commitSha: cloneResult.commitSha,
3590
+ slug: cloneResult.slug,
3591
+ targetPath: initData.targetPath,
3592
+ templateDir: cloneResult.templateDir,
3593
+ orderedUnits: orderResult.orderedUnits,
3594
+ copiedFiles: copyResult.copiedFiles,
3595
+ conflictsResolved: mergeResult.conflictsResolved
3596
+ };
3597
+ }).then(validationAndFixStep).map(async ({ getStepResult, getInitData }) => {
3598
+ const validationResult = getStepResult(validationAndFixStep);
3599
+ const intelligentMergeResult = getStepResult(intelligentMergeStep);
3600
+ const copyResult = getStepResult(programmaticFileCopyStep);
3601
+ const cloneResult = getStepResult(cloneTemplateStep);
3602
+ const initData = getInitData();
3603
+ const branchName = intelligentMergeResult.branchName || `feat/install-template-${cloneResult.slug || initData.slug}`;
3604
+ const allErrors = [copyResult.error, intelligentMergeResult.error, validationResult.error].filter(Boolean);
3605
+ const overallSuccess = copyResult.success !== false && intelligentMergeResult.success !== false && validationResult.success;
3606
+ const messages = [];
3607
+ if (copyResult.copiedFiles?.length > 0) {
3608
+ messages.push(`${copyResult.copiedFiles.length} files copied`);
3609
+ }
3610
+ if (copyResult.conflicts?.length > 0) {
3611
+ messages.push(`${copyResult.conflicts.length} conflicts skipped`);
3612
+ }
3613
+ if (intelligentMergeResult.conflictsResolved?.length > 0) {
3614
+ messages.push(`${intelligentMergeResult.conflictsResolved.length} conflicts resolved`);
3615
+ }
3616
+ if (validationResult.validationResults?.errorsFixed > 0) {
3617
+ messages.push(`${validationResult.validationResults.errorsFixed} validation errors fixed`);
3618
+ }
3619
+ const comprehensiveMessage = messages.length > 0 ? `Template merge completed: ${messages.join(", ")}` : validationResult.message || "Template merge completed";
3620
+ return {
3621
+ success: overallSuccess,
3622
+ applied: validationResult.applied || copyResult.copiedFiles?.length > 0 || false,
3623
+ message: comprehensiveMessage,
3624
+ validationResults: validationResult.validationResults,
3625
+ error: allErrors.length > 0 ? allErrors.join("; ") : void 0,
3626
+ errors: allErrors.length > 0 ? allErrors : void 0,
3627
+ branchName,
3628
+ // Additional debugging info
3629
+ stepResults: {
3630
+ copySuccess: copyResult.success,
3631
+ mergeSuccess: intelligentMergeResult.success,
3632
+ validationSuccess: validationResult.success,
3633
+ filesCopied: copyResult.copiedFiles?.length || 0,
3634
+ conflictsSkipped: copyResult.conflicts?.length || 0,
3635
+ conflictsResolved: intelligentMergeResult.conflictsResolved?.length || 0
3636
+ }
3637
+ };
3638
+ }).commit();
3639
+ var determineConflictStrategy = (_unit, _targetFile) => {
3640
+ return "skip";
3641
+ };
3642
+
3643
+ // src/index.ts
3644
+ var AgentBuilder = class extends Agent {
3645
+ builderConfig;
3646
+ /**
3647
+ * Private constructor - use AgentBuilder.create() instead
3648
+ */
3649
+ constructor(config) {
3650
+ const additionalInstructions = config.instructions ? `## Priority Instructions
3651
+
3652
+ ${config.instructions}` : "";
3653
+ const combinedInstructions = additionalInstructions + AgentBuilderDefaults.DEFAULT_INSTRUCTIONS(config.projectPath);
3654
+ const agentConfig = {
3655
+ name: "agent-builder",
3656
+ description: "An AI agent specialized in generating Mastra agents, tools, and workflows from natural language requirements.",
3657
+ instructions: combinedInstructions,
3658
+ model: config.model,
3659
+ tools: async () => {
3660
+ return {
3661
+ ...await AgentBuilderDefaults.DEFAULT_TOOLS(config.projectPath, config.mode),
3662
+ ...config.tools || {}
3663
+ };
3664
+ },
3665
+ workflows: {
3666
+ "merge-template": mergeTemplateWorkflow
3667
+ },
3668
+ memory: new Memory({
3669
+ options: AgentBuilderDefaults.DEFAULT_MEMORY_CONFIG,
3670
+ processors: [
3671
+ new WriteToDiskProcessor({ prefix: "before-filter" }),
3672
+ new ToolSummaryProcessor({ summaryModel: config.summaryModel || config.model }),
3673
+ new TokenLimiter(1e5),
3674
+ new WriteToDiskProcessor({ prefix: "after-filter" })
3675
+ ]
3676
+ })
3677
+ };
3678
+ super(agentConfig);
3679
+ this.builderConfig = config;
3680
+ }
3681
+ /**
3682
+ * Enhanced generate method with AgentBuilder-specific configuration
3683
+ * Overrides the base Agent generate method to provide additional project context
3684
+ */
3685
+ generate = async (messages, generateOptions = {}) => {
3686
+ const { ...baseOptions } = generateOptions;
3687
+ const originalInstructions = await this.getInstructions({ runtimeContext: generateOptions?.runtimeContext });
3688
+ const additionalInstructions = baseOptions.instructions;
3689
+ let enhancedInstructions = originalInstructions;
3690
+ if (additionalInstructions) {
3691
+ enhancedInstructions = `${originalInstructions}
3692
+
3693
+ ${additionalInstructions}`;
3694
+ }
3695
+ const enhancedContext = [...baseOptions.context || []];
3696
+ const enhancedOptions = {
3697
+ ...baseOptions,
3698
+ maxSteps: 300,
3699
+ // Higher default for code generation
3700
+ temperature: 0.3,
3701
+ // Lower temperature for more consistent code generation
3702
+ instructions: enhancedInstructions,
3703
+ context: enhancedContext
3704
+ };
3705
+ this.logger.debug(`[AgentBuilder:${this.name}] Starting generation with enhanced context`, {
3706
+ projectPath: this.builderConfig.projectPath
3707
+ });
3708
+ return super.generate(messages, enhancedOptions);
3709
+ };
3710
+ /**
3711
+ * Enhanced stream method with AgentBuilder-specific configuration
3712
+ * Overrides the base Agent stream method to provide additional project context
3713
+ */
3714
+ stream = async (messages, streamOptions = {}) => {
3715
+ const { ...baseOptions } = streamOptions;
3716
+ const originalInstructions = await this.getInstructions({ runtimeContext: streamOptions?.runtimeContext });
3717
+ const additionalInstructions = baseOptions.instructions;
3718
+ let enhancedInstructions = originalInstructions;
3719
+ if (additionalInstructions) {
3720
+ enhancedInstructions = `${originalInstructions}
3721
+
3722
+ ${additionalInstructions}`;
3723
+ }
3724
+ const enhancedContext = [...baseOptions.context || []];
3725
+ const enhancedOptions = {
3726
+ ...baseOptions,
3727
+ maxSteps: 100,
3728
+ // Higher default for code generation
3729
+ temperature: 0.3,
3730
+ // Lower temperature for more consistent code generation
3731
+ instructions: enhancedInstructions,
3732
+ context: enhancedContext
3733
+ };
3734
+ this.logger.debug(`[AgentBuilder:${this.name}] Starting streaming with enhanced context`, {
3735
+ projectPath: this.builderConfig.projectPath
3736
+ });
3737
+ return super.stream(messages, enhancedOptions);
3738
+ };
3739
+ /**
3740
+ * Generate a Mastra agent from natural language requirements
3741
+ */
3742
+ async generateAgent(requirements, options) {
3743
+ const prompt = `Generate a Mastra agent based on these requirements: ${requirements}
3744
+
3745
+ Please provide:
3746
+ 1. Complete agent code with proper configuration
3747
+ 2. Any custom tools the agent needs
3748
+ 3. Example usage
3749
+ 4. Testing recommendations
3750
+
3751
+ ${options?.outputFormat === "explanation" ? "Focus on explaining the approach and architecture." : ""}
3752
+ ${options?.outputFormat === "code" ? "Focus on providing complete, working code." : ""}
3753
+ ${!options?.outputFormat || options.outputFormat === "both" ? "Provide both explanation and complete code." : ""}`;
3754
+ return this.generate(prompt, {
3755
+ runtimeContext: options?.runtimeContext
3756
+ });
3757
+ }
3758
+ /**
3759
+ * Get the default configuration for AgentBuilder
3760
+ */
3761
+ static defaultConfig(projectPath) {
3762
+ return {
3763
+ instructions: AgentBuilderDefaults.DEFAULT_INSTRUCTIONS(projectPath),
3764
+ memoryConfig: AgentBuilderDefaults.DEFAULT_MEMORY_CONFIG,
3765
+ tools: AgentBuilderDefaults.DEFAULT_TOOLS
3766
+ };
3767
+ }
3768
+ };
3769
+
3770
+ export { AgentBuilder };