mastracode 0.4.0 → 0.5.0

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 (155) hide show
  1. package/CHANGELOG.md +328 -0
  2. package/LICENSE.md +15 -0
  3. package/README.md +68 -29
  4. package/dist/agents/memory.d.ts.map +1 -1
  5. package/dist/agents/model.d.ts +17 -6
  6. package/dist/agents/model.d.ts.map +1 -1
  7. package/dist/agents/prompts/index.d.ts.map +1 -1
  8. package/dist/agents/prompts/tool-guidance.d.ts +2 -0
  9. package/dist/agents/prompts/tool-guidance.d.ts.map +1 -1
  10. package/dist/agents/subagents/audit-tests.d.ts +0 -7
  11. package/dist/agents/subagents/audit-tests.d.ts.map +1 -1
  12. package/dist/agents/subagents/execute.d.ts +0 -7
  13. package/dist/agents/subagents/execute.d.ts.map +1 -1
  14. package/dist/agents/subagents/explore.d.ts +0 -7
  15. package/dist/agents/subagents/explore.d.ts.map +1 -1
  16. package/dist/agents/subagents/index.d.ts.map +1 -1
  17. package/dist/agents/subagents/plan.d.ts +0 -7
  18. package/dist/agents/subagents/plan.d.ts.map +1 -1
  19. package/dist/agents/tools.d.ts +3 -1
  20. package/dist/agents/tools.d.ts.map +1 -1
  21. package/dist/agents/workspace.d.ts +4 -1
  22. package/dist/agents/workspace.d.ts.map +1 -1
  23. package/dist/{chunk-K4WJUBEC.cjs → chunk-AJEYT7X3.cjs} +763 -429
  24. package/dist/chunk-AJEYT7X3.cjs.map +1 -0
  25. package/dist/{chunk-U5A7TFNT.js → chunk-CC2724NI.js} +46 -10
  26. package/dist/chunk-CC2724NI.js.map +1 -0
  27. package/dist/{chunk-REVOTI2T.js → chunk-JI4M5525.js} +740 -412
  28. package/dist/chunk-JI4M5525.js.map +1 -0
  29. package/dist/{chunk-Z4QRXVST.cjs → chunk-MBPGUMYQ.cjs} +325 -251
  30. package/dist/chunk-MBPGUMYQ.cjs.map +1 -0
  31. package/dist/{chunk-MT3YCFCC.cjs → chunk-OEDRHUU5.cjs} +47 -9
  32. package/dist/chunk-OEDRHUU5.cjs.map +1 -0
  33. package/dist/{chunk-M5LKPQB4.js → chunk-WKPHD54B.js} +283 -209
  34. package/dist/chunk-WKPHD54B.js.map +1 -0
  35. package/dist/{chunk-C4X3C2DL.cjs → chunk-XVYUS2EA.cjs} +2213 -1035
  36. package/dist/chunk-XVYUS2EA.cjs.map +1 -0
  37. package/dist/{chunk-X3BGE7CL.js → chunk-YQNZ7DHQ.js} +1788 -613
  38. package/dist/chunk-YQNZ7DHQ.js.map +1 -0
  39. package/dist/cli.cjs +79 -31
  40. package/dist/cli.cjs.map +1 -1
  41. package/dist/cli.js +71 -23
  42. package/dist/cli.js.map +1 -1
  43. package/dist/clipboard/index.d.ts +5 -0
  44. package/dist/clipboard/index.d.ts.map +1 -1
  45. package/dist/error-classification.d.ts +10 -0
  46. package/dist/error-classification.d.ts.map +1 -0
  47. package/dist/index.cjs +2 -2
  48. package/dist/index.d.ts +10 -3
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +1 -1
  51. package/dist/mcp/config.d.ts +8 -0
  52. package/dist/mcp/config.d.ts.map +1 -1
  53. package/dist/mcp/index.d.ts +1 -1
  54. package/dist/mcp/index.d.ts.map +1 -1
  55. package/dist/mcp/manager.d.ts +4 -2
  56. package/dist/mcp/manager.d.ts.map +1 -1
  57. package/dist/mcp/types.d.ts +30 -3
  58. package/dist/mcp/types.d.ts.map +1 -1
  59. package/dist/onboarding/onboarding-inline.d.ts +2 -0
  60. package/dist/onboarding/onboarding-inline.d.ts.map +1 -1
  61. package/dist/onboarding/packs.d.ts +1 -0
  62. package/dist/onboarding/packs.d.ts.map +1 -1
  63. package/dist/onboarding/settings.d.ts +37 -2
  64. package/dist/onboarding/settings.d.ts.map +1 -1
  65. package/dist/permissions-S3LGXIDB.js +3 -0
  66. package/dist/{permissions-CVXKYIWR.js.map → permissions-S3LGXIDB.js.map} +1 -1
  67. package/dist/permissions-VGABAVGD.cjs +40 -0
  68. package/dist/{permissions-2HIUSRQN.cjs.map → permissions-VGABAVGD.cjs.map} +1 -1
  69. package/dist/permissions.d.ts.map +1 -1
  70. package/dist/providers/claude-max.d.ts +13 -0
  71. package/dist/providers/claude-max.d.ts.map +1 -1
  72. package/dist/providers/openai-codex.d.ts +1 -0
  73. package/dist/providers/openai-codex.d.ts.map +1 -1
  74. package/dist/tool-names.d.ts +68 -0
  75. package/dist/tool-names.d.ts.map +1 -0
  76. package/dist/tools/ast-smart-edit.d.ts +77 -5
  77. package/dist/tools/ast-smart-edit.d.ts.map +1 -1
  78. package/dist/tools/index.d.ts +2 -2
  79. package/dist/tools/index.d.ts.map +1 -1
  80. package/dist/tools/string-replace-lsp.d.ts +15 -0
  81. package/dist/tools/string-replace-lsp.d.ts.map +1 -1
  82. package/dist/tools/subagent.d.ts.map +1 -1
  83. package/dist/tools/utils.d.ts +4 -2
  84. package/dist/tools/utils.d.ts.map +1 -1
  85. package/dist/tui/command-dispatch.d.ts.map +1 -1
  86. package/dist/tui/commands/clone.d.ts +29 -0
  87. package/dist/tui/commands/clone.d.ts.map +1 -0
  88. package/dist/tui/commands/custom-providers.d.ts +8 -0
  89. package/dist/tui/commands/custom-providers.d.ts.map +1 -0
  90. package/dist/tui/commands/index.d.ts +3 -1
  91. package/dist/tui/commands/index.d.ts.map +1 -1
  92. package/dist/tui/commands/mcp.d.ts.map +1 -1
  93. package/dist/tui/commands/models-pack.d.ts +4 -0
  94. package/dist/tui/commands/models-pack.d.ts.map +1 -1
  95. package/dist/tui/commands/om.d.ts.map +1 -1
  96. package/dist/tui/commands/report-issue.d.ts +3 -0
  97. package/dist/tui/commands/report-issue.d.ts.map +1 -0
  98. package/dist/tui/commands/resource.d.ts.map +1 -1
  99. package/dist/tui/commands/settings.d.ts.map +1 -1
  100. package/dist/tui/commands/threads.d.ts +1 -0
  101. package/dist/tui/commands/threads.d.ts.map +1 -1
  102. package/dist/tui/components/ask-question-inline.d.ts +3 -0
  103. package/dist/tui/components/ask-question-inline.d.ts.map +1 -1
  104. package/dist/tui/components/custom-editor.d.ts +1 -1
  105. package/dist/tui/components/custom-editor.d.ts.map +1 -1
  106. package/dist/tui/components/help-overlay.d.ts.map +1 -1
  107. package/dist/tui/components/plan-approval-inline.d.ts.map +1 -1
  108. package/dist/tui/components/settings.d.ts +2 -0
  109. package/dist/tui/components/settings.d.ts.map +1 -1
  110. package/dist/tui/components/subagent-execution.d.ts +6 -1
  111. package/dist/tui/components/subagent-execution.d.ts.map +1 -1
  112. package/dist/tui/components/thread-selector.d.ts +6 -0
  113. package/dist/tui/components/thread-selector.d.ts.map +1 -1
  114. package/dist/tui/components/tool-execution-enhanced.d.ts +1 -0
  115. package/dist/tui/components/tool-execution-enhanced.d.ts.map +1 -1
  116. package/dist/tui/components/tool-validation-error.d.ts.map +1 -1
  117. package/dist/tui/handlers/message.d.ts.map +1 -1
  118. package/dist/tui/handlers/prompts.d.ts +6 -0
  119. package/dist/tui/handlers/prompts.d.ts.map +1 -1
  120. package/dist/tui/handlers/subagent.d.ts.map +1 -1
  121. package/dist/tui/mastra-tui.d.ts +14 -5
  122. package/dist/tui/mastra-tui.d.ts.map +1 -1
  123. package/dist/tui/render-messages.d.ts.map +1 -1
  124. package/dist/tui/setup.d.ts.map +1 -1
  125. package/dist/tui/state.d.ts +4 -5
  126. package/dist/tui/state.d.ts.map +1 -1
  127. package/dist/tui.cjs +19 -19
  128. package/dist/tui.js +2 -2
  129. package/dist/utils/debug-log.d.ts +12 -0
  130. package/dist/utils/debug-log.d.ts.map +1 -0
  131. package/dist/utils/plans.d.ts +7 -0
  132. package/dist/utils/plans.d.ts.map +1 -0
  133. package/dist/utils/update-check.d.ts +40 -0
  134. package/dist/utils/update-check.d.ts.map +1 -0
  135. package/package.json +8 -8
  136. package/dist/chunk-C4X3C2DL.cjs.map +0 -1
  137. package/dist/chunk-K4WJUBEC.cjs.map +0 -1
  138. package/dist/chunk-M5LKPQB4.js.map +0 -1
  139. package/dist/chunk-MT3YCFCC.cjs.map +0 -1
  140. package/dist/chunk-REVOTI2T.js.map +0 -1
  141. package/dist/chunk-U5A7TFNT.js.map +0 -1
  142. package/dist/chunk-X3BGE7CL.js.map +0 -1
  143. package/dist/chunk-Z4QRXVST.cjs.map +0 -1
  144. package/dist/docs/SKILL.md +0 -30
  145. package/dist/docs/assets/SOURCE_MAP.json +0 -11
  146. package/dist/docs/references/docs-mastra-code-configuration.md +0 -299
  147. package/dist/docs/references/docs-mastra-code-customization.md +0 -228
  148. package/dist/docs/references/docs-mastra-code-modes.md +0 -104
  149. package/dist/docs/references/docs-mastra-code-overview.md +0 -135
  150. package/dist/docs/references/docs-mastra-code-tools.md +0 -229
  151. package/dist/docs/references/reference-mastra-code-createMastraCode.md +0 -108
  152. package/dist/permissions-2HIUSRQN.cjs +0 -40
  153. package/dist/permissions-CVXKYIWR.js +0 -3
  154. package/dist/tui/commands/models.d.ts +0 -3
  155. package/dist/tui/commands/models.d.ts.map +0 -1
@@ -1,23 +1,21 @@
1
- import { setAuthStorage, setAuthStorage2, loadSettings, getDynamicModel, createViewTool, createGrepTool, createGlobTool, createExecuteCommandTool, createWriteFileTool, getAvailableModePacks, getAvailableOmPacks, resolveModelDefaults, resolveOmModel, mastra, exploreSubagent, planSubagent, stringReplaceLspTool, executeSubagent, releaseThreadLock, acquireThreadLock, resolveModel, astSmartEditTool, hasTavilyKey, createWebSearchTool, createWebExtractTool, requestSandboxAccessTool } from './chunk-REVOTI2T.js';
1
+ import { setAuthStorage, setAuthStorage2, loadSettings, getDynamicModel, createViewTool, createGrepTool, createGlobTool, createExecuteCommandTool, createWriteFileTool, createStringReplaceLspTool, getAvailableModePacks, getAvailableOmPacks, resolveModelDefaults, resolveOmModel, mastra, exploreSubagent, planSubagent, executeSubagent, releaseThreadLock, acquireThreadLock, getDynamicWorkspace, resolveModel, getCustomProviderId, toCustomProviderModelId, saveSettings, hasTavilyKey, createWebSearchTool, createWebExtractTool, requestSandboxAccessTool } from './chunk-JI4M5525.js';
2
2
  import { AuthStorage, detectProject, getResourceIdOverride, getStorageConfig, getCurrentGitBranch, getOmScope, getDatabasePath } from './chunk-SM3QCOA7.js';
3
- import { getToolCategory } from './chunk-U5A7TFNT.js';
4
- import { Mastra } from '@mastra/core';
3
+ import { getToolCategory, MC_TOOLS } from './chunk-CC2724NI.js';
5
4
  import { Agent } from '@mastra/core/agent';
6
5
  import { taskCheckTool, taskWriteTool, Harness } from '@mastra/core/harness';
7
- import { noopLogger } from '@mastra/core/logger';
8
- import * as fs4 from 'fs';
9
- import fs4__default, { readFileSync, existsSync } from 'fs';
6
+ import { PROVIDER_REGISTRY, ModelsDevGateway, NetlifyGateway } from '@mastra/core/llm';
7
+ import * as fs3 from 'fs';
8
+ import fs3__default, { readFileSync, existsSync } from 'fs';
10
9
  import * as os from 'os';
11
10
  import os__default, { homedir } from 'os';
12
- import * as path from 'path';
13
- import path__default, { join } from 'path';
11
+ import * as path3 from 'path';
12
+ import path3__default, { join } from 'path';
14
13
  import { Memory } from '@mastra/memory';
15
14
  import { createAnthropic } from '@ai-sdk/anthropic';
16
- import { Workspace, LocalSandbox, LocalFilesystem } from '@mastra/core/workspace';
15
+ import { createOpenAI } from '@ai-sdk/openai';
17
16
  import { spawn } from 'child_process';
18
17
  import { MCPClient } from '@mastra/mcp';
19
18
  import { z } from 'zod';
20
- import { ModelsDevGateway, NetlifyGateway } from '@mastra/core/llm';
21
19
  import { LibSQLStore } from '@mastra/libsql';
22
20
  import { PostgresStore } from '@mastra/pg';
23
21
 
@@ -326,80 +324,117 @@ ${sections.join("\n\n")}
326
324
 
327
325
  // src/agents/prompts/tool-guidance.ts
328
326
  function buildToolGuidance(modeId, options = {}) {
327
+ const denied = options.deniedTools ?? /* @__PURE__ */ new Set();
329
328
  const sections = [];
330
329
  sections.push(`# Tool Usage Rules
331
330
 
332
331
  IMPORTANT: You can ONLY call tools by their exact registered names listed below. Shell commands like \`git\`, \`npm\`, \`ls\`, etc. are NOT tools \u2014 they must be run via the \`execute_command\` tool.
333
332
 
334
333
  You have access to the following tools. Use the RIGHT tool for the job:`);
335
- sections.push(`
336
- **view** \u2014 Read file contents or list directories
334
+ const readTools = [];
335
+ if (!denied.has(MC_TOOLS.VIEW)) {
336
+ readTools.push(`
337
+ **${MC_TOOLS.VIEW}** \u2014 Read file contents
337
338
  - Use this to read files before editing them. NEVER propose changes to code you haven't read.
338
- - Use \`view_range\` for large files to read specific sections.
339
- - For directory listings, this shows 2 levels deep.
340
- - Example: To check lines 50-100 of a large file: \`view("src/big-file.ts", { view_range: [50, 100] })\`
341
-
342
- **search_content** \u2014 Search file contents using regex
343
- - Use this for ALL content search (finding functions, variables, error messages, imports, etc.)
344
- - NEVER use \`execute_command\` with grep, rg, or ag. Always use the search_content tool.
345
- - Supports regex patterns, file type filtering, and context lines.
346
- - Example: Find where a function is defined: \`search_content("function handleSubmit", { glob: "**/*.ts" })\`
347
- - Example: Find all imports of a module: \`search_content("from ['\\"]express['\\"]", { glob: "**/*.ts" })\`
348
-
349
- **find_files** \u2014 Find files by name pattern
350
- - Use this to find files matching a pattern (e.g., "**/*.ts", "src/**/test*").
351
- - NEVER use \`execute_command\` with find or ls for file search. Always use find_files.
352
- - Respects .gitignore automatically.
353
- - Example: Find all test files: \`find_files("**/*.test.ts")\`
354
- - Example: Find config files: \`find_files("**/config.{js,ts,json}")\`
355
-
356
- **execute_command** \u2014 Run shell commands
339
+ - Use \`offset\` (1-indexed start line) and \`limit\` (number of lines) for large files.
340
+ - Example: Read lines 50-100: \`{ path: "src/big-file.ts", offset: 50, limit: 51 }\`
341
+ - To list directories, use \`${MC_TOOLS.FIND_FILES}\` instead.`);
342
+ }
343
+ if (!denied.has(MC_TOOLS.SEARCH_CONTENT)) {
344
+ readTools.push(`
345
+ **${MC_TOOLS.SEARCH_CONTENT}** \u2014 Search file contents using regex
346
+ - Preferred for content search (finding functions, variables, error messages, imports, etc.)
347
+ - Use \`path\` to filter by directory or glob pattern. Supports \`contextLines\`, \`caseSensitive\`, and \`maxCount\`.
348
+ - Example: Find a function: \`{ pattern: "function handleSubmit", path: "**/*.ts" }\`
349
+ - Example: Find imports: \`{ pattern: "from ['\\"\\]express['\\"\\]", path: "**/*.ts" }\`
350
+ - Respects .gitignore by default.`);
351
+ }
352
+ if (!denied.has(MC_TOOLS.FIND_FILES)) {
353
+ readTools.push(`
354
+ **${MC_TOOLS.FIND_FILES}** \u2014 List files and directories as a tree
355
+ - Preferred for exploring project structure and finding files by pattern.
356
+ - Returns tree-style output. Respects .gitignore by default.
357
+ - Example: List project root: \`{ path: "./" }\`
358
+ - Example: Find test files: \`{ path: "./src", pattern: "**/*.test.ts" }\`
359
+ - Example: Find config files: \`{ pattern: "*.config.{js,ts,json}" }\``);
360
+ }
361
+ if (!denied.has(MC_TOOLS.EXECUTE_COMMAND)) {
362
+ readTools.push(`
363
+ **${MC_TOOLS.EXECUTE_COMMAND}** \u2014 Run shell commands
357
364
  - Use for: git, npm/pnpm, docker, build tools, test runners, and other terminal operations.
358
- - Do NOT use for: file reading (use view), file search (use search_content/find_files), file editing (use string_replace_lsp/write_file).
359
- - Commands have a 30-second default timeout. Use the \`timeout\` parameter for longer-running commands.
360
- - Pipe to \`| tail -N\` for commands with long output \u2014 the full output streams to the user, only the last N lines are returned to you. If you're building any kind of package you should be tailing.
365
+ - Prefer dedicated tools for: file reading (${MC_TOOLS.VIEW}), file search (${MC_TOOLS.SEARCH_CONTENT}/${MC_TOOLS.FIND_FILES}), file editing (${MC_TOOLS.STRING_REPLACE_LSP}/${MC_TOOLS.WRITE_FILE}).
366
+ - Commands have a 30-second default timeout. Use \`timeout\` for longer commands, \`cwd\` for working directory.
367
+ - Use the \`tail\` parameter or pipe to \`| tail -N\` to limit output \u2014 the full output streams to the user, only the tail is returned to you. If you're building any kind of package you should be tailing.
361
368
  - Good: Run independent commands in parallel when possible.
362
- - Bad: Running \`cat file.txt\` \u2014 use the view tool instead.`);
369
+ - Bad: Running \`cat file.txt\` \u2014 use the ${MC_TOOLS.VIEW} tool instead.`);
370
+ }
371
+ if (readTools.length > 0) {
372
+ sections.push(readTools.join("\n"));
373
+ }
363
374
  if (modeId !== "plan") {
364
- sections.push(`
365
- **string_replace_lsp** \u2014 Edit files by replacing exact text
366
- - You MUST read a file with \`view\` before editing it.
367
- - \`old_str\` must be an exact match of existing text in the file.
368
- - Provide enough surrounding context in \`old_str\` to make it unique.
369
- - For creating new files, use \`write_file\` instead.
375
+ const writeTools = [];
376
+ if (!denied.has(MC_TOOLS.STRING_REPLACE_LSP)) {
377
+ writeTools.push(`
378
+ **${MC_TOOLS.STRING_REPLACE_LSP}** \u2014 Edit files by replacing exact text
379
+ - You MUST read a file with \`${MC_TOOLS.VIEW}\` before editing it.
380
+ - \`old_string\` must be an exact match of existing text in the file.
381
+ - Provide enough surrounding context in \`old_string\` to make it unique.
382
+ - Use \`replace_all: true\` to replace all occurrences (default: false, requires unique match).
383
+ - For creating new files, use \`${MC_TOOLS.WRITE_FILE}\` instead.
370
384
  - Good: Include 2-3 lines of surrounding context to ensure uniqueness.
371
- - Bad: Using just \`return true;\` \u2014 too common, will match multiple places.
372
-
373
- **write_file** \u2014 Create new files or overwrite existing ones
385
+ - Bad: Using just \`return true;\` \u2014 too common, will match multiple places.`);
386
+ }
387
+ if (!denied.has(MC_TOOLS.WRITE_FILE)) {
388
+ writeTools.push(`
389
+ **${MC_TOOLS.WRITE_FILE}** \u2014 Create new files or overwrite existing ones
374
390
  - Use this to create new files.
375
- - If overwriting an existing file, you MUST have read it first with \`view\`.
376
- - NEVER create files unless necessary. Prefer editing existing files.`);
391
+ - If overwriting an existing file, you MUST have read it first with \`${MC_TOOLS.VIEW}\`.
392
+ - Prefer editing existing files over creating new ones.`);
393
+ }
394
+ if (writeTools.length > 0) {
395
+ sections.push(writeTools.join("\n"));
396
+ }
377
397
  }
378
398
  if (options.hasWebSearch) {
379
- sections.push(`
380
- **web_search** / **web_extract** \u2014 Search the web / extract page content
399
+ const webTools = [];
400
+ if (!denied.has("web_search")) webTools.push("**web_search**");
401
+ if (!denied.has("web_extract")) webTools.push("**web_extract**");
402
+ if (webTools.length > 0) {
403
+ sections.push(`
404
+ ${webTools.join(" / ")} \u2014 Search the web / extract page content
381
405
  - Use for looking up documentation, error messages, package APIs.`);
406
+ }
382
407
  }
383
- sections.push(`
408
+ const taskTools = [];
409
+ if (!denied.has("task_write")) {
410
+ taskTools.push(`
384
411
  **task_write** \u2014 Track tasks for complex multi-step work
385
412
  - Use when a task requires 3 or more distinct steps or actions.
386
413
  - Pass the FULL task list each time (replaces previous list).
387
414
  - Mark tasks \`in_progress\` BEFORE starting work. Only ONE task should be \`in_progress\` at a time.
388
415
  - Mark tasks \`completed\` IMMEDIATELY after finishing each task. Do not batch completions.
389
- - Each task has: content (imperative form), status (pending|in_progress|completed), activeForm (present continuous form shown during execution).
390
-
416
+ - Each task has: content (imperative form), status (pending|in_progress|completed), activeForm (present continuous form shown during execution).`);
417
+ }
418
+ if (!denied.has("task_check")) {
419
+ taskTools.push(`
391
420
  **task_check** \u2014 Check completion status of tasks
392
421
  - Use this BEFORE deciding you're done with a task to verify all tasks are completed.
393
422
  - Returns the number of completed, in progress, and pending tasks.
394
423
  - If any tasks remain incomplete, continue working on them.
395
- - IMPORTANT: Always check task completion before ending work on a complex task.
396
-
424
+ - IMPORTANT: Always check task completion before ending work on a complex task.`);
425
+ }
426
+ if (!denied.has("ask_user")) {
427
+ taskTools.push(`
397
428
  **ask_user** \u2014 Ask the user a structured question
398
429
  - Use when you need clarification, want to validate assumptions, or need the user to make a decision.
399
430
  - Provide clear, specific questions. End with a question mark.
400
431
  - Include options (2-4 choices) for structured decisions. Omit options for open-ended questions.
401
432
  - Don't use this for simple yes/no \u2014 just ask in your text response.`);
402
- if (modeId === "plan") {
433
+ }
434
+ if (taskTools.length > 0) {
435
+ sections.push(taskTools.join("\n"));
436
+ }
437
+ if (modeId === "plan" && !denied.has("submit_plan")) {
403
438
  sections.push(`
404
439
  **submit_plan** \u2014 Submit a completed implementation plan for user review
405
440
  - Call this tool when your plan is complete. Do NOT just describe your plan in text \u2014 you MUST call this tool.
@@ -407,10 +442,12 @@ You have access to the following tools. Use the RIGHT tool for the job:`);
407
442
  - On approval, the system automatically switches to the default mode so you can implement.
408
443
  - Takes two arguments: \`title\` (short descriptive title) and \`plan\` (full plan in markdown).`);
409
444
  }
410
- sections.push(`
445
+ if (!denied.has("subagent")) {
446
+ sections.push(`
411
447
  **subagent** \u2014 Delegate a focused task to a specialized subagent
412
448
  - Only use subagents when you will spawn **multiple subagents in parallel**. If you only need one task done, do it yourself.
413
449
  - Subagent outputs are **untrusted**. Always review and verify the results.`);
450
+ }
414
451
  return sections.join("\n");
415
452
  }
416
453
 
@@ -423,7 +460,14 @@ var modePrompts = {
423
460
  function buildFullPrompt(ctx) {
424
461
  const modelId = ctx.state?.currentModelId;
425
462
  const hasWebSearch = hasTavilyKey() || !!modelId && modelId.startsWith("anthropic/");
426
- const toolGuidance = buildToolGuidance(ctx.modeId, { hasWebSearch });
463
+ const deniedTools = /* @__PURE__ */ new Set();
464
+ const permRules = ctx.state?.permissionRules;
465
+ if (permRules?.tools) {
466
+ for (const [name, policy] of Object.entries(permRules.tools)) {
467
+ if (policy === "deny") deniedTools.add(name);
468
+ }
469
+ }
470
+ const toolGuidance = buildToolGuidance(ctx.modeId, { hasWebSearch, deniedTools });
427
471
  const baseCtx = {
428
472
  projectPath: ctx.workingDir,
429
473
  projectName: ctx.projectName || "unknown",
@@ -491,11 +535,11 @@ function getHarnessState(requestContext) {
491
535
  }
492
536
  function getObserverModel({ requestContext }) {
493
537
  const state = getHarnessState(requestContext);
494
- return resolveModel(state?.observerModelId ?? DEFAULT_OM_MODEL_ID);
538
+ return resolveModel(state?.observerModelId ?? DEFAULT_OM_MODEL_ID, { remapForCodexOAuth: true });
495
539
  }
496
540
  function getReflectorModel({ requestContext }) {
497
541
  const state = getHarnessState(requestContext);
498
- return resolveModel(state?.reflectorModelId ?? DEFAULT_OM_MODEL_ID);
542
+ return resolveModel(state?.reflectorModelId ?? DEFAULT_OM_MODEL_ID, { remapForCodexOAuth: true });
499
543
  }
500
544
  function getDynamicMemory(storage) {
501
545
  return ({ requestContext }) => {
@@ -518,19 +562,13 @@ function getDynamicMemory(storage) {
518
562
  bufferActivation: 2e3,
519
563
  model: getObserverModel,
520
564
  messageTokens: obsThreshold,
521
- blockAfter: 2,
522
- modelSettings: {
523
- maxOutputTokens: 6e4
524
- }
565
+ blockAfter: 2
525
566
  },
526
567
  reflection: {
527
568
  bufferActivation: 1 / 2,
528
569
  blockAfter: 1.1,
529
570
  model: getReflectorModel,
530
- observationTokens: refThreshold,
531
- modelSettings: {
532
- maxOutputTokens: 6e4
533
- }
571
+ observationTokens: refThreshold
534
572
  }
535
573
  }
536
574
  }
@@ -539,120 +577,48 @@ function getDynamicMemory(storage) {
539
577
  return cachedMemory;
540
578
  };
541
579
  }
542
- function createDynamicTools(mcpManager) {
580
+ function createDynamicTools(mcpManager, extraTools) {
543
581
  return function getDynamicTools({ requestContext }) {
544
582
  const ctx = requestContext.get("harness");
545
583
  const state = ctx?.getState?.();
546
- const modeId = ctx?.modeId ?? "build";
547
584
  const modelId = state?.currentModelId;
548
585
  const isAnthropicModel = modelId?.startsWith("anthropic/");
549
- const projectPath = state?.projectPath ?? "";
550
- const viewTool = createViewTool(projectPath);
551
- const grepTool = createGrepTool(projectPath);
552
- const globTool = createGlobTool(projectPath);
553
- const executeCommandTool = createExecuteCommandTool(projectPath);
554
- const writeFileTool = createWriteFileTool(projectPath);
586
+ const isOpenAIModel = modelId?.startsWith("openai/");
555
587
  const tools = {
556
- view: viewTool,
557
- search_content: grepTool,
558
- find_files: globTool,
559
- execute_command: executeCommandTool,
560
588
  request_sandbox_access: requestSandboxAccessTool
561
589
  };
562
- if (modeId !== "plan") {
563
- tools.string_replace_lsp = stringReplaceLspTool;
564
- tools.ast_smart_edit = astSmartEditTool;
565
- tools.write_file = writeFileTool;
566
- }
567
590
  if (hasTavilyKey()) {
568
591
  tools.web_search = createWebSearchTool();
569
592
  tools.web_extract = createWebExtractTool();
570
593
  } else if (isAnthropicModel) {
571
594
  const anthropic = createAnthropic({});
572
595
  tools.web_search = anthropic.tools.webSearch_20250305();
596
+ } else if (isOpenAIModel) {
597
+ const openai = createOpenAI({});
598
+ tools.web_search = openai.tools.webSearch();
573
599
  }
574
600
  if (mcpManager) {
575
601
  const mcpTools = mcpManager.getTools();
576
602
  Object.assign(tools, mcpTools);
577
603
  }
578
- return tools;
579
- };
580
- }
581
- var mastraCodeLocalSkillsPath = path__default.join(process.cwd(), ".mastracode", "skills");
582
- var claudeLocalSkillsPath = path__default.join(process.cwd(), ".claude", "skills");
583
- var mastraCodeGlobalSkillsPath = path__default.join(os__default.homedir(), ".mastracode", "skills");
584
- var claudeGlobalSkillsPath = path__default.join(os__default.homedir(), ".claude", "skills");
585
- function collectSkillPaths(skillsDirs) {
586
- const paths = [];
587
- const seen = /* @__PURE__ */ new Set();
588
- for (const skillsDir of skillsDirs) {
589
- if (!fs4__default.existsSync(skillsDir)) continue;
590
- const resolved = fs4__default.realpathSync(skillsDir);
591
- if (!seen.has(resolved)) {
592
- seen.add(resolved);
593
- paths.push(skillsDir);
604
+ if (extraTools) {
605
+ const resolved = typeof extraTools === "function" ? extraTools({ requestContext }) : extraTools;
606
+ for (const [name, tool] of Object.entries(resolved)) {
607
+ if (!(name in tools)) {
608
+ tools[name] = tool;
609
+ }
610
+ }
594
611
  }
595
- try {
596
- const entries = fs4__default.readdirSync(skillsDir, { withFileTypes: true });
597
- for (const entry of entries) {
598
- if (entry.isSymbolicLink()) {
599
- const linkPath = path__default.join(skillsDir, entry.name);
600
- const realPath = fs4__default.realpathSync(linkPath);
601
- const stat = fs4__default.statSync(realPath);
602
- if (stat.isDirectory()) {
603
- const realParent = path__default.dirname(realPath);
604
- if (!seen.has(realParent)) {
605
- seen.add(realParent);
606
- paths.push(realParent);
607
- }
608
- }
612
+ const permissionRules = state?.permissionRules;
613
+ if (permissionRules?.tools) {
614
+ for (const [name, policy] of Object.entries(permissionRules.tools)) {
615
+ if (policy === "deny") {
616
+ delete tools[name];
609
617
  }
610
618
  }
611
- } catch {
612
619
  }
613
- }
614
- return paths;
615
- }
616
- var skillPaths = collectSkillPaths([
617
- mastraCodeLocalSkillsPath,
618
- claudeLocalSkillsPath,
619
- mastraCodeGlobalSkillsPath,
620
- claudeGlobalSkillsPath
621
- ]);
622
- function getDynamicWorkspace({ requestContext }) {
623
- const ctx = requestContext.get("harness");
624
- const state = ctx?.getState?.();
625
- const projectPath = state?.projectPath;
626
- if (!projectPath) {
627
- throw new Error("Project path is required");
628
- }
629
- const sandboxPaths = state?.sandboxAllowedPaths ?? [];
630
- const workspace = new Workspace({
631
- id: "mastra-code-workspace",
632
- name: "Mastra Code Workspace",
633
- filesystem: new LocalFilesystem({
634
- basePath: projectPath,
635
- allowedPaths: skillPaths
636
- }),
637
- sandbox: new LocalSandbox({
638
- workingDirectory: projectPath,
639
- env: process.env
640
- }),
641
- // Disable workspace tools — built-in tools are used instead.
642
- // Workspace tools use different output formats (e.g. → separator, offset/limit params)
643
- // that the TUI renderers don't fully support yet.
644
- // We will update to use workspace tools very soon - just disabling until then
645
- tools: { enabled: false },
646
- ...skillPaths.length > 0 ? { skills: skillPaths } : {}
647
- });
648
- workspace.filesystem.setAllowedPaths([...skillPaths, ...sandboxPaths.map((p) => path__default.resolve(p))]);
649
- return workspace;
650
- }
651
- if (skillPaths.length > 0) {
652
- console.info(`Skills loaded from:`);
653
- for (const p of skillPaths) {
654
- console.info(` - ${p}`);
655
- }
620
+ return tools;
621
+ };
656
622
  }
657
623
  var VALID_EVENTS = [
658
624
  "PreToolUse",
@@ -670,15 +636,15 @@ function loadHooksConfig(projectDir) {
670
636
  return mergeConfigs(globalConfig, projectConfig);
671
637
  }
672
638
  function getProjectHooksPath(projectDir) {
673
- return path.join(projectDir, ".mastracode", "hooks.json");
639
+ return path3.join(projectDir, ".mastracode", "hooks.json");
674
640
  }
675
641
  function getGlobalHooksPath() {
676
- return path.join(os.homedir(), ".mastracode", "hooks.json");
642
+ return path3.join(os.homedir(), ".mastracode", "hooks.json");
677
643
  }
678
644
  function loadSingleConfig(filePath) {
679
645
  try {
680
- if (!fs4.existsSync(filePath)) return {};
681
- const raw = fs4.readFileSync(filePath, "utf-8");
646
+ if (!fs3.existsSync(filePath)) return {};
647
+ const raw = fs3.readFileSync(filePath, "utf-8");
682
648
  return validateConfig(JSON.parse(raw));
683
649
  } catch {
684
650
  return {};
@@ -975,18 +941,18 @@ function loadMcpConfig(projectDir) {
975
941
  return mergeConfigs2(claudeConfig, globalConfig, projectConfig);
976
942
  }
977
943
  function getProjectMcpPath(projectDir) {
978
- return path.join(projectDir, ".mastracode", "mcp.json");
944
+ return path3.join(projectDir, ".mastracode", "mcp.json");
979
945
  }
980
946
  function getGlobalMcpPath() {
981
- return path.join(os.homedir(), ".mastracode", "mcp.json");
947
+ return path3.join(os.homedir(), ".mastracode", "mcp.json");
982
948
  }
983
949
  function getClaudeSettingsPath(projectDir) {
984
- return path.join(projectDir, ".claude", "settings.local.json");
950
+ return path3.join(projectDir, ".claude", "settings.local.json");
985
951
  }
986
952
  function loadSingleConfig2(filePath) {
987
953
  try {
988
- if (!fs4.existsSync(filePath)) return {};
989
- const raw = fs4.readFileSync(filePath, "utf-8");
954
+ if (!fs3.existsSync(filePath)) return {};
955
+ const raw = fs3.readFileSync(filePath, "utf-8");
990
956
  return validateConfig2(JSON.parse(raw));
991
957
  } catch {
992
958
  return {};
@@ -995,8 +961,8 @@ function loadSingleConfig2(filePath) {
995
961
  function loadClaudeSettings(projectDir) {
996
962
  try {
997
963
  const filePath = getClaudeSettingsPath(projectDir);
998
- if (!fs4.existsSync(filePath)) return {};
999
- const raw = fs4.readFileSync(filePath, "utf-8");
964
+ if (!fs3.existsSync(filePath)) return {};
965
+ const raw = fs3.readFileSync(filePath, "utf-8");
1000
966
  const parsed = JSON.parse(raw);
1001
967
  if (parsed?.mcpServers && typeof parsed.mcpServers === "object") {
1002
968
  return validateConfig2({ mcpServers: parsed.mcpServers });
@@ -1006,43 +972,97 @@ function loadClaudeSettings(projectDir) {
1006
972
  return {};
1007
973
  }
1008
974
  }
975
+ function classifyServerEntry(raw) {
976
+ if (!raw || typeof raw !== "object") {
977
+ return { kind: "skip", reason: "Invalid entry: expected an object" };
978
+ }
979
+ const obj = raw;
980
+ const hasCommand = typeof obj.command === "string";
981
+ const hasUrl = typeof obj.url === "string";
982
+ if (hasCommand && hasUrl) {
983
+ return { kind: "skip", reason: 'Cannot specify both "command" and "url"' };
984
+ }
985
+ if (hasCommand) {
986
+ return { kind: "stdio" };
987
+ }
988
+ if (hasUrl) {
989
+ try {
990
+ new URL(obj.url);
991
+ } catch {
992
+ return { kind: "skip", reason: `Invalid URL: "${obj.url}"` };
993
+ }
994
+ return { kind: "http" };
995
+ }
996
+ return { kind: "skip", reason: 'Missing required field: "command" (stdio) or "url" (http)' };
997
+ }
1009
998
  function validateConfig2(raw) {
1010
999
  if (!raw || typeof raw !== "object") return {};
1011
1000
  const obj = raw;
1012
1001
  if (!obj.mcpServers || typeof obj.mcpServers !== "object") return {};
1013
1002
  const servers = {};
1003
+ const skippedServers = [];
1014
1004
  const rawServers = obj.mcpServers;
1015
1005
  for (const [name, entry] of Object.entries(rawServers)) {
1016
- if (isValidServerConfig(entry)) {
1006
+ const classification = classifyServerEntry(entry);
1007
+ if (classification.kind === "stdio") {
1008
+ const e = entry;
1009
+ servers[name] = {
1010
+ command: e.command,
1011
+ args: Array.isArray(e.args) ? e.args : void 0,
1012
+ env: typeof e.env === "object" && e.env !== null ? e.env : void 0
1013
+ };
1014
+ } else if (classification.kind === "http") {
1015
+ const e = entry;
1017
1016
  servers[name] = {
1018
- command: entry.command,
1019
- args: Array.isArray(entry.args) ? entry.args : void 0,
1020
- env: typeof entry.env === "object" && entry.env !== null ? entry.env : void 0
1017
+ url: e.url,
1018
+ headers: typeof e.headers === "object" && e.headers !== null ? e.headers : void 0
1021
1019
  };
1020
+ } else {
1021
+ skippedServers.push({ name, reason: classification.reason });
1022
1022
  }
1023
1023
  }
1024
- if (Object.keys(servers).length === 0) return {};
1025
- return { mcpServers: servers };
1026
- }
1027
- function isValidServerConfig(raw) {
1028
- if (!raw || typeof raw !== "object") return false;
1029
- const obj = raw;
1030
- return typeof obj.command === "string";
1024
+ const result = {};
1025
+ if (Object.keys(servers).length > 0) {
1026
+ result.mcpServers = servers;
1027
+ }
1028
+ if (skippedServers.length > 0) {
1029
+ result.skippedServers = skippedServers;
1030
+ }
1031
+ return result;
1031
1032
  }
1032
1033
  function mergeConfigs2(...configs) {
1033
1034
  const merged = {};
1035
+ const allSkipped = [];
1034
1036
  for (const config of configs) {
1035
1037
  if (config.mcpServers) {
1036
1038
  for (const [name, server] of Object.entries(config.mcpServers)) {
1037
1039
  merged[name] = server;
1038
1040
  }
1039
1041
  }
1042
+ if (config.skippedServers) {
1043
+ allSkipped.push(...config.skippedServers);
1044
+ }
1045
+ }
1046
+ const validNames = new Set(Object.keys(merged));
1047
+ const filteredSkipped = allSkipped.filter((s) => !validNames.has(s.name));
1048
+ const skippedMap = /* @__PURE__ */ new Map();
1049
+ for (const s of filteredSkipped) {
1050
+ skippedMap.set(s.name, s);
1051
+ }
1052
+ const result = {};
1053
+ if (Object.keys(merged).length > 0) {
1054
+ result.mcpServers = merged;
1040
1055
  }
1041
- if (Object.keys(merged).length === 0) return {};
1042
- return { mcpServers: merged };
1056
+ if (skippedMap.size > 0) {
1057
+ result.skippedServers = Array.from(skippedMap.values());
1058
+ }
1059
+ return result;
1043
1060
  }
1044
1061
 
1045
1062
  // src/mcp/manager.ts
1063
+ function getTransport(cfg) {
1064
+ return "url" in cfg ? "http" : "stdio";
1065
+ }
1046
1066
  function createMcpManager(projectDir) {
1047
1067
  let config = loadMcpConfig(projectDir);
1048
1068
  let client = null;
@@ -1052,7 +1072,15 @@ function createMcpManager(projectDir) {
1052
1072
  function buildServerDefs(servers) {
1053
1073
  const defs = {};
1054
1074
  for (const [name, cfg] of Object.entries(servers)) {
1055
- defs[name] = { command: cfg.command, args: cfg.args, env: cfg.env };
1075
+ if ("url" in cfg) {
1076
+ const httpCfg = cfg;
1077
+ defs[name] = {
1078
+ url: new URL(httpCfg.url),
1079
+ requestInit: httpCfg.headers ? { headers: httpCfg.headers } : void 0
1080
+ };
1081
+ } else {
1082
+ defs[name] = { command: cfg.command, args: cfg.args, env: cfg.env };
1083
+ }
1056
1084
  }
1057
1085
  return defs;
1058
1086
  }
@@ -1075,7 +1103,8 @@ function createMcpManager(projectDir) {
1075
1103
  name,
1076
1104
  connected: true,
1077
1105
  toolCount: serverToolNames.length,
1078
- toolNames: serverToolNames
1106
+ toolNames: serverToolNames,
1107
+ transport: getTransport(servers[name])
1079
1108
  });
1080
1109
  }
1081
1110
  } catch (error) {
@@ -1086,6 +1115,7 @@ function createMcpManager(projectDir) {
1086
1115
  connected: false,
1087
1116
  toolCount: 0,
1088
1117
  toolNames: [],
1118
+ transport: getTransport(servers[name]),
1089
1119
  error: errMsg
1090
1120
  });
1091
1121
  }
@@ -1120,11 +1150,16 @@ function createMcpManager(projectDir) {
1120
1150
  return { ...tools };
1121
1151
  },
1122
1152
  hasServers() {
1123
- return config.mcpServers !== void 0 && Object.keys(config.mcpServers).length > 0;
1153
+ const hasConfigured = config.mcpServers !== void 0 && Object.keys(config.mcpServers).length > 0;
1154
+ const hasSkipped = config.skippedServers !== void 0 && config.skippedServers.length > 0;
1155
+ return hasConfigured || hasSkipped;
1124
1156
  },
1125
1157
  getServerStatuses() {
1126
1158
  return Array.from(serverStatuses.values());
1127
1159
  },
1160
+ getSkippedServers() {
1161
+ return [...config.skippedServers ?? []];
1162
+ },
1128
1163
  getConfigPaths() {
1129
1164
  return {
1130
1165
  project: getProjectMcpPath(projectDir),
@@ -1182,21 +1217,21 @@ var stateSchema = z.object({
1182
1217
  approvedAt: z.string()
1183
1218
  }).nullable().default(null)
1184
1219
  });
1185
- var CACHE_DIR = path__default.join(os__default.homedir(), ".cache", "mastra");
1186
- var CACHE_FILE = path__default.join(CACHE_DIR, "gateway-refresh-time");
1187
- var GLOBAL_PROVIDER_REGISTRY_JSON = path__default.join(CACHE_DIR, "provider-registry.json");
1188
- var GLOBAL_PROVIDER_TYPES_DTS = path__default.join(CACHE_DIR, "provider-types.generated.d.ts");
1220
+ var CACHE_DIR = path3__default.join(os__default.homedir(), ".cache", "mastra");
1221
+ var CACHE_FILE = path3__default.join(CACHE_DIR, "gateway-refresh-time");
1222
+ var GLOBAL_PROVIDER_REGISTRY_JSON = path3__default.join(CACHE_DIR, "provider-registry.json");
1223
+ var GLOBAL_PROVIDER_TYPES_DTS = path3__default.join(CACHE_DIR, "provider-types.generated.d.ts");
1189
1224
  var DEFAULT_SYNC_INTERVAL_MS = 5 * 60 * 1e3;
1190
1225
  var isSyncing = false;
1191
1226
  async function atomicWriteFile(filePath, content) {
1192
1227
  const randomSuffix = Math.random().toString(36).substring(2, 15);
1193
1228
  const tempPath = `${filePath}.${process.pid}.${Date.now()}.${randomSuffix}.tmp`;
1194
1229
  try {
1195
- await fs4__default.promises.writeFile(tempPath, content, "utf-8");
1196
- await fs4__default.promises.rename(tempPath, filePath);
1230
+ await fs3__default.promises.writeFile(tempPath, content, "utf-8");
1231
+ await fs3__default.promises.rename(tempPath, filePath);
1197
1232
  } catch (error) {
1198
1233
  try {
1199
- await fs4__default.promises.unlink(tempPath);
1234
+ await fs3__default.promises.unlink(tempPath);
1200
1235
  } catch {
1201
1236
  }
1202
1237
  throw error;
@@ -1261,10 +1296,10 @@ export type ModelForProvider<P extends Provider> = ProviderModelsMap[P][number];
1261
1296
  }
1262
1297
  function getLastSyncTime() {
1263
1298
  try {
1264
- if (!fs4__default.existsSync(CACHE_FILE)) {
1299
+ if (!fs3__default.existsSync(CACHE_FILE)) {
1265
1300
  return null;
1266
1301
  }
1267
- const timestamp = fs4__default.readFileSync(CACHE_FILE, "utf-8").trim();
1302
+ const timestamp = fs3__default.readFileSync(CACHE_FILE, "utf-8").trim();
1268
1303
  return new Date(parseInt(timestamp, 10));
1269
1304
  } catch {
1270
1305
  return null;
@@ -1272,10 +1307,10 @@ function getLastSyncTime() {
1272
1307
  }
1273
1308
  function saveLastSyncTime(date) {
1274
1309
  try {
1275
- if (!fs4__default.existsSync(CACHE_DIR)) {
1276
- fs4__default.mkdirSync(CACHE_DIR, { recursive: true });
1310
+ if (!fs3__default.existsSync(CACHE_DIR)) {
1311
+ fs3__default.mkdirSync(CACHE_DIR, { recursive: true });
1277
1312
  }
1278
- fs4__default.writeFileSync(CACHE_FILE, date.getTime().toString(), "utf-8");
1313
+ fs3__default.writeFileSync(CACHE_FILE, date.getTime().toString(), "utf-8");
1279
1314
  } catch (error) {
1280
1315
  console.warn("[GatewaySync] Failed to save sync time:", error);
1281
1316
  }
@@ -1296,7 +1331,7 @@ async function syncGateways(force = false) {
1296
1331
  isSyncing = true;
1297
1332
  try {
1298
1333
  const { providers, models } = await fetchProvidersFromGateways();
1299
- await fs4__default.promises.mkdir(CACHE_DIR, { recursive: true });
1334
+ await fs3__default.promises.mkdir(CACHE_DIR, { recursive: true });
1300
1335
  const registryData = {
1301
1336
  providers,
1302
1337
  models,
@@ -1393,19 +1428,13 @@ async function createMastraCode(config) {
1393
1428
  const storageWarning = storageResult.warning;
1394
1429
  const memory = getDynamicMemory(storage);
1395
1430
  const mcpManager = config?.disableMcp ? void 0 : createMcpManager(project.rootPath);
1396
- const codeAgentInstance = new Agent({
1431
+ const codeAgent = new Agent({
1397
1432
  id: "code-agent",
1398
1433
  name: "Code Agent",
1399
1434
  instructions: getDynamicInstructions,
1400
1435
  model: getDynamicModel,
1401
- tools: createDynamicTools(mcpManager)
1402
- });
1403
- const mastraInstance = new Mastra({
1404
- agents: { codeAgentInstance },
1405
- logger: noopLogger,
1406
- storage
1436
+ tools: createDynamicTools(mcpManager, config?.extraTools)
1407
1437
  });
1408
- const codeAgent = mastraInstance.getAgent("codeAgentInstance");
1409
1438
  const hookManager = config?.disableHooks ? void 0 : new HookManager(project.rootPath, "session-init");
1410
1439
  if (hookManager?.hasHooks()) {
1411
1440
  const hookConfig = hookManager.getConfig();
@@ -1417,6 +1446,7 @@ async function createMastraCode(config) {
1417
1446
  const globTool = createGlobTool(project.rootPath);
1418
1447
  const executeCommandTool = createExecuteCommandTool(project.rootPath);
1419
1448
  const writeFileTool = createWriteFileTool(project.rootPath);
1449
+ const stringReplaceLspTool = createStringReplaceLspTool(project.rootPath);
1420
1450
  const readOnlyTools = {
1421
1451
  view: viewTool,
1422
1452
  search_content: grepTool,
@@ -1490,6 +1520,18 @@ async function createMastraCode(config) {
1490
1520
  google: process.env.GOOGLE_GENERATIVE_AI_API_KEY ? "apikey" : false,
1491
1521
  deepseek: process.env.DEEPSEEK_API_KEY ? "apikey" : false
1492
1522
  };
1523
+ try {
1524
+ const registry = PROVIDER_REGISTRY;
1525
+ for (const [provider, config2] of Object.entries(registry)) {
1526
+ if (startupAccess[provider] && startupAccess[provider] !== false) continue;
1527
+ const envVars = config2?.apiKeyEnvVar;
1528
+ const envVarList = Array.isArray(envVars) ? envVars : envVars ? [envVars] : [];
1529
+ if (envVarList.some((envVar) => process.env[envVar])) {
1530
+ startupAccess[provider] = "apikey";
1531
+ }
1532
+ }
1533
+ } catch {
1534
+ }
1493
1535
  const builtinPacks = getAvailableModePacks(startupAccess);
1494
1536
  const builtinOmPacks = getAvailableOmPacks(startupAccess);
1495
1537
  const effectiveDefaults = resolveModelDefaults(globalSettings, builtinPacks);
@@ -1536,7 +1578,7 @@ async function createMastraCode(config) {
1536
1578
  ...globalInitialState,
1537
1579
  ...config?.initialState
1538
1580
  },
1539
- workspace: getDynamicWorkspace,
1581
+ workspace: config?.workspace ?? getDynamicWorkspace,
1540
1582
  modes,
1541
1583
  heartbeatHandlers: config?.heartbeatHandlers ?? defaultHeartbeatHandlers,
1542
1584
  modelAuthChecker: (provider) => {
@@ -1544,9 +1586,41 @@ async function createMastraCode(config) {
1544
1586
  if (oauthId && authStorage.isLoggedIn(oauthId)) {
1545
1587
  return true;
1546
1588
  }
1589
+ const customProvider = loadSettings().customProviders.find((entry) => {
1590
+ return provider === getCustomProviderId(entry.name);
1591
+ });
1592
+ if (customProvider) {
1593
+ return true;
1594
+ }
1547
1595
  return void 0;
1548
1596
  },
1549
1597
  modelUseCountProvider: () => loadSettings().modelUseCounts,
1598
+ modelUseCountTracker: (modelId) => {
1599
+ try {
1600
+ const settings = loadSettings();
1601
+ settings.modelUseCounts[modelId] = (settings.modelUseCounts[modelId] ?? 0) + 1;
1602
+ saveSettings(settings);
1603
+ } catch (error) {
1604
+ console.error("Failed to persist model usage count", error);
1605
+ }
1606
+ },
1607
+ customModelCatalogProvider: () => {
1608
+ const settings = loadSettings();
1609
+ const customModels = [];
1610
+ for (const provider of settings.customProviders) {
1611
+ const providerId = getCustomProviderId(provider.name);
1612
+ for (const modelName of provider.models) {
1613
+ customModels.push({
1614
+ id: toCustomProviderModelId(provider.name, modelName),
1615
+ provider: providerId,
1616
+ modelName,
1617
+ hasApiKey: true,
1618
+ apiKeyEnvVar: void 0
1619
+ });
1620
+ }
1621
+ }
1622
+ return customModels;
1623
+ },
1550
1624
  threadLock: {
1551
1625
  acquire: acquireThreadLock,
1552
1626
  release: releaseThreadLock
@@ -1561,9 +1635,9 @@ async function createMastraCode(config) {
1561
1635
  }
1562
1636
  });
1563
1637
  }
1564
- return { harness, mcpManager, hookManager, authStorage, storageWarning };
1638
+ return { harness, mcpManager, hookManager, authStorage, resolveModel, storageWarning };
1565
1639
  }
1566
1640
 
1567
1641
  export { createMastraCode };
1568
- //# sourceMappingURL=chunk-M5LKPQB4.js.map
1569
- //# sourceMappingURL=chunk-M5LKPQB4.js.map
1642
+ //# sourceMappingURL=chunk-WKPHD54B.js.map
1643
+ //# sourceMappingURL=chunk-WKPHD54B.js.map