@mastra/code-sdk 1.2.0-alpha.8 → 1.2.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 (132) hide show
  1. package/CHANGELOG.md +237 -0
  2. package/README.md +22 -0
  3. package/dist/agents/model.d.ts.map +1 -1
  4. package/dist/agents/model.js +5 -2
  5. package/dist/agents/model.js.map +1 -1
  6. package/dist/agents/modes/build.d.ts.map +1 -1
  7. package/dist/agents/modes/build.js +6 -1
  8. package/dist/agents/modes/build.js.map +1 -1
  9. package/dist/agents/modes/explore.d.ts.map +1 -1
  10. package/dist/agents/modes/explore.js +4 -1
  11. package/dist/agents/modes/explore.js.map +1 -1
  12. package/dist/agents/modes/plan.d.ts.map +1 -1
  13. package/dist/agents/modes/plan.js +8 -3
  14. package/dist/agents/modes/plan.js.map +1 -1
  15. package/dist/agents/prompts/index.d.ts.map +1 -1
  16. package/dist/agents/prompts/index.js +4 -1
  17. package/dist/agents/prompts/index.js.map +1 -1
  18. package/dist/agents/prompts/plan.d.ts +1 -1
  19. package/dist/agents/prompts/plan.d.ts.map +1 -1
  20. package/dist/agents/prompts/plan.js +2 -2
  21. package/dist/agents/prompts/plan.js.map +1 -1
  22. package/dist/agents/prompts/tool-guidance.d.ts +2 -0
  23. package/dist/agents/prompts/tool-guidance.d.ts.map +1 -1
  24. package/dist/agents/prompts/tool-guidance.js +3 -2
  25. package/dist/agents/prompts/tool-guidance.js.map +1 -1
  26. package/dist/agents/tool-availability.d.ts.map +1 -1
  27. package/dist/agents/tool-availability.js +15 -6
  28. package/dist/agents/tool-availability.js.map +1 -1
  29. package/dist/agents/tools.d.ts +16 -0
  30. package/dist/agents/tools.d.ts.map +1 -1
  31. package/dist/agents/tools.js +16 -3
  32. package/dist/agents/tools.js.map +1 -1
  33. package/dist/agents/workflow-builder-agent.d.ts +2 -0
  34. package/dist/agents/workflow-builder-agent.d.ts.map +1 -0
  35. package/dist/agents/workflow-builder-agent.js +80 -0
  36. package/dist/agents/workflow-builder-agent.js.map +1 -0
  37. package/dist/headless/cli.d.ts.map +1 -1
  38. package/dist/headless/cli.js +3 -0
  39. package/dist/headless/cli.js.map +1 -1
  40. package/dist/hooks/manager.d.ts +9 -2
  41. package/dist/hooks/manager.d.ts.map +1 -1
  42. package/dist/hooks/manager.js +19 -3
  43. package/dist/hooks/manager.js.map +1 -1
  44. package/dist/hooks/types.d.ts +20 -0
  45. package/dist/hooks/types.d.ts.map +1 -1
  46. package/dist/hooks/types.js.map +1 -1
  47. package/dist/index.d.ts +73 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +204 -69
  50. package/dist/index.js.map +1 -1
  51. package/dist/permissions.d.ts.map +1 -1
  52. package/dist/permissions.js +6 -1
  53. package/dist/permissions.js.map +1 -1
  54. package/dist/plugin.d.ts +64 -1
  55. package/dist/plugin.d.ts.map +1 -1
  56. package/dist/plugin.js +3 -1
  57. package/dist/plugin.js.map +1 -1
  58. package/dist/plugins/loader.d.ts +7 -3
  59. package/dist/plugins/loader.d.ts.map +1 -1
  60. package/dist/plugins/loader.js +53 -1
  61. package/dist/plugins/loader.js.map +1 -1
  62. package/dist/plugins/manager.d.ts +36 -2
  63. package/dist/plugins/manager.d.ts.map +1 -1
  64. package/dist/plugins/manager.js +74 -2
  65. package/dist/plugins/manager.js.map +1 -1
  66. package/dist/plugins/signal-lane.d.ts +58 -0
  67. package/dist/plugins/signal-lane.d.ts.map +1 -0
  68. package/dist/plugins/signal-lane.js +166 -0
  69. package/dist/plugins/signal-lane.js.map +1 -0
  70. package/dist/plugins/types.d.ts +36 -0
  71. package/dist/plugins/types.d.ts.map +1 -1
  72. package/dist/tools/workflows/create-workflow.d.ts +7 -0
  73. package/dist/tools/workflows/create-workflow.d.ts.map +1 -0
  74. package/dist/tools/workflows/create-workflow.js +81 -0
  75. package/dist/tools/workflows/create-workflow.js.map +1 -0
  76. package/dist/tools/workflows/delete-workflow.d.ts +7 -0
  77. package/dist/tools/workflows/delete-workflow.d.ts.map +1 -0
  78. package/dist/tools/workflows/delete-workflow.js +21 -0
  79. package/dist/tools/workflows/delete-workflow.js.map +1 -0
  80. package/dist/tools/workflows/ephemeral-memory.d.ts +7 -0
  81. package/dist/tools/workflows/ephemeral-memory.d.ts.map +1 -0
  82. package/dist/tools/workflows/ephemeral-memory.js +45 -0
  83. package/dist/tools/workflows/ephemeral-memory.js.map +1 -0
  84. package/dist/tools/workflows/extract-json-schema.d.ts +12 -0
  85. package/dist/tools/workflows/extract-json-schema.d.ts.map +1 -0
  86. package/dist/tools/workflows/extract-json-schema.js +22 -0
  87. package/dist/tools/workflows/extract-json-schema.js.map +1 -0
  88. package/dist/tools/workflows/get-workflow.d.ts +11 -0
  89. package/dist/tools/workflows/get-workflow.d.ts.map +1 -0
  90. package/dist/tools/workflows/get-workflow.js +34 -0
  91. package/dist/tools/workflows/get-workflow.js.map +1 -0
  92. package/dist/tools/workflows/list-available-agents.d.ts +8 -0
  93. package/dist/tools/workflows/list-available-agents.d.ts.map +1 -0
  94. package/dist/tools/workflows/list-available-agents.js +32 -0
  95. package/dist/tools/workflows/list-available-agents.js.map +1 -0
  96. package/dist/tools/workflows/list-available-tools.d.ts +9 -0
  97. package/dist/tools/workflows/list-available-tools.d.ts.map +1 -0
  98. package/dist/tools/workflows/list-available-tools.js +40 -0
  99. package/dist/tools/workflows/list-available-tools.js.map +1 -0
  100. package/dist/tools/workflows/list-available-workflows.d.ts +9 -0
  101. package/dist/tools/workflows/list-available-workflows.d.ts.map +1 -0
  102. package/dist/tools/workflows/list-available-workflows.js +32 -0
  103. package/dist/tools/workflows/list-available-workflows.js.map +1 -0
  104. package/dist/tools/workflows/list-workflows.d.ts +9 -0
  105. package/dist/tools/workflows/list-workflows.d.ts.map +1 -0
  106. package/dist/tools/workflows/list-workflows.js +33 -0
  107. package/dist/tools/workflows/list-workflows.js.map +1 -0
  108. package/dist/tools/workflows/run-workflow.d.ts +9 -0
  109. package/dist/tools/workflows/run-workflow.d.ts.map +1 -0
  110. package/dist/tools/workflows/run-workflow.js +52 -0
  111. package/dist/tools/workflows/run-workflow.js.map +1 -0
  112. package/dist/tools/workflows/save-workflow.d.ts +369 -0
  113. package/dist/tools/workflows/save-workflow.d.ts.map +1 -0
  114. package/dist/tools/workflows/save-workflow.js +28 -0
  115. package/dist/tools/workflows/save-workflow.js.map +1 -0
  116. package/dist/tools/workflows/tool-ids.d.ts +15 -0
  117. package/dist/tools/workflows/tool-ids.d.ts.map +1 -0
  118. package/dist/tools/workflows/tool-ids.js +19 -0
  119. package/dist/tools/workflows/tool-ids.js.map +1 -0
  120. package/dist/utils/plans.d.ts +9 -6
  121. package/dist/utils/plans.d.ts.map +1 -1
  122. package/dist/utils/plans.js +11 -11
  123. package/dist/utils/plans.js.map +1 -1
  124. package/dist/workflows/register-primitives.d.ts +52 -0
  125. package/dist/workflows/register-primitives.d.ts.map +1 -0
  126. package/dist/workflows/register-primitives.js +39 -0
  127. package/dist/workflows/register-primitives.js.map +1 -0
  128. package/dist/workflows/service.d.ts +64 -0
  129. package/dist/workflows/service.d.ts.map +1 -0
  130. package/dist/workflows/service.js +53 -0
  131. package/dist/workflows/service.js.map +1 -0
  132. package/package.json +15 -15
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/agents/prompts/index.ts"],"sourcesContent":["/**\n * Prompt system — exports the prompt builder and mode-specific prompts.\n */\n\nexport { buildModePrompt, buildModePromptFn } from './build.js';\nexport { planModePrompt } from './plan.js';\nexport { fastModePrompt } from './fast.js';\n\nimport { buildBasePrompt } from '@mastra/core/coding-agent';\nimport type { PromptContext as BasePromptContext } from '@mastra/core/coding-agent';\nimport { hasTavilyKey } from '../../tools/index.js';\nimport { loadAgentInstructions, formatAgentInstructions, createGitRefInstructionReader } from './agent-instructions.js';\nimport { buildModePromptFn } from './build.js';\nimport { fastModePrompt } from './fast.js';\nimport { modelSpecificPrompts } from './model.js';\nimport { planModePrompt } from './plan.js';\nimport { buildToolGuidance } from './tool-guidance.js';\n\n// Extended prompt context that includes runtime information\nexport interface PromptContext extends Omit<BasePromptContext, 'toolGuidance'> {\n modeId: string;\n state?: any;\n currentDate: string;\n workingDir: string;\n}\n\nconst modePrompts: Record<string, string | ((ctx: PromptContext) => string)> = {\n build: buildModePromptFn,\n plan: planModePrompt,\n fast: fastModePrompt,\n};\n\n/**\n * Build the full system prompt for a given mode and context.\n * Combines the base prompt with mode-specific instructions.\n */\nexport function buildFullPrompt(ctx: PromptContext): string {\n // Determine whether web search tools are available\n const modelId = ctx.modelId;\n const hasWebSearch = hasTavilyKey() || (!!modelId && modelId.startsWith('anthropic/'));\n\n // Collect per-tool deny rules so guidance omits denied tools\n const deniedTools = new Set<string>();\n const permRules = ctx.state?.permissionRules as { tools?: Record<string, string> } | undefined;\n if (permRules?.tools) {\n for (const [name, policy] of Object.entries(permRules.tools)) {\n if (policy === 'deny') deniedTools.add(name);\n }\n }\n\n // Build mode-aware tool guidance\n const toolGuidance = buildToolGuidance(ctx.modeId, { hasWebSearch, deniedTools });\n\n // Map new context to base context\n const baseCtx: BasePromptContext = {\n projectPath: ctx.workingDir,\n projectName: ctx.projectName || 'unknown',\n gitBranch: ctx.gitBranch,\n platform: process.platform,\n commonBinaries: ctx.commonBinaries,\n date: ctx.currentDate,\n mode: ctx.modeId,\n modelId: ctx.modelId,\n activePlan: ctx.state?.activePlan,\n toolGuidance,\n };\n\n const base = buildBasePrompt(baseCtx);\n const entry = modePrompts[ctx.modeId] || modePrompts.build;\n const modeSpecific = (typeof entry === 'function' ? entry(ctx) : entry) ?? '';\n const modelSpecific = ctx.modelId\n ? (modelSpecificPrompts[ctx.modelId as keyof typeof modelSpecificPrompts] ?? '')\n : '';\n\n // The current task list is carried on the agent state-signal lane (see\n // TaskStateProcessor) rather than injected into the cached system prompt. This\n // keeps the prompt prefix stable across task updates (preserving prompt cache)\n // while still surviving observational-memory truncation.\n\n // Load and inject agent instructions from AGENTS.md/CLAUDE.md files.\n // Untrusted checkouts (e.g. a PR branch under review) never read\n // project-scope files off the working tree: their AGENTS.md is\n // attacker-writable and would otherwise land in the system prompt as\n // trusted configuration. When the session carries a trusted base ref, the\n // project instructions are served from that ref instead (`git show`);\n // without one, project-scope files are skipped entirely. Home-directory\n // (global) instructions belong to whoever owns the machine, so hosts that\n // run sessions for someone else opt out of them entirely.\n const configDir = ctx.state?.configDir as string | undefined;\n const untrustedCheckout = ctx.state?.untrustedCheckout === true;\n const skipGlobalInstructions = ctx.state?.skipGlobalInstructions === true;\n const baseRef = typeof ctx.state?.baseRef === 'string' ? ctx.state.baseRef : undefined;\n const projectReader = untrustedCheckout\n ? baseRef\n ? createGitRefInstructionReader(ctx.workingDir, baseRef)\n : { exists: () => false, read: () => '' }\n : undefined;\n const instructionSources = loadAgentInstructions(ctx.workingDir, configDir, projectReader, {\n skipGlobal: skipGlobalInstructions,\n });\n const instructionsSection = formatAgentInstructions(instructionSources);\n\n const sections = [base, instructionsSection.trim(), modelSpecific.trim(), modeSpecific.trim()].filter(Boolean);\n\n return sections.join('\\n\\n');\n}\n"],"mappings":";;;;;;;;;;AA0BA,MAAM,cAAyE;CAC7E,OAAO;CACP,MAAM;CACN,MAAM;AACR;;;;;AAMA,SAAgB,gBAAgB,KAA4B;CAE1D,MAAM,UAAU,IAAI;CACpB,MAAM,eAAe,aAAa,KAAM,CAAC,CAAC,WAAW,QAAQ,WAAW,YAAY;CAGpF,MAAM,8BAAc,IAAI,IAAY;CACpC,MAAM,YAAY,IAAI,OAAO;CAC7B,IAAI,WAAW,OACR;OAAA,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,UAAU,KAAK,GACzD,IAAI,WAAW,QAAQ,YAAY,IAAI,IAAI;CAAA;CAK/C,MAAM,eAAe,kBAAkB,IAAI,QAAQ;EAAE;EAAc;CAAY,CAAC;CAgBhF,MAAM,OAAO,gBAAgB;EAZ3B,aAAa,IAAI;EACjB,aAAa,IAAI,eAAe;EAChC,WAAW,IAAI;EACf,UAAU,QAAQ;EAClB,gBAAgB,IAAI;EACpB,MAAM,IAAI;EACV,MAAM,IAAI;EACV,SAAS,IAAI;EACb,YAAY,IAAI,OAAO;EACvB;CAGiC,CAAC;CACpC,MAAM,QAAQ,YAAY,IAAI,WAAW,YAAY;CACrD,MAAM,gBAAgB,OAAO,UAAU,aAAa,MAAM,GAAG,IAAI,UAAU;CAC3E,MAAM,gBAAgB,IAAI,UACrB,qBAAqB,IAAI,YAAiD,KAC3E;CAgBJ,MAAM,YAAY,IAAI,OAAO;CAC7B,MAAM,oBAAoB,IAAI,OAAO,sBAAsB;CAC3D,MAAM,yBAAyB,IAAI,OAAO,2BAA2B;CACrE,MAAM,UAAU,OAAO,IAAI,OAAO,YAAY,WAAW,IAAI,MAAM,UAAU,KAAA;CAC7E,MAAM,gBAAgB,oBAClB,UACE,8BAA8B,IAAI,YAAY,OAAO,IACrD;EAAE,cAAc;EAAO,YAAY;CAAG,IACxC,KAAA;CAQJ,OAFiB;EAAC;EAFU,wBAHD,sBAAsB,IAAI,YAAY,WAAW,eAAe,EACzF,YAAY,uBACd,CACqE,CAE3B,CAAC,CAAC,KAAK;EAAG,cAAc,KAAK;EAAG,aAAa,KAAK;CAAC,CAAC,CAAC,OAAO,OAExF,CAAC,CAAC,KAAK,MAAM;AAC7B"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/agents/prompts/index.ts"],"sourcesContent":["/**\n * Prompt system — exports the prompt builder and mode-specific prompts.\n */\n\nexport { buildModePrompt, buildModePromptFn } from './build.js';\nexport { planModePrompt } from './plan.js';\nexport { fastModePrompt } from './fast.js';\n\nimport { buildBasePrompt } from '@mastra/core/coding-agent';\nimport type { PromptContext as BasePromptContext } from '@mastra/core/coding-agent';\nimport { hasTavilyKey } from '../../tools/index.js';\nimport { getLocalPlansRelativeDir } from '../../utils/plans.js';\nimport { loadAgentInstructions, formatAgentInstructions, createGitRefInstructionReader } from './agent-instructions.js';\nimport { buildModePromptFn } from './build.js';\nimport { fastModePrompt } from './fast.js';\nimport { modelSpecificPrompts } from './model.js';\nimport { planModePrompt } from './plan.js';\nimport { buildToolGuidance } from './tool-guidance.js';\n\n// Extended prompt context that includes runtime information\nexport interface PromptContext extends Omit<BasePromptContext, 'toolGuidance'> {\n modeId: string;\n state?: any;\n currentDate: string;\n workingDir: string;\n}\n\nconst modePrompts: Record<string, string | ((ctx: PromptContext) => string)> = {\n build: buildModePromptFn,\n plan: planModePrompt,\n fast: fastModePrompt,\n};\n\n/**\n * Build the full system prompt for a given mode and context.\n * Combines the base prompt with mode-specific instructions.\n */\nexport function buildFullPrompt(ctx: PromptContext): string {\n // Determine whether web search tools are available\n const modelId = ctx.modelId;\n const hasWebSearch = hasTavilyKey() || (!!modelId && modelId.startsWith('anthropic/'));\n\n // Collect per-tool deny rules so guidance omits denied tools\n const deniedTools = new Set<string>();\n const permRules = ctx.state?.permissionRules as { tools?: Record<string, string> } | undefined;\n if (permRules?.tools) {\n for (const [name, policy] of Object.entries(permRules.tools)) {\n if (policy === 'deny') deniedTools.add(name);\n }\n }\n\n // Build mode-aware tool guidance\n const factoryProjectId = typeof ctx.state?.factoryProjectId === 'string' ? ctx.state.factoryProjectId : undefined;\n const toolGuidance = buildToolGuidance(ctx.modeId, {\n hasWebSearch,\n deniedTools,\n plansDir: getLocalPlansRelativeDir({ factoryProjectId }),\n });\n\n // Map new context to base context\n const baseCtx: BasePromptContext = {\n projectPath: ctx.workingDir,\n projectName: ctx.projectName || 'unknown',\n gitBranch: ctx.gitBranch,\n platform: process.platform,\n commonBinaries: ctx.commonBinaries,\n date: ctx.currentDate,\n mode: ctx.modeId,\n modelId: ctx.modelId,\n activePlan: ctx.state?.activePlan,\n toolGuidance,\n };\n\n const base = buildBasePrompt(baseCtx);\n const entry = modePrompts[ctx.modeId] || modePrompts.build;\n const modeSpecific = (typeof entry === 'function' ? entry(ctx) : entry) ?? '';\n const modelSpecific = ctx.modelId\n ? (modelSpecificPrompts[ctx.modelId as keyof typeof modelSpecificPrompts] ?? '')\n : '';\n\n // The current task list is carried on the agent state-signal lane (see\n // TaskStateProcessor) rather than injected into the cached system prompt. This\n // keeps the prompt prefix stable across task updates (preserving prompt cache)\n // while still surviving observational-memory truncation.\n\n // Load and inject agent instructions from AGENTS.md/CLAUDE.md files.\n // Untrusted checkouts (e.g. a PR branch under review) never read\n // project-scope files off the working tree: their AGENTS.md is\n // attacker-writable and would otherwise land in the system prompt as\n // trusted configuration. When the session carries a trusted base ref, the\n // project instructions are served from that ref instead (`git show`);\n // without one, project-scope files are skipped entirely. Home-directory\n // (global) instructions belong to whoever owns the machine, so hosts that\n // run sessions for someone else opt out of them entirely.\n const configDir = ctx.state?.configDir as string | undefined;\n const untrustedCheckout = ctx.state?.untrustedCheckout === true;\n const skipGlobalInstructions = ctx.state?.skipGlobalInstructions === true;\n const baseRef = typeof ctx.state?.baseRef === 'string' ? ctx.state.baseRef : undefined;\n const projectReader = untrustedCheckout\n ? baseRef\n ? createGitRefInstructionReader(ctx.workingDir, baseRef)\n : { exists: () => false, read: () => '' }\n : undefined;\n const instructionSources = loadAgentInstructions(ctx.workingDir, configDir, projectReader, {\n skipGlobal: skipGlobalInstructions,\n });\n const instructionsSection = formatAgentInstructions(instructionSources);\n\n const sections = [base, instructionsSection.trim(), modelSpecific.trim(), modeSpecific.trim()].filter(Boolean);\n\n return sections.join('\\n\\n');\n}\n"],"mappings":";;;;;;;;;;;AA2BA,MAAM,cAAyE;CAC7E,OAAO;CACP,MAAM;CACN,MAAM;AACR;;;;;AAMA,SAAgB,gBAAgB,KAA4B;CAE1D,MAAM,UAAU,IAAI;CACpB,MAAM,eAAe,aAAa,KAAM,CAAC,CAAC,WAAW,QAAQ,WAAW,YAAY;CAGpF,MAAM,8BAAc,IAAI,IAAY;CACpC,MAAM,YAAY,IAAI,OAAO;CAC7B,IAAI,WAAW,OACR;OAAA,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,UAAU,KAAK,GACzD,IAAI,WAAW,QAAQ,YAAY,IAAI,IAAI;CAAA;CAK/C,MAAM,mBAAmB,OAAO,IAAI,OAAO,qBAAqB,WAAW,IAAI,MAAM,mBAAmB,KAAA;CACxG,MAAM,eAAe,kBAAkB,IAAI,QAAQ;EACjD;EACA;EACA,UAAU,yBAAyB,EAAE,iBAAiB,CAAC;CACzD,CAAC;CAgBD,MAAM,OAAO,gBAAgB;EAZ3B,aAAa,IAAI;EACjB,aAAa,IAAI,eAAe;EAChC,WAAW,IAAI;EACf,UAAU,QAAQ;EAClB,gBAAgB,IAAI;EACpB,MAAM,IAAI;EACV,MAAM,IAAI;EACV,SAAS,IAAI;EACb,YAAY,IAAI,OAAO;EACvB;CAGiC,CAAC;CACpC,MAAM,QAAQ,YAAY,IAAI,WAAW,YAAY;CACrD,MAAM,gBAAgB,OAAO,UAAU,aAAa,MAAM,GAAG,IAAI,UAAU;CAC3E,MAAM,gBAAgB,IAAI,UACrB,qBAAqB,IAAI,YAAiD,KAC3E;CAgBJ,MAAM,YAAY,IAAI,OAAO;CAC7B,MAAM,oBAAoB,IAAI,OAAO,sBAAsB;CAC3D,MAAM,yBAAyB,IAAI,OAAO,2BAA2B;CACrE,MAAM,UAAU,OAAO,IAAI,OAAO,YAAY,WAAW,IAAI,MAAM,UAAU,KAAA;CAC7E,MAAM,gBAAgB,oBAClB,UACE,8BAA8B,IAAI,YAAY,OAAO,IACrD;EAAE,cAAc;EAAO,YAAY;CAAG,IACxC,KAAA;CAQJ,OAFiB;EAAC;EAFU,wBAHD,sBAAsB,IAAI,YAAY,WAAW,eAAe,EACzF,YAAY,uBACd,CACqE,CAE3B,CAAC,CAAC,KAAK;EAAG,cAAc,KAAK;EAAG,aAAa,KAAK;CAAC,CAAC,CAAC,OAAO,OAExF,CAAC,CAAC,KAAK,MAAM;AAC7B"}
@@ -1,6 +1,6 @@
1
1
  interface PlanPromptContext {
2
2
  state?: Record<string, unknown>;
3
3
  }
4
- export declare function planModePrompt(_ctx: PlanPromptContext): string;
4
+ export declare function planModePrompt(ctx: PlanPromptContext): string;
5
5
  export {};
6
6
  //# sourceMappingURL=plan.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/agents/prompts/plan.ts"],"names":[],"mappings":"AAKA,UAAU,iBAAiB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAsG9D"}
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/agents/prompts/plan.ts"],"names":[],"mappings":"AAKA,UAAU,iBAAiB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM,CAuG7D"}
@@ -3,8 +3,8 @@ import { getLocalPlansRelativeDir } from "../../utils/plans.js";
3
3
  /**
4
4
  * Plan mode prompt — read-only exploration and planning.
5
5
  */
6
- function planModePrompt(_ctx) {
7
- const plansDir = getLocalPlansRelativeDir();
6
+ function planModePrompt(ctx) {
7
+ const plansDir = getLocalPlansRelativeDir({ factoryProjectId: typeof ctx.state?.factoryProjectId === "string" ? ctx.state.factoryProjectId : void 0 });
8
8
  const examplePath = `${plansDir}/add-dark-mode.md`;
9
9
  return `
10
10
  # Plan Mode — READ-ONLY (except plan files)
@@ -1 +1 @@
1
- {"version":3,"file":"plan.js","names":[],"sources":["../../../src/agents/prompts/plan.ts"],"sourcesContent":["/**\n * Plan mode prompt — read-only exploration and planning.\n */\nimport { getLocalPlansRelativeDir } from '../../utils/plans.js';\n\ninterface PlanPromptContext {\n state?: Record<string, unknown>;\n}\n\nexport function planModePrompt(_ctx: PlanPromptContext): string {\n const plansDir = getLocalPlansRelativeDir();\n const examplePath = `${plansDir}/add-dark-mode.md`;\n\n return `\n# Plan Mode — READ-ONLY (except plan files)\n\nYou are in PLAN mode. Your job is to explore the codebase and design an implementation plan — NOT to make changes to the project.\n\n## CRITICAL: Read-Only Mode (project files)\n\nThis mode is **read-only for project files**. You must NOT modify the project.\n\n- Do NOT modify, create, or delete project files\n- Do NOT run commands that change state (no git commit, no npm install, no file creation)\n- Do NOT run build commands, tests, or scripts that have side effects\n\nThe ONE exception is plan files: you CAN create and edit markdown files inside \\`${plansDir}/\\` (e.g. \\`${examplePath}\\`). You may NOT write anywhere else.\n\nIf the user asks you to make changes while in Plan mode, explain that you're in read-only mode and they should switch to Build mode (\\`/mode build\\`) first.\n\n## Exploration Strategy\n\nBefore writing any plan, build a mental model of the codebase:\n1. Start with the directory structure (\\`view\\` on the project root or relevant subdirectory).\n2. Find the relevant entry points and core files using \\`search_content\\` and \\`find_files\\`.\n3. Read the actual code — don't assume based on file names alone.\n4. Trace data flow: where does input come from, how is it transformed, where does it go?\n5. Identify existing patterns the codebase uses (naming, structure, error handling, testing).\n\n## Goal-Ready Plans\n\nThe submit_plan approval UI can let the user approve the plan normally or start it as a persistent goal. Write plans so they can be carried out as a goal if the user chooses that option:\n- Make the desired outcome explicit and verifiable.\n- Break work into ordered, actionable steps that can be executed autonomously.\n- Include constraints, risks, blockers, and decision points that may require user input.\n- Include concrete verification criteria so the goal judge can tell when the work is done.\n\n## Your Plan Output\n\nProduce a clear, step-by-step plan with this structure:\n\n### Overview\nOne paragraph: what the change does and why.\n\n### Complexity Estimate\n- **Size**: Small (1-2 files) / Medium (3-5 files) / Large (6+ files)\n- **Risk**: Low (additive, no breaking changes) / Medium (modifies existing behavior) / High (architectural, affects many consumers)\n- **Dependencies**: List any new packages, external services, or migration steps needed.\n\n### Steps\nFor each step:\n1. **File**: path to create or modify\n2. **Change**: what to add/modify/remove, with enough specificity to implement directly\n3. **Why**: brief rationale connecting this step to the overall goal\n\n### Verification\n- What tests to run\n- What to check manually\n- What could go wrong\n\n## Plan File Workflow\n\nWrite each plan to its own markdown file under \\`${plansDir}/\\` (e.g. \\`${examplePath}\\`). Start the file with a \\`# Title\\` heading describing the plan.\n\n1. **First submission**: Write your plan to a file under \\`${plansDir}/\\` using \\`write_file\\`, then call \\`submit_plan\\` with the \\`path\\` to that file.\n2. **Reading**: Use \\`view\\` to read a plan file.\n3. **Editing**: Use \\`string_replace_lsp\\` for targeted edits to specific sections.\n\n**Reuse the same file while you keep iterating on the same plan.** Only create a NEW file when you're starting a genuinely different plan — that keeps each plan available to look back at and keeps revision diffs meaningful.\n\n## IMMEDIATE ACTION: Write plan file, then call submit_plan\n\nAs soon as your plan is complete:\n1. Write it to a file under \\`${plansDir}/\\` using \\`write_file\\`\n2. Call \\`submit_plan\\` with the \\`path\\` to that file\n\n**CRITICAL:** Do NOT generate a long text response describing your plan. The plan content belongs in the plan file, not in your text output or the \\`submit_plan\\` arguments.\n\n\\`\\`\\`javascript\nsubmit_plan({\n path: \"${examplePath}\"\n})\n\\`\\`\\`\n\nThe user will see the plan rendered inline and can:\n- **Approve** — automatically switches to Build mode for implementation\n- **Start as goal** — approves the plan and enters goal mode so the agent keeps working toward the plan until judged complete, paused, or waiting for user input\n- **Request changes** — rejects the plan; the agent stops immediately and the user provides revision feedback in their next chat message\n\n## Revision Workflow\n\nIf the user requests changes, you will be stopped immediately. Wait for their next message — it will contain their revision feedback. When you receive it:\n1. Use \\`view\\` to read the SAME plan file\n2. Use \\`string_replace_lsp\\` to make targeted edits based on feedback\n3. Use \\`view\\` to re-read the updated file\n4. Call \\`submit_plan\\` again with the same \\`path\\` — editing the file alone does NOT resubmit it\n\nThe user will see a diff of what changed between the previous and revised plan. Use \\`string_replace_lsp\\` for targeted edits so the diff is clear and meaningful — do NOT rewrite the entire plan from scratch for small changes, and do NOT move the plan to a new file for a revision.\n\nDo NOT start implementing until the plan is approved.\n`;\n}\n"],"mappings":";;;;;AASA,SAAgB,eAAe,MAAiC;CAC9D,MAAM,WAAW,yBAAyB;CAC1C,MAAM,cAAc,GAAG,SAAS;CAEhC,OAAO;;;;;;;;;;;;;mFAa0E,SAAS,cAAc,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDA8CnE,SAAS,cAAc,YAAY;;6DAEzB,SAAS;;;;;;;;;gCAStC,SAAS;;;;;;;WAO9B,YAAY;;;;;;;;;;;;;;;;;;;;;AAqBvB"}
1
+ {"version":3,"file":"plan.js","names":[],"sources":["../../../src/agents/prompts/plan.ts"],"sourcesContent":["/**\n * Plan mode prompt — read-only exploration and planning.\n */\nimport { getLocalPlansRelativeDir } from '../../utils/plans.js';\n\ninterface PlanPromptContext {\n state?: Record<string, unknown>;\n}\n\nexport function planModePrompt(ctx: PlanPromptContext): string {\n const factoryProjectId = typeof ctx.state?.factoryProjectId === 'string' ? ctx.state.factoryProjectId : undefined;\n const plansDir = getLocalPlansRelativeDir({ factoryProjectId });\n const examplePath = `${plansDir}/add-dark-mode.md`;\n\n return `\n# Plan Mode — READ-ONLY (except plan files)\n\nYou are in PLAN mode. Your job is to explore the codebase and design an implementation plan — NOT to make changes to the project.\n\n## CRITICAL: Read-Only Mode (project files)\n\nThis mode is **read-only for project files**. You must NOT modify the project.\n\n- Do NOT modify, create, or delete project files\n- Do NOT run commands that change state (no git commit, no npm install, no file creation)\n- Do NOT run build commands, tests, or scripts that have side effects\n\nThe ONE exception is plan files: you CAN create and edit markdown files inside \\`${plansDir}/\\` (e.g. \\`${examplePath}\\`). You may NOT write anywhere else.\n\nIf the user asks you to make changes while in Plan mode, explain that you're in read-only mode and they should switch to Build mode (\\`/mode build\\`) first.\n\n## Exploration Strategy\n\nBefore writing any plan, build a mental model of the codebase:\n1. Start with the directory structure (\\`view\\` on the project root or relevant subdirectory).\n2. Find the relevant entry points and core files using \\`search_content\\` and \\`find_files\\`.\n3. Read the actual code — don't assume based on file names alone.\n4. Trace data flow: where does input come from, how is it transformed, where does it go?\n5. Identify existing patterns the codebase uses (naming, structure, error handling, testing).\n\n## Goal-Ready Plans\n\nThe submit_plan approval UI can let the user approve the plan normally or start it as a persistent goal. Write plans so they can be carried out as a goal if the user chooses that option:\n- Make the desired outcome explicit and verifiable.\n- Break work into ordered, actionable steps that can be executed autonomously.\n- Include constraints, risks, blockers, and decision points that may require user input.\n- Include concrete verification criteria so the goal judge can tell when the work is done.\n\n## Your Plan Output\n\nProduce a clear, step-by-step plan with this structure:\n\n### Overview\nOne paragraph: what the change does and why.\n\n### Complexity Estimate\n- **Size**: Small (1-2 files) / Medium (3-5 files) / Large (6+ files)\n- **Risk**: Low (additive, no breaking changes) / Medium (modifies existing behavior) / High (architectural, affects many consumers)\n- **Dependencies**: List any new packages, external services, or migration steps needed.\n\n### Steps\nFor each step:\n1. **File**: path to create or modify\n2. **Change**: what to add/modify/remove, with enough specificity to implement directly\n3. **Why**: brief rationale connecting this step to the overall goal\n\n### Verification\n- What tests to run\n- What to check manually\n- What could go wrong\n\n## Plan File Workflow\n\nWrite each plan to its own markdown file under \\`${plansDir}/\\` (e.g. \\`${examplePath}\\`). Start the file with a \\`# Title\\` heading describing the plan.\n\n1. **First submission**: Write your plan to a file under \\`${plansDir}/\\` using \\`write_file\\`, then call \\`submit_plan\\` with the \\`path\\` to that file.\n2. **Reading**: Use \\`view\\` to read a plan file.\n3. **Editing**: Use \\`string_replace_lsp\\` for targeted edits to specific sections.\n\n**Reuse the same file while you keep iterating on the same plan.** Only create a NEW file when you're starting a genuinely different plan — that keeps each plan available to look back at and keeps revision diffs meaningful.\n\n## IMMEDIATE ACTION: Write plan file, then call submit_plan\n\nAs soon as your plan is complete:\n1. Write it to a file under \\`${plansDir}/\\` using \\`write_file\\`\n2. Call \\`submit_plan\\` with the \\`path\\` to that file\n\n**CRITICAL:** Do NOT generate a long text response describing your plan. The plan content belongs in the plan file, not in your text output or the \\`submit_plan\\` arguments.\n\n\\`\\`\\`javascript\nsubmit_plan({\n path: \"${examplePath}\"\n})\n\\`\\`\\`\n\nThe user will see the plan rendered inline and can:\n- **Approve** — automatically switches to Build mode for implementation\n- **Start as goal** — approves the plan and enters goal mode so the agent keeps working toward the plan until judged complete, paused, or waiting for user input\n- **Request changes** — rejects the plan; the agent stops immediately and the user provides revision feedback in their next chat message\n\n## Revision Workflow\n\nIf the user requests changes, you will be stopped immediately. Wait for their next message — it will contain their revision feedback. When you receive it:\n1. Use \\`view\\` to read the SAME plan file\n2. Use \\`string_replace_lsp\\` to make targeted edits based on feedback\n3. Use \\`view\\` to re-read the updated file\n4. Call \\`submit_plan\\` again with the same \\`path\\` — editing the file alone does NOT resubmit it\n\nThe user will see a diff of what changed between the previous and revised plan. Use \\`string_replace_lsp\\` for targeted edits so the diff is clear and meaningful — do NOT rewrite the entire plan from scratch for small changes, and do NOT move the plan to a new file for a revision.\n\nDo NOT start implementing until the plan is approved.\n`;\n}\n"],"mappings":";;;;;AASA,SAAgB,eAAe,KAAgC;CAE7D,MAAM,WAAW,yBAAyB,EAAE,kBADnB,OAAO,IAAI,OAAO,qBAAqB,WAAW,IAAI,MAAM,mBAAmB,KAAA,EAC3C,CAAC;CAC9D,MAAM,cAAc,GAAG,SAAS;CAEhC,OAAO;;;;;;;;;;;;;mFAa0E,SAAS,cAAc,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDA8CnE,SAAS,cAAc,YAAY;;6DAEzB,SAAS;;;;;;;;;gCAStC,SAAS;;;;;;;WAO9B,YAAY;;;;;;;;;;;;;;;;;;;;;AAqBvB"}
@@ -7,6 +7,8 @@ interface ToolGuidanceOptions {
7
7
  hasWebSearch?: boolean;
8
8
  /** Tool names that have been denied — omit their guidance sections. */
9
9
  deniedTools?: Set<string>;
10
+ /** Workspace-relative directory where plan mode can write plans. */
11
+ plansDir?: string;
10
12
  }
11
13
  export declare function buildToolGuidance(modeId: string, options?: ToolGuidanceOptions): string;
12
14
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"tool-guidance.d.ts","sourceRoot":"","sources":["../../../src/agents/prompts/tool-guidance.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,UAAU,mBAAmB;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CA+N3F"}
1
+ {"version":3,"file":"tool-guidance.d.ts","sourceRoot":"","sources":["../../../src/agents/prompts/tool-guidance.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,UAAU,mBAAmB;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAgO3F"}
@@ -7,6 +7,7 @@ import { MC_TOOLS } from "../../tool-names.js";
7
7
  */
8
8
  function buildToolGuidance(modeId, options = {}) {
9
9
  const denied = options.deniedTools ?? /* @__PURE__ */ new Set();
10
+ const plansDir = options.plansDir ?? ".mastracode/plans";
10
11
  const sections = [];
11
12
  sections.push(`# Tool Usage Rules
12
13
 
@@ -130,9 +131,9 @@ ${patchToolGuidance}
130
131
  - Call this tool when your plan is complete. Do NOT just describe your plan in text — you MUST call this tool.
131
132
  - The plan will be rendered as markdown and the user can approve, reject, or request changes.
132
133
  - On approval, the system automatically switches to the default mode so you can implement.
133
- - Takes one argument: \`path\` (the plan markdown file you wrote under \`.mastracode/plans/\`). Do NOT pass the plan body — it lives in the file.`);
134
+ - Takes one argument: \`path\` (the plan markdown file you wrote under \`${plansDir}/\`). Do NOT pass the plan body — it lives in the file.`);
134
135
  if (modeId === "plan") sections.push(`
135
- **Plan file access** — Your plan lives in a markdown file under \`.mastracode/plans/\` (e.g. \`add-dark-mode-toggle.md\`)
136
+ **Plan file access** — Your plan lives in a markdown file under \`${plansDir}/\` (e.g. \`add-dark-mode-toggle.md\`)
136
137
  - Use \`write_file\` to create the plan file, \`view\` to read it, and \`string_replace_lsp\` for targeted edits.
137
138
  - On first submission: write the plan to the file, then call \`submit_plan\` with its \`path\`.
138
139
  - On revision: read the existing file, edit specific sections, re-read, then call \`submit_plan\` with the same \`path\`.
@@ -1 +1 @@
1
- {"version":3,"file":"tool-guidance.js","names":[],"sources":["../../../src/agents/prompts/tool-guidance.ts"],"sourcesContent":["/**\n * Mode-specific tool behavioral guidance.\n * Generates tool usage instructions that match the actual registered tool names\n * and are scoped to what's available in the current mode.\n */\n\nimport { MC_TOOLS } from '../../tool-names.js';\n\ninterface ToolGuidanceOptions {\n hasWebSearch?: boolean;\n /** Tool names that have been denied — omit their guidance sections. */\n deniedTools?: Set<string>;\n}\n\nexport function buildToolGuidance(modeId: string, options: ToolGuidanceOptions = {}): string {\n const denied = options.deniedTools ?? new Set<string>();\n const sections: string[] = [];\n\n sections.push(`# Tool Usage Rules\n\nIMPORTANT: You can ONLY call tools by their exact registered names listed below. Shell commands like \\`git\\`, \\`npm\\`, \\`ls\\`, etc. are NOT tools — they must be run via the \\`execute_command\\` tool.\n\nYou have access to the following tools. Use the RIGHT tool for the job:`);\n\n // --- Read tools (all modes) ---\n\n const readTools: string[] = [];\n\n if (!denied.has(MC_TOOLS.VIEW)) {\n readTools.push(`\n**${MC_TOOLS.VIEW}** — Read file contents\n- Use this to read files before editing them. NEVER propose changes to code you haven't read.\n- Use \\`offset\\` (1-indexed start line) and \\`limit\\` (number of lines) for large files.\n- Example: Read lines 50-100: \\`{ path: \"src/big-file.ts\", offset: 50, limit: 51 }\\`\n- To list directories, use \\`${MC_TOOLS.FIND_FILES}\\` instead.`);\n }\n\n if (!denied.has(MC_TOOLS.SEARCH_CONTENT)) {\n readTools.push(`\n**${MC_TOOLS.SEARCH_CONTENT}** — Search file contents using regex\n- Preferred for content search (finding functions, variables, error messages, imports, etc.)\n- Use \\`path\\` to filter by directory or glob pattern. Supports \\`contextLines\\`, \\`caseSensitive\\`, and \\`maxCount\\`.\n- Example: Find a function: \\`{ pattern: \"function handleSubmit\", path: \"**/*.ts\" }\\`\n- Example: Find imports: \\`{ pattern: \"from ['\\\\\"\\\\]express['\\\\\"\\\\]\", path: \"**/*.ts\" }\\`\n- Respects .gitignore by default.`);\n }\n\n if (!denied.has(MC_TOOLS.FIND_FILES)) {\n readTools.push(`\n**${MC_TOOLS.FIND_FILES}** — List files and directories as a tree\n- Preferred for exploring project structure and finding files by pattern.\n- Returns tree-style output. Respects .gitignore by default.\n- Example: List project root: \\`{ path: \"./\" }\\`\n- Example: Find test files: \\`{ path: \"./src\", pattern: \"**/*.test.ts\" }\\`\n- Example: Find config files: \\`{ pattern: \"*.config.{js,ts,json}\" }\\``);\n }\n\n if (!denied.has(MC_TOOLS.EXECUTE_COMMAND)) {\n readTools.push(`\n**${MC_TOOLS.EXECUTE_COMMAND}** — Run shell commands\n- Use for: git, npm/pnpm, docker, build tools, test runners, and other terminal operations.\n- 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}).\n- Commands have a 30-second default timeout. Use \\`timeout\\` for longer commands, \\`cwd\\` for working directory.\n- Use the \\`tail\\` parameter or pipe to \\`| tail -N\\` to limit output — 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.\n- Good: Run independent commands in parallel when possible.\n- Bad: Running \\`cat file.txt\\` — use the ${MC_TOOLS.VIEW} tool instead.`);\n }\n\n if (!denied.has(MC_TOOLS.LSP_INSPECT)) {\n readTools.push(`\n**${MC_TOOLS.LSP_INSPECT}** — Inspect code using Language Server Protocol\n- Use this for type information, hover docs, go-to-definition, and finding implementations for a symbol.\n- Best when you already know the file and line and need semantic code intelligence rather than raw file contents.\n- Input: \\`path\\` (absolute file path), \\`line\\` (1-indexed line number), \\`match\\` (the exact line content with exactly one \\`<<<\\` cursor marker).\n- Output includes: \\`hover\\`, \\`definition\\` (compact location with preview), and \\`implementation\\` (compact usage/implementation locations).\n- Example: \\`{ path: \"/abs/path/src/foo.ts\", line: 10, match: \"const foo = <<<bar()\" }\\` — inspect the symbol at the \\`<<<\\` position.\n- Use \\`${MC_TOOLS.VIEW}\\` when you need to read the implementation or surrounding code.\n- Use \\`${MC_TOOLS.SEARCH_CONTENT}\\` or \\`${MC_TOOLS.FIND_FILES}\\` first if you do not yet know where the symbol is.`);\n }\n\n if (!denied.has(MC_TOOLS.NOTIFICATION_INBOX)) {\n readTools.push(`\n**${MC_TOOLS.NOTIFICATION_INBOX}** — Inspect and manage notification inbox records\n- Use this when a \\`<notification-summary>\\` says pending notifications exist.\n- Use \\`{ \"action\": \"list\", \"status\": \"pending\" }\\` or \\`{ \"action\": \"search\", \"query\": \"...\" }\\` to find notification records for the current thread.\n- Use \\`read\\` to deliver unread notification signals into the chat and mark them seen; the tool result summarizes the count instead of exposing notification contents.\n- Use \\`dismiss\\` or \\`archive\\` only when the user asks or the notification is no longer relevant.`);\n }\n\n if (readTools.length > 0) {\n sections.push(readTools.join('\\n'));\n }\n\n // --- Write/edit tools (build & fast only) ---\n\n if (modeId !== 'plan') {\n const writeTools: string[] = [];\n\n if (!denied.has(MC_TOOLS.STRING_REPLACE_LSP)) {\n writeTools.push(`\n**${MC_TOOLS.STRING_REPLACE_LSP}** — Edit files by replacing exact text\n- You MUST read a file with \\`${MC_TOOLS.VIEW}\\` before editing it.\n- \\`old_string\\` must be an exact match of existing text in the file.\n- Provide enough surrounding context in \\`old_string\\` to make it unique.\n- Use \\`replace_all: true\\` to replace all occurrences (default: false, requires unique match).\n- For creating new files, use \\`${MC_TOOLS.WRITE_FILE}\\` instead.\n- Good: Include 2-3 lines of surrounding context to ensure uniqueness.\n- Bad: Using just \\`return true;\\` — too common, will match multiple places.`);\n }\n\n if (!denied.has(MC_TOOLS.WRITE_FILE)) {\n writeTools.push(`\n**${MC_TOOLS.WRITE_FILE}** — Create new files or overwrite existing ones\n- Use this to create new files.\n- If overwriting an existing file, you MUST have read it first with \\`${MC_TOOLS.VIEW}\\`.\n- Prefer editing existing files over creating new ones.`);\n }\n\n if (writeTools.length > 0) {\n sections.push(writeTools.join('\\n'));\n }\n }\n\n // --- Web tools (all modes, conditionally available) ---\n\n if (options.hasWebSearch) {\n const webTools: string[] = [];\n if (!denied.has('web_search')) webTools.push('**web_search**');\n if (!denied.has('web_extract')) webTools.push('**web_extract**');\n if (webTools.length > 0) {\n sections.push(`\n${webTools.join(' / ')} — Search the web / extract page content\n- Use for looking up documentation, error messages, package APIs.`);\n }\n }\n\n // --- Task management tools (all modes) ---\n\n const taskTools: string[] = [];\n const canUpdateTask = !denied.has('task_update');\n const canCompleteTask = !denied.has('task_complete');\n const canCheckTasks = !denied.has('task_check');\n const canWriteTasks = !denied.has('task_write');\n const patchToolGuidance =\n canUpdateTask && canCompleteTask\n ? '- Prefer task_update or task_complete when changing one existing task.'\n : canUpdateTask\n ? '- Prefer task_update when changing one existing task.'\n : canCompleteTask\n ? '- Prefer task_complete when marking one existing task completed.'\n : '- Use task_write with the full task list when changing existing tasks.';\n\n if (canWriteTasks) {\n taskTools.push(`\n**task_write** — Track tasks for complex multi-step work\n- Use when a task requires 3 or more distinct steps or actions.\n- Use task_write to create the initial task list or replace the whole list after replanning.\n- Each task has: id (stable identifier), content (imperative form), status (pending, in_progress, or completed), activeForm (present continuous form shown during execution).\n- Keep task IDs stable across updates. If you omit IDs, the tool result returns generated IDs.\n${patchToolGuidance}\n- Mark tasks \\`in_progress\\` BEFORE starting work. Only ONE task should be \\`in_progress\\` at a time.\n- Mark tasks \\`completed\\` IMMEDIATELY after finishing each task. Do not batch completions.`);\n }\n\n if (canUpdateTask) {\n taskTools.push(`\n**task_update** — Patch one tracked task by ID\n- Use this for targeted changes to one existing task.\n- Provide the task ID and only the fields that changed: content, status, or activeForm.`);\n }\n\n if (canCompleteTask) {\n const idSource = canCheckTasks\n ? 'Use task_check if you need the current IDs before completing a task.'\n : canWriteTasks\n ? 'Use IDs returned by task_write.'\n : 'Use only task IDs already visible in the current task list.';\n taskTools.push(`\n**task_complete** — Mark one tracked task completed by ID\n- Use this immediately after finishing a tracked task.\n- ${idSource}`);\n }\n\n if (canCheckTasks) {\n taskTools.push(`\n**task_check** — Check completion status of tasks\n- Use this BEFORE finishing tracked work to verify all tasks are completed.\n- Returns a readable status summary plus structured fields: tasks, summary, incompleteTasks, and isError.\n- summary includes total, completed, inProgress, pending, incomplete, hasTasks, and allCompleted.\n- Use summary.allCompleted to decide whether tracked work is complete; if summary.hasTasks is false, no task list is currently tracked.\n- If any tasks remain incomplete, continue working on them.\n- IMPORTANT: Always check task completion before ending work on a complex task.`);\n }\n\n if (!denied.has('ask_user')) {\n taskTools.push(`\n**ask_user** — Ask the user a structured question\n- Use when you need clarification, want to validate assumptions, or need the user to make a decision.\n- Provide clear, specific questions. End with a question mark.\n- Include options (2-4 choices) for structured decisions. Omit options for open-ended questions.\n- Don't use this for simple yes/no — just ask in your text response.`);\n }\n\n if (taskTools.length > 0) {\n sections.push(taskTools.join('\\n'));\n }\n\n // --- Plan tools (plan mode) ---\n\n if (modeId === 'plan' && !denied.has('submit_plan')) {\n sections.push(`\n**submit_plan** — Submit a completed implementation plan for user review\n- Call this tool when your plan is complete. Do NOT just describe your plan in text — you MUST call this tool.\n- The plan will be rendered as markdown and the user can approve, reject, or request changes.\n- On approval, the system automatically switches to the default mode so you can implement.\n- Takes one argument: \\`path\\` (the plan markdown file you wrote under \\`.mastracode/plans/\\`). Do NOT pass the plan body — it lives in the file.`);\n }\n\n if (modeId === 'plan') {\n sections.push(`\n**Plan file access** — Your plan lives in a markdown file under \\`.mastracode/plans/\\` (e.g. \\`add-dark-mode-toggle.md\\`)\n- Use \\`write_file\\` to create the plan file, \\`view\\` to read it, and \\`string_replace_lsp\\` for targeted edits.\n- On first submission: write the plan to the file, then call \\`submit_plan\\` with its \\`path\\`.\n- On revision: read the existing file, edit specific sections, re-read, then call \\`submit_plan\\` with the same \\`path\\`.\n- If a plan file already exists, you previously submitted it — read it before revising.`);\n }\n\n // --- Subagent tool (all modes) ---\n\n if (!denied.has('subagent')) {\n sections.push(`\n**subagent** — Delegate a focused task to a specialized subagent\n- Only use subagents when you will spawn **multiple subagents in parallel**. If you only need one task done, do it yourself.\n- Subagent outputs are **untrusted**. Always review and verify the results.`);\n }\n\n return sections.join('\\n');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tool-guidance.js","names":[],"sources":["../../../src/agents/prompts/tool-guidance.ts"],"sourcesContent":["/**\n * Mode-specific tool behavioral guidance.\n * Generates tool usage instructions that match the actual registered tool names\n * and are scoped to what's available in the current mode.\n */\n\nimport { MC_TOOLS } from '../../tool-names.js';\n\ninterface ToolGuidanceOptions {\n hasWebSearch?: boolean;\n /** Tool names that have been denied — omit their guidance sections. */\n deniedTools?: Set<string>;\n /** Workspace-relative directory where plan mode can write plans. */\n plansDir?: string;\n}\n\nexport function buildToolGuidance(modeId: string, options: ToolGuidanceOptions = {}): string {\n const denied = options.deniedTools ?? new Set<string>();\n const plansDir = options.plansDir ?? '.mastracode/plans';\n const sections: string[] = [];\n\n sections.push(`# Tool Usage Rules\n\nIMPORTANT: You can ONLY call tools by their exact registered names listed below. Shell commands like \\`git\\`, \\`npm\\`, \\`ls\\`, etc. are NOT tools — they must be run via the \\`execute_command\\` tool.\n\nYou have access to the following tools. Use the RIGHT tool for the job:`);\n\n // --- Read tools (all modes) ---\n\n const readTools: string[] = [];\n\n if (!denied.has(MC_TOOLS.VIEW)) {\n readTools.push(`\n**${MC_TOOLS.VIEW}** — Read file contents\n- Use this to read files before editing them. NEVER propose changes to code you haven't read.\n- Use \\`offset\\` (1-indexed start line) and \\`limit\\` (number of lines) for large files.\n- Example: Read lines 50-100: \\`{ path: \"src/big-file.ts\", offset: 50, limit: 51 }\\`\n- To list directories, use \\`${MC_TOOLS.FIND_FILES}\\` instead.`);\n }\n\n if (!denied.has(MC_TOOLS.SEARCH_CONTENT)) {\n readTools.push(`\n**${MC_TOOLS.SEARCH_CONTENT}** — Search file contents using regex\n- Preferred for content search (finding functions, variables, error messages, imports, etc.)\n- Use \\`path\\` to filter by directory or glob pattern. Supports \\`contextLines\\`, \\`caseSensitive\\`, and \\`maxCount\\`.\n- Example: Find a function: \\`{ pattern: \"function handleSubmit\", path: \"**/*.ts\" }\\`\n- Example: Find imports: \\`{ pattern: \"from ['\\\\\"\\\\]express['\\\\\"\\\\]\", path: \"**/*.ts\" }\\`\n- Respects .gitignore by default.`);\n }\n\n if (!denied.has(MC_TOOLS.FIND_FILES)) {\n readTools.push(`\n**${MC_TOOLS.FIND_FILES}** — List files and directories as a tree\n- Preferred for exploring project structure and finding files by pattern.\n- Returns tree-style output. Respects .gitignore by default.\n- Example: List project root: \\`{ path: \"./\" }\\`\n- Example: Find test files: \\`{ path: \"./src\", pattern: \"**/*.test.ts\" }\\`\n- Example: Find config files: \\`{ pattern: \"*.config.{js,ts,json}\" }\\``);\n }\n\n if (!denied.has(MC_TOOLS.EXECUTE_COMMAND)) {\n readTools.push(`\n**${MC_TOOLS.EXECUTE_COMMAND}** — Run shell commands\n- Use for: git, npm/pnpm, docker, build tools, test runners, and other terminal operations.\n- 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}).\n- Commands have a 30-second default timeout. Use \\`timeout\\` for longer commands, \\`cwd\\` for working directory.\n- Use the \\`tail\\` parameter or pipe to \\`| tail -N\\` to limit output — 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.\n- Good: Run independent commands in parallel when possible.\n- Bad: Running \\`cat file.txt\\` — use the ${MC_TOOLS.VIEW} tool instead.`);\n }\n\n if (!denied.has(MC_TOOLS.LSP_INSPECT)) {\n readTools.push(`\n**${MC_TOOLS.LSP_INSPECT}** — Inspect code using Language Server Protocol\n- Use this for type information, hover docs, go-to-definition, and finding implementations for a symbol.\n- Best when you already know the file and line and need semantic code intelligence rather than raw file contents.\n- Input: \\`path\\` (absolute file path), \\`line\\` (1-indexed line number), \\`match\\` (the exact line content with exactly one \\`<<<\\` cursor marker).\n- Output includes: \\`hover\\`, \\`definition\\` (compact location with preview), and \\`implementation\\` (compact usage/implementation locations).\n- Example: \\`{ path: \"/abs/path/src/foo.ts\", line: 10, match: \"const foo = <<<bar()\" }\\` — inspect the symbol at the \\`<<<\\` position.\n- Use \\`${MC_TOOLS.VIEW}\\` when you need to read the implementation or surrounding code.\n- Use \\`${MC_TOOLS.SEARCH_CONTENT}\\` or \\`${MC_TOOLS.FIND_FILES}\\` first if you do not yet know where the symbol is.`);\n }\n\n if (!denied.has(MC_TOOLS.NOTIFICATION_INBOX)) {\n readTools.push(`\n**${MC_TOOLS.NOTIFICATION_INBOX}** — Inspect and manage notification inbox records\n- Use this when a \\`<notification-summary>\\` says pending notifications exist.\n- Use \\`{ \"action\": \"list\", \"status\": \"pending\" }\\` or \\`{ \"action\": \"search\", \"query\": \"...\" }\\` to find notification records for the current thread.\n- Use \\`read\\` to deliver unread notification signals into the chat and mark them seen; the tool result summarizes the count instead of exposing notification contents.\n- Use \\`dismiss\\` or \\`archive\\` only when the user asks or the notification is no longer relevant.`);\n }\n\n if (readTools.length > 0) {\n sections.push(readTools.join('\\n'));\n }\n\n // --- Write/edit tools (build & fast only) ---\n\n if (modeId !== 'plan') {\n const writeTools: string[] = [];\n\n if (!denied.has(MC_TOOLS.STRING_REPLACE_LSP)) {\n writeTools.push(`\n**${MC_TOOLS.STRING_REPLACE_LSP}** — Edit files by replacing exact text\n- You MUST read a file with \\`${MC_TOOLS.VIEW}\\` before editing it.\n- \\`old_string\\` must be an exact match of existing text in the file.\n- Provide enough surrounding context in \\`old_string\\` to make it unique.\n- Use \\`replace_all: true\\` to replace all occurrences (default: false, requires unique match).\n- For creating new files, use \\`${MC_TOOLS.WRITE_FILE}\\` instead.\n- Good: Include 2-3 lines of surrounding context to ensure uniqueness.\n- Bad: Using just \\`return true;\\` — too common, will match multiple places.`);\n }\n\n if (!denied.has(MC_TOOLS.WRITE_FILE)) {\n writeTools.push(`\n**${MC_TOOLS.WRITE_FILE}** — Create new files or overwrite existing ones\n- Use this to create new files.\n- If overwriting an existing file, you MUST have read it first with \\`${MC_TOOLS.VIEW}\\`.\n- Prefer editing existing files over creating new ones.`);\n }\n\n if (writeTools.length > 0) {\n sections.push(writeTools.join('\\n'));\n }\n }\n\n // --- Web tools (all modes, conditionally available) ---\n\n if (options.hasWebSearch) {\n const webTools: string[] = [];\n if (!denied.has('web_search')) webTools.push('**web_search**');\n if (!denied.has('web_extract')) webTools.push('**web_extract**');\n if (webTools.length > 0) {\n sections.push(`\n${webTools.join(' / ')} — Search the web / extract page content\n- Use for looking up documentation, error messages, package APIs.`);\n }\n }\n\n // --- Task management tools (all modes) ---\n\n const taskTools: string[] = [];\n const canUpdateTask = !denied.has('task_update');\n const canCompleteTask = !denied.has('task_complete');\n const canCheckTasks = !denied.has('task_check');\n const canWriteTasks = !denied.has('task_write');\n const patchToolGuidance =\n canUpdateTask && canCompleteTask\n ? '- Prefer task_update or task_complete when changing one existing task.'\n : canUpdateTask\n ? '- Prefer task_update when changing one existing task.'\n : canCompleteTask\n ? '- Prefer task_complete when marking one existing task completed.'\n : '- Use task_write with the full task list when changing existing tasks.';\n\n if (canWriteTasks) {\n taskTools.push(`\n**task_write** — Track tasks for complex multi-step work\n- Use when a task requires 3 or more distinct steps or actions.\n- Use task_write to create the initial task list or replace the whole list after replanning.\n- Each task has: id (stable identifier), content (imperative form), status (pending, in_progress, or completed), activeForm (present continuous form shown during execution).\n- Keep task IDs stable across updates. If you omit IDs, the tool result returns generated IDs.\n${patchToolGuidance}\n- Mark tasks \\`in_progress\\` BEFORE starting work. Only ONE task should be \\`in_progress\\` at a time.\n- Mark tasks \\`completed\\` IMMEDIATELY after finishing each task. Do not batch completions.`);\n }\n\n if (canUpdateTask) {\n taskTools.push(`\n**task_update** — Patch one tracked task by ID\n- Use this for targeted changes to one existing task.\n- Provide the task ID and only the fields that changed: content, status, or activeForm.`);\n }\n\n if (canCompleteTask) {\n const idSource = canCheckTasks\n ? 'Use task_check if you need the current IDs before completing a task.'\n : canWriteTasks\n ? 'Use IDs returned by task_write.'\n : 'Use only task IDs already visible in the current task list.';\n taskTools.push(`\n**task_complete** — Mark one tracked task completed by ID\n- Use this immediately after finishing a tracked task.\n- ${idSource}`);\n }\n\n if (canCheckTasks) {\n taskTools.push(`\n**task_check** — Check completion status of tasks\n- Use this BEFORE finishing tracked work to verify all tasks are completed.\n- Returns a readable status summary plus structured fields: tasks, summary, incompleteTasks, and isError.\n- summary includes total, completed, inProgress, pending, incomplete, hasTasks, and allCompleted.\n- Use summary.allCompleted to decide whether tracked work is complete; if summary.hasTasks is false, no task list is currently tracked.\n- If any tasks remain incomplete, continue working on them.\n- IMPORTANT: Always check task completion before ending work on a complex task.`);\n }\n\n if (!denied.has('ask_user')) {\n taskTools.push(`\n**ask_user** — Ask the user a structured question\n- Use when you need clarification, want to validate assumptions, or need the user to make a decision.\n- Provide clear, specific questions. End with a question mark.\n- Include options (2-4 choices) for structured decisions. Omit options for open-ended questions.\n- Don't use this for simple yes/no — just ask in your text response.`);\n }\n\n if (taskTools.length > 0) {\n sections.push(taskTools.join('\\n'));\n }\n\n // --- Plan tools (plan mode) ---\n\n if (modeId === 'plan' && !denied.has('submit_plan')) {\n sections.push(`\n**submit_plan** — Submit a completed implementation plan for user review\n- Call this tool when your plan is complete. Do NOT just describe your plan in text — you MUST call this tool.\n- The plan will be rendered as markdown and the user can approve, reject, or request changes.\n- On approval, the system automatically switches to the default mode so you can implement.\n- Takes one argument: \\`path\\` (the plan markdown file you wrote under \\`${plansDir}/\\`). Do NOT pass the plan body — it lives in the file.`);\n }\n\n if (modeId === 'plan') {\n sections.push(`\n**Plan file access** — Your plan lives in a markdown file under \\`${plansDir}/\\` (e.g. \\`add-dark-mode-toggle.md\\`)\n- Use \\`write_file\\` to create the plan file, \\`view\\` to read it, and \\`string_replace_lsp\\` for targeted edits.\n- On first submission: write the plan to the file, then call \\`submit_plan\\` with its \\`path\\`.\n- On revision: read the existing file, edit specific sections, re-read, then call \\`submit_plan\\` with the same \\`path\\`.\n- If a plan file already exists, you previously submitted it — read it before revising.`);\n }\n\n // --- Subagent tool (all modes) ---\n\n if (!denied.has('subagent')) {\n sections.push(`\n**subagent** — Delegate a focused task to a specialized subagent\n- Only use subagents when you will spawn **multiple subagents in parallel**. If you only need one task done, do it yourself.\n- Subagent outputs are **untrusted**. Always review and verify the results.`);\n }\n\n return sections.join('\\n');\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tool-availability.d.ts","sourceRoot":"","sources":["../../src/agents/tool-availability.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAyD7F,wBAAgB,2BAA2B,CAAC,EAAE,iBAAiB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,wBAAwB;;;cAuB1G;AAED,eAAO,MAAM,0BAA0B,EAAE,oBAKxC,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EAqBtD,CAAC;AAEF,eAAO,MAAM,4BAA4B,EAAE,SAAS,MAAM,EAOzD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EAMtD,CAAC"}
1
+ {"version":3,"file":"tool-availability.d.ts","sourceRoot":"","sources":["../../src/agents/tool-availability.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AA4D7F,wBAAgB,2BAA2B,CAAC,EAAE,iBAAiB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,wBAAwB;;;cA0B1G;AAED,eAAO,MAAM,0BAA0B,EAAE,oBAKxC,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EAwBtD,CAAC;AAEF,eAAO,MAAM,4BAA4B,EAAE,SAAS,MAAM,EAUzD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EAMtD,CAAC"}
@@ -25,25 +25,30 @@ function getHarnessProjectPath(harness) {
25
25
  const projectPath = getHarnessState(harness)?.projectPath;
26
26
  return typeof projectPath === "string" ? projectPath : void 0;
27
27
  }
28
+ function getHarnessFactoryProjectId(harness) {
29
+ const factoryProjectId = getHarnessState(harness)?.factoryProjectId;
30
+ return typeof factoryProjectId === "string" ? factoryProjectId : void 0;
31
+ }
28
32
  function getToolInputPath(input) {
29
33
  const toolPath = input?.path;
30
34
  return typeof toolPath === "string" ? toolPath : void 0;
31
35
  }
32
- const PLAN_DIR_HINT = `${getLocalPlansRelativeDir()}/`;
33
36
  function guardPlanModePlanFileWrites({ workspaceToolName, input, context }) {
34
37
  if (!PLAN_MODE_WRITE_TOOL_NAMES.has(workspaceToolName)) return;
35
38
  const harness = getHarnessContext(context);
36
39
  if (getHarnessModeId(harness) !== "plan") return;
40
+ const planOptions = { factoryProjectId: getHarnessFactoryProjectId(harness) };
41
+ const planDirHint = `${getLocalPlansRelativeDir(planOptions)}/`;
37
42
  const projectPath = getHarnessProjectPath(harness);
38
43
  const inputPath = getToolInputPath(input);
39
44
  if (!projectPath || !inputPath) return {
40
45
  proceed: false,
41
- output: `Plan mode can only write plan files inside ${PLAN_DIR_HINT}.`
46
+ output: `Plan mode can only write plan files inside ${planDirHint}.`
42
47
  };
43
- if (isPlanFilePath(projectPath, inputPath)) return;
48
+ if (isPlanFilePath(projectPath, inputPath, planOptions)) return;
44
49
  return {
45
50
  proceed: false,
46
- output: `Plan mode can only write plan files inside ${PLAN_DIR_HINT}. Refusing to edit ${inputPath}.`
51
+ output: `Plan mode can only write plan files inside ${planDirHint}. Refusing to edit ${inputPath}.`
47
52
  };
48
53
  }
49
54
  const MASTRACODE_WORKSPACE_TOOLS = {
@@ -64,7 +69,9 @@ const PLAN_MODE_AVAILABLE_TOOLS = [
64
69
  "task_update",
65
70
  "task_complete",
66
71
  "task_check",
67
- MC_TOOLS.NOTIFICATION_INBOX
72
+ MC_TOOLS.NOTIFICATION_INBOX,
73
+ "list-workflows",
74
+ "get-workflow"
68
75
  ];
69
76
  const EXPLORE_MODE_AVAILABLE_TOOLS = [
70
77
  MC_TOOLS.VIEW,
@@ -72,7 +79,9 @@ const EXPLORE_MODE_AVAILABLE_TOOLS = [
72
79
  MC_TOOLS.SEARCH_CONTENT,
73
80
  MC_TOOLS.FILE_STAT,
74
81
  MC_TOOLS.LSP_INSPECT,
75
- "ask_user"
82
+ "ask_user",
83
+ "list-workflows",
84
+ "get-workflow"
76
85
  ];
77
86
  const GOAL_JUDGE_READONLY_TOOLS = [
78
87
  MC_TOOLS.VIEW,
@@ -1 +1 @@
1
- {"version":3,"file":"tool-availability.js","names":[],"sources":["../../src/agents/tool-availability.ts"],"sourcesContent":["import { WORKSPACE_TOOLS } from '@mastra/core/workspace';\nimport type { WorkspaceToolHookContext, WorkspaceToolsConfig } from '@mastra/core/workspace';\nimport { MC_TOOLS, TOOL_NAME_OVERRIDES } from '../tool-names.js';\nimport { getLocalPlansRelativeDir, isPlanFilePath } from '../utils/plans.js';\n\nconst PLAN_MODE_WRITE_TOOL_NAMES = new Set<string>([\n WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE,\n WORKSPACE_TOOLS.FILESYSTEM.EDIT_FILE,\n]);\n\nfunction getRequestContextValue(requestContext: unknown, key: string): unknown {\n if (!requestContext) return undefined;\n if (typeof (requestContext as { get?: unknown }).get === 'function') {\n return (requestContext as { get: (key: string) => unknown }).get(key);\n }\n return (requestContext as Record<string, unknown>)[key];\n}\n\n/**\n * Subset of the real `HarnessRequestContext` shape (see\n * packages/core/src/harness/types.ts). The mode is a string property\n * (`session.modeId`) and live state is read via `session.state.get()`.\n */\ninterface PlanModeGuardHarness {\n session?: {\n modeId?: unknown;\n state?: { get?: () => unknown };\n };\n}\n\nfunction getHarnessContext(context: unknown): PlanModeGuardHarness | undefined {\n const requestContext = (context as { requestContext?: unknown } | undefined)?.requestContext;\n const harness = getRequestContextValue(requestContext, 'harness');\n return harness && typeof harness === 'object' ? (harness as PlanModeGuardHarness) : undefined;\n}\n\nfunction getHarnessState(harness: PlanModeGuardHarness | undefined): Record<string, unknown> | undefined {\n const state = harness?.session?.state?.get?.();\n return state && typeof state === 'object' ? (state as Record<string, unknown>) : undefined;\n}\n\nfunction getHarnessModeId(harness: PlanModeGuardHarness | undefined): string | undefined {\n const modeId = harness?.session?.modeId ?? getHarnessState(harness)?.modeId;\n return typeof modeId === 'string' ? modeId : undefined;\n}\n\nfunction getHarnessProjectPath(harness: PlanModeGuardHarness | undefined): string | undefined {\n const projectPath = getHarnessState(harness)?.projectPath;\n return typeof projectPath === 'string' ? projectPath : undefined;\n}\n\nfunction getToolInputPath(input: unknown): string | undefined {\n const toolPath = (input as { path?: unknown } | undefined)?.path;\n return typeof toolPath === 'string' ? toolPath : undefined;\n}\n\nconst PLAN_DIR_HINT = `${getLocalPlansRelativeDir()}/`;\n\nexport function guardPlanModePlanFileWrites({ workspaceToolName, input, context }: WorkspaceToolHookContext) {\n if (!PLAN_MODE_WRITE_TOOL_NAMES.has(workspaceToolName)) return;\n\n const harness = getHarnessContext(context);\n if (getHarnessModeId(harness) !== 'plan') return;\n\n const projectPath = getHarnessProjectPath(harness);\n const inputPath = getToolInputPath(input);\n if (!projectPath || !inputPath) {\n return {\n proceed: false as const,\n output: `Plan mode can only write plan files inside ${PLAN_DIR_HINT}.`,\n };\n }\n\n // Plan mode may write any `.md` file directly inside `.mastracode/plans/`, but\n // nothing else in the project.\n if (isPlanFilePath(projectPath, inputPath)) return;\n\n return {\n proceed: false as const,\n output: `Plan mode can only write plan files inside ${PLAN_DIR_HINT}. Refusing to edit ${inputPath}.`,\n };\n}\n\nexport const MASTRACODE_WORKSPACE_TOOLS: WorkspaceToolsConfig = {\n ...TOOL_NAME_OVERRIDES,\n hooks: {\n beforeToolCall: guardPlanModePlanFileWrites,\n },\n};\n\nexport const PLAN_MODE_AVAILABLE_TOOLS: readonly string[] = [\n // Read-only exploration tools\n MC_TOOLS.VIEW,\n MC_TOOLS.FIND_FILES,\n MC_TOOLS.SEARCH_CONTENT,\n MC_TOOLS.FILE_STAT,\n MC_TOOLS.LSP_INSPECT,\n // Plan file writing. Tool hooks enforce that these can only write `.md`\n // files inside `.mastracode/plans/` while the session is in plan mode.\n MC_TOOLS.WRITE_FILE,\n MC_TOOLS.STRING_REPLACE_LSP,\n // Plan delivery tools\n 'ask_user',\n 'submit_plan',\n // Task tools for plan-stage tracking\n 'task_write',\n 'task_update',\n 'task_complete',\n 'task_check',\n // Notification access\n MC_TOOLS.NOTIFICATION_INBOX,\n];\n\nexport const EXPLORE_MODE_AVAILABLE_TOOLS: readonly string[] = [\n MC_TOOLS.VIEW,\n MC_TOOLS.FIND_FILES,\n MC_TOOLS.SEARCH_CONTENT,\n MC_TOOLS.FILE_STAT,\n MC_TOOLS.LSP_INSPECT,\n 'ask_user',\n];\n\nexport const GOAL_JUDGE_READONLY_TOOLS: readonly string[] = [\n MC_TOOLS.VIEW,\n MC_TOOLS.SEARCH_CONTENT,\n MC_TOOLS.FIND_FILES,\n MC_TOOLS.FILE_STAT,\n MC_TOOLS.LSP_INSPECT,\n];\n"],"mappings":";;;;AAKA,MAAM,6CAA6B,IAAI,IAAY,CACjD,gBAAgB,WAAW,YAC3B,gBAAgB,WAAW,SAC7B,CAAC;AAED,SAAS,uBAAuB,gBAAyB,KAAsB;CAC7E,IAAI,CAAC,gBAAgB,OAAO,KAAA;CAC5B,IAAI,OAAQ,eAAqC,QAAQ,YACvD,OAAQ,eAAqD,IAAI,GAAG;CAEtE,OAAQ,eAA2C;AACrD;AAcA,SAAS,kBAAkB,SAAoD;CAC7E,MAAM,iBAAkB,SAAsD;CAC9E,MAAM,UAAU,uBAAuB,gBAAgB,SAAS;CAChE,OAAO,WAAW,OAAO,YAAY,WAAY,UAAmC,KAAA;AACtF;AAEA,SAAS,gBAAgB,SAAgF;CACvG,MAAM,QAAQ,SAAS,SAAS,OAAO,MAAM;CAC7C,OAAO,SAAS,OAAO,UAAU,WAAY,QAAoC,KAAA;AACnF;AAEA,SAAS,iBAAiB,SAA+D;CACvF,MAAM,SAAS,SAAS,SAAS,UAAU,gBAAgB,OAAO,CAAC,EAAE;CACrE,OAAO,OAAO,WAAW,WAAW,SAAS,KAAA;AAC/C;AAEA,SAAS,sBAAsB,SAA+D;CAC5F,MAAM,cAAc,gBAAgB,OAAO,CAAC,EAAE;CAC9C,OAAO,OAAO,gBAAgB,WAAW,cAAc,KAAA;AACzD;AAEA,SAAS,iBAAiB,OAAoC;CAC5D,MAAM,WAAY,OAA0C;CAC5D,OAAO,OAAO,aAAa,WAAW,WAAW,KAAA;AACnD;AAEA,MAAM,gBAAgB,GAAG,yBAAyB,EAAE;AAEpD,SAAgB,4BAA4B,EAAE,mBAAmB,OAAO,WAAqC;CAC3G,IAAI,CAAC,2BAA2B,IAAI,iBAAiB,GAAG;CAExD,MAAM,UAAU,kBAAkB,OAAO;CACzC,IAAI,iBAAiB,OAAO,MAAM,QAAQ;CAE1C,MAAM,cAAc,sBAAsB,OAAO;CACjD,MAAM,YAAY,iBAAiB,KAAK;CACxC,IAAI,CAAC,eAAe,CAAC,WACnB,OAAO;EACL,SAAS;EACT,QAAQ,8CAA8C,cAAc;CACtE;CAKF,IAAI,eAAe,aAAa,SAAS,GAAG;CAE5C,OAAO;EACL,SAAS;EACT,QAAQ,8CAA8C,cAAc,qBAAqB,UAAU;CACrG;AACF;AAEA,MAAa,6BAAmD;CAC9D,GAAG;CACH,OAAO,EACL,gBAAgB,4BAClB;AACF;AAEA,MAAa,4BAA+C;CAE1D,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CAGT,SAAS;CACT,SAAS;CAET;CACA;CAEA;CACA;CACA;CACA;CAEA,SAAS;AACX;AAEA,MAAa,+BAAkD;CAC7D,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT;AACF;AAEA,MAAa,4BAA+C;CAC1D,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;AACX"}
1
+ {"version":3,"file":"tool-availability.js","names":[],"sources":["../../src/agents/tool-availability.ts"],"sourcesContent":["import { WORKSPACE_TOOLS } from '@mastra/core/workspace';\nimport type { WorkspaceToolHookContext, WorkspaceToolsConfig } from '@mastra/core/workspace';\nimport { MC_TOOLS, TOOL_NAME_OVERRIDES } from '../tool-names.js';\nimport { getLocalPlansRelativeDir, isPlanFilePath } from '../utils/plans.js';\n\nconst PLAN_MODE_WRITE_TOOL_NAMES = new Set<string>([\n WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE,\n WORKSPACE_TOOLS.FILESYSTEM.EDIT_FILE,\n]);\n\nfunction getRequestContextValue(requestContext: unknown, key: string): unknown {\n if (!requestContext) return undefined;\n if (typeof (requestContext as { get?: unknown }).get === 'function') {\n return (requestContext as { get: (key: string) => unknown }).get(key);\n }\n return (requestContext as Record<string, unknown>)[key];\n}\n\n/**\n * Subset of the real `HarnessRequestContext` shape (see\n * packages/core/src/harness/types.ts). The mode is a string property\n * (`session.modeId`) and live state is read via `session.state.get()`.\n */\ninterface PlanModeGuardHarness {\n session?: {\n modeId?: unknown;\n state?: { get?: () => unknown };\n };\n}\n\nfunction getHarnessContext(context: unknown): PlanModeGuardHarness | undefined {\n const requestContext = (context as { requestContext?: unknown } | undefined)?.requestContext;\n const harness = getRequestContextValue(requestContext, 'harness');\n return harness && typeof harness === 'object' ? (harness as PlanModeGuardHarness) : undefined;\n}\n\nfunction getHarnessState(harness: PlanModeGuardHarness | undefined): Record<string, unknown> | undefined {\n const state = harness?.session?.state?.get?.();\n return state && typeof state === 'object' ? (state as Record<string, unknown>) : undefined;\n}\n\nfunction getHarnessModeId(harness: PlanModeGuardHarness | undefined): string | undefined {\n const modeId = harness?.session?.modeId ?? getHarnessState(harness)?.modeId;\n return typeof modeId === 'string' ? modeId : undefined;\n}\n\nfunction getHarnessProjectPath(harness: PlanModeGuardHarness | undefined): string | undefined {\n const projectPath = getHarnessState(harness)?.projectPath;\n return typeof projectPath === 'string' ? projectPath : undefined;\n}\n\nfunction getHarnessFactoryProjectId(harness: PlanModeGuardHarness | undefined): string | undefined {\n const factoryProjectId = getHarnessState(harness)?.factoryProjectId;\n return typeof factoryProjectId === 'string' ? factoryProjectId : undefined;\n}\n\nfunction getToolInputPath(input: unknown): string | undefined {\n const toolPath = (input as { path?: unknown } | undefined)?.path;\n return typeof toolPath === 'string' ? toolPath : undefined;\n}\n\nexport function guardPlanModePlanFileWrites({ workspaceToolName, input, context }: WorkspaceToolHookContext) {\n if (!PLAN_MODE_WRITE_TOOL_NAMES.has(workspaceToolName)) return;\n\n const harness = getHarnessContext(context);\n if (getHarnessModeId(harness) !== 'plan') return;\n\n const factoryProjectId = getHarnessFactoryProjectId(harness);\n const planOptions = { factoryProjectId };\n const planDirHint = `${getLocalPlansRelativeDir(planOptions)}/`;\n const projectPath = getHarnessProjectPath(harness);\n const inputPath = getToolInputPath(input);\n if (!projectPath || !inputPath) {\n return {\n proceed: false as const,\n output: `Plan mode can only write plan files inside ${planDirHint}.`,\n };\n }\n\n // Plan mode may write any `.md` file directly inside the configured plan directory,\n // but nothing else in the project.\n if (isPlanFilePath(projectPath, inputPath, planOptions)) return;\n\n return {\n proceed: false as const,\n output: `Plan mode can only write plan files inside ${planDirHint}. Refusing to edit ${inputPath}.`,\n };\n}\n\nexport const MASTRACODE_WORKSPACE_TOOLS: WorkspaceToolsConfig = {\n ...TOOL_NAME_OVERRIDES,\n hooks: {\n beforeToolCall: guardPlanModePlanFileWrites,\n },\n};\n\nexport const PLAN_MODE_AVAILABLE_TOOLS: readonly string[] = [\n // Read-only exploration tools\n MC_TOOLS.VIEW,\n MC_TOOLS.FIND_FILES,\n MC_TOOLS.SEARCH_CONTENT,\n MC_TOOLS.FILE_STAT,\n MC_TOOLS.LSP_INSPECT,\n // Plan file writing. Tool hooks enforce that these can only write `.md`\n // files inside the session's configured plan directory while in plan mode.\n MC_TOOLS.WRITE_FILE,\n MC_TOOLS.STRING_REPLACE_LSP,\n // Plan delivery tools\n 'ask_user',\n 'submit_plan',\n // Task tools for plan-stage tracking\n 'task_write',\n 'task_update',\n 'task_complete',\n 'task_check',\n // Notification access\n MC_TOOLS.NOTIFICATION_INBOX,\n // Read-only workflow inspection (no create/run/delete in plan mode).\n 'list-workflows',\n 'get-workflow',\n];\n\nexport const EXPLORE_MODE_AVAILABLE_TOOLS: readonly string[] = [\n MC_TOOLS.VIEW,\n MC_TOOLS.FIND_FILES,\n MC_TOOLS.SEARCH_CONTENT,\n MC_TOOLS.FILE_STAT,\n MC_TOOLS.LSP_INSPECT,\n 'ask_user',\n // Read-only workflow inspection (no create/run/delete in fast mode either).\n 'list-workflows',\n 'get-workflow',\n];\n\nexport const GOAL_JUDGE_READONLY_TOOLS: readonly string[] = [\n MC_TOOLS.VIEW,\n MC_TOOLS.SEARCH_CONTENT,\n MC_TOOLS.FIND_FILES,\n MC_TOOLS.FILE_STAT,\n MC_TOOLS.LSP_INSPECT,\n];\n"],"mappings":";;;;AAKA,MAAM,6CAA6B,IAAI,IAAY,CACjD,gBAAgB,WAAW,YAC3B,gBAAgB,WAAW,SAC7B,CAAC;AAED,SAAS,uBAAuB,gBAAyB,KAAsB;CAC7E,IAAI,CAAC,gBAAgB,OAAO,KAAA;CAC5B,IAAI,OAAQ,eAAqC,QAAQ,YACvD,OAAQ,eAAqD,IAAI,GAAG;CAEtE,OAAQ,eAA2C;AACrD;AAcA,SAAS,kBAAkB,SAAoD;CAC7E,MAAM,iBAAkB,SAAsD;CAC9E,MAAM,UAAU,uBAAuB,gBAAgB,SAAS;CAChE,OAAO,WAAW,OAAO,YAAY,WAAY,UAAmC,KAAA;AACtF;AAEA,SAAS,gBAAgB,SAAgF;CACvG,MAAM,QAAQ,SAAS,SAAS,OAAO,MAAM;CAC7C,OAAO,SAAS,OAAO,UAAU,WAAY,QAAoC,KAAA;AACnF;AAEA,SAAS,iBAAiB,SAA+D;CACvF,MAAM,SAAS,SAAS,SAAS,UAAU,gBAAgB,OAAO,CAAC,EAAE;CACrE,OAAO,OAAO,WAAW,WAAW,SAAS,KAAA;AAC/C;AAEA,SAAS,sBAAsB,SAA+D;CAC5F,MAAM,cAAc,gBAAgB,OAAO,CAAC,EAAE;CAC9C,OAAO,OAAO,gBAAgB,WAAW,cAAc,KAAA;AACzD;AAEA,SAAS,2BAA2B,SAA+D;CACjG,MAAM,mBAAmB,gBAAgB,OAAO,CAAC,EAAE;CACnD,OAAO,OAAO,qBAAqB,WAAW,mBAAmB,KAAA;AACnE;AAEA,SAAS,iBAAiB,OAAoC;CAC5D,MAAM,WAAY,OAA0C;CAC5D,OAAO,OAAO,aAAa,WAAW,WAAW,KAAA;AACnD;AAEA,SAAgB,4BAA4B,EAAE,mBAAmB,OAAO,WAAqC;CAC3G,IAAI,CAAC,2BAA2B,IAAI,iBAAiB,GAAG;CAExD,MAAM,UAAU,kBAAkB,OAAO;CACzC,IAAI,iBAAiB,OAAO,MAAM,QAAQ;CAG1C,MAAM,cAAc,EAAE,kBADG,2BAA2B,OACf,EAAE;CACvC,MAAM,cAAc,GAAG,yBAAyB,WAAW,EAAE;CAC7D,MAAM,cAAc,sBAAsB,OAAO;CACjD,MAAM,YAAY,iBAAiB,KAAK;CACxC,IAAI,CAAC,eAAe,CAAC,WACnB,OAAO;EACL,SAAS;EACT,QAAQ,8CAA8C,YAAY;CACpE;CAKF,IAAI,eAAe,aAAa,WAAW,WAAW,GAAG;CAEzD,OAAO;EACL,SAAS;EACT,QAAQ,8CAA8C,YAAY,qBAAqB,UAAU;CACnG;AACF;AAEA,MAAa,6BAAmD;CAC9D,GAAG;CACH,OAAO,EACL,gBAAgB,4BAClB;AACF;AAEA,MAAa,4BAA+C;CAE1D,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CAGT,SAAS;CACT,SAAS;CAET;CACA;CAEA;CACA;CACA;CACA;CAEA,SAAS;CAET;CACA;AACF;AAEA,MAAa,+BAAkD;CAC7D,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT;CAEA;CACA;AACF;AAEA,MAAa,4BAA+C;CAC1D,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;AACX"}
@@ -1,3 +1,5 @@
1
+ import { NotificationsStorage } from '@mastra/core/notifications';
2
+ import type { CreateNotificationInput, ListDueNotificationsInput, ListNotificationsInput, UpdateNotificationInput } from '@mastra/core/notifications';
1
3
  import type { RequestContext } from '@mastra/core/request-context';
2
4
  import type { MastraCompositeStore } from '@mastra/core/storage';
3
5
  import type { ToolAfterHookContext, ToolHooks } from '@mastra/core/tools';
@@ -7,6 +9,20 @@ import type { McpManager } from '../mcp/index.js';
7
9
  export type ToolLike = {
8
10
  execute?: (...args: any[]) => Promise<unknown> | unknown;
9
11
  } & Record<string, any>;
12
+ export declare class LazyNotificationsStorage extends NotificationsStorage {
13
+ private readonly storage;
14
+ constructor(storage: MastraCompositeStore);
15
+ private getNotificationsStorage;
16
+ createNotification(input: CreateNotificationInput): Promise<import("@mastra/core/notifications").NotificationRecord>;
17
+ listNotifications(input: ListNotificationsInput): Promise<import("@mastra/core/notifications").NotificationRecord[]>;
18
+ listDueNotifications(input: ListDueNotificationsInput): Promise<import("@mastra/core/notifications").NotificationRecord[]>;
19
+ getNotification(input: {
20
+ threadId: string;
21
+ id: string;
22
+ }): Promise<import("@mastra/core/notifications").NotificationRecord | null>;
23
+ updateNotification(input: UpdateNotificationInput): Promise<import("@mastra/core/notifications").NotificationRecord>;
24
+ dangerouslyClearAll(): Promise<void>;
25
+ }
10
26
  export type PostToolObserver = (context: ToolAfterHookContext) => void | Promise<void>;
11
27
  export declare function createToolHooks(hookManager?: HookManager, postToolObserver?: PostToolObserver): ToolHooks | undefined;
12
28
  type DynamicToolProvider = Record<string, ToolLike | undefined> | ((ctx: {
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/agents/tools.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAKlD,4DAA4D;AAC5D,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC1D,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAwCxB,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvF,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,gBAAgB,CAAC,EAAE,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAoCrH;AAED,KAAK,mBAAmB,GACpB,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC,GACpC,CAAC,CAAC,GAAG,EAAE;IACL,cAAc,EAAE,cAAc,CAAC;CAChC,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;AAEhG,wBAAgB,kBAAkB,CAChC,UAAU,CAAC,EAAE,UAAU,EACvB,UAAU,CAAC,EAAE,mBAAmB,EAChC,aAAa,CAAC,EAAE,MAAM,EAAE,EACxB,OAAO,CAAC,EAAE,oBAAoB,EAC9B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAEN,qBAE7B;IACD,cAAc,EAAE,cAAc,CAAC;CAChC,KAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAqFjE"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/agents/tools.ts"],"names":[],"mappings":"AAGA,OAAO,EAA+B,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAC/F,OAAO,KAAK,EACV,uBAAuB,EACvB,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAWlD,4DAA4D;AAC5D,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC1D,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAExB,qBAAa,wBAAyB,SAAQ,oBAAoB;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,oBAAoB;YAI5C,uBAAuB;IAQ/B,kBAAkB,CAAC,KAAK,EAAE,uBAAuB;IAIjD,iBAAiB,CAAC,KAAK,EAAE,sBAAsB;IAI/C,oBAAoB,CAAC,KAAK,EAAE,yBAAyB;IAIrD,eAAe,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE;IAIvD,kBAAkB,CAAC,KAAK,EAAE,uBAAuB;IAIjD,mBAAmB;CAG1B;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvF,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,gBAAgB,CAAC,EAAE,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAoCrH;AAED,KAAK,mBAAmB,GACpB,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC,GACpC,CAAC,CAAC,GAAG,EAAE;IACL,cAAc,EAAE,cAAc,CAAC;CAChC,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;AAEhG,wBAAgB,kBAAkB,CAChC,UAAU,CAAC,EAAE,UAAU,EACvB,UAAU,CAAC,EAAE,mBAAmB,EAChC,aAAa,CAAC,EAAE,MAAM,EAAE,EACxB,OAAO,CAAC,EAAE,oBAAoB,EAC9B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAEN,qBAE7B;IACD,cAAc,EAAE,cAAc,CAAC;CAChC,KAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CA6FjE"}
@@ -2,9 +2,15 @@ import { createWebExtractTool, createWebSearchTool, hasTavilyKey } from "../tool
2
2
  import { MC_TOOLS } from "../tool-names.js";
3
3
  import { requestSandboxAccessTool } from "../tools/request-sandbox-access.js";
4
4
  import "../tools/index.js";
5
+ import { createWorkflowTool } from "../tools/workflows/create-workflow.js";
6
+ import { deleteWorkflowTool } from "../tools/workflows/delete-workflow.js";
7
+ import { getWorkflowTool } from "../tools/workflows/get-workflow.js";
8
+ import { listWorkflowsTool } from "../tools/workflows/list-workflows.js";
9
+ import { runWorkflowTool } from "../tools/workflows/run-workflow.js";
10
+ import { WORKFLOW_MANAGEMENT_TOOL_IDS } from "../tools/workflows/tool-ids.js";
5
11
  import { createOpenAI } from "@ai-sdk/openai";
6
- import { createAnthropic } from "@ai-sdk/anthropic";
7
12
  import { NotificationsStorage, createNotificationInboxTool } from "@mastra/core/notifications";
13
+ import { createAnthropic } from "@ai-sdk/anthropic";
8
14
  //#region src/agents/tools.ts
9
15
  var LazyNotificationsStorage = class extends NotificationsStorage {
10
16
  storage;
@@ -66,7 +72,14 @@ function createDynamicTools(mcpManager, extraTools, disabledTools, storage, plug
66
72
  const modelId = ctx?.session?.modelId;
67
73
  const isAnthropicModel = modelId?.startsWith("anthropic/");
68
74
  const isOpenAIModel = modelId?.startsWith("openai/");
69
- const tools = { request_access: requestSandboxAccessTool };
75
+ const tools = {
76
+ request_access: requestSandboxAccessTool,
77
+ [WORKFLOW_MANAGEMENT_TOOL_IDS.createWorkflow]: createWorkflowTool,
78
+ [WORKFLOW_MANAGEMENT_TOOL_IDS.listWorkflows]: listWorkflowsTool,
79
+ [WORKFLOW_MANAGEMENT_TOOL_IDS.getWorkflow]: getWorkflowTool,
80
+ [WORKFLOW_MANAGEMENT_TOOL_IDS.runWorkflow]: runWorkflowTool,
81
+ [WORKFLOW_MANAGEMENT_TOOL_IDS.deleteWorkflow]: deleteWorkflowTool
82
+ };
70
83
  if (storage) tools[MC_TOOLS.NOTIFICATION_INBOX] = createNotificationInboxTool({ storage: new LazyNotificationsStorage(storage) });
71
84
  if (hasTavilyKey()) {
72
85
  tools.web_search = createWebSearchTool();
@@ -100,6 +113,6 @@ function createDynamicTools(mcpManager, extraTools, disabledTools, storage, plug
100
113
  };
101
114
  }
102
115
  //#endregion
103
- export { createDynamicTools, createToolHooks };
116
+ export { LazyNotificationsStorage, createDynamicTools, createToolHooks };
104
117
 
105
118
  //# sourceMappingURL=tools.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","names":[],"sources":["../../src/agents/tools.ts"],"sourcesContent":["import { createAnthropic } from '@ai-sdk/anthropic';\nimport { createOpenAI } from '@ai-sdk/openai';\nimport type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport { createNotificationInboxTool, NotificationsStorage } from '@mastra/core/notifications';\nimport type {\n CreateNotificationInput,\n ListDueNotificationsInput,\n ListNotificationsInput,\n UpdateNotificationInput,\n} from '@mastra/core/notifications';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { MastraCompositeStore } from '@mastra/core/storage';\nimport type { ToolAfterHookContext, ToolHooks } from '@mastra/core/tools';\nimport type { HookManager } from '../hooks/index.js';\nimport type { McpManager } from '../mcp/index.js';\nimport type { MastraCodeComposedState } from '../schema.js';\nimport { MC_TOOLS } from '../tool-names.js';\nimport { createWebSearchTool, createWebExtractTool, hasTavilyKey, requestSandboxAccessTool } from '../tools/index.js';\n\n/** Minimal shape for tools passed to createDynamicTools. */\nexport type ToolLike = {\n execute?: (...args: any[]) => Promise<unknown> | unknown;\n} & Record<string, any>;\n\nclass LazyNotificationsStorage extends NotificationsStorage {\n constructor(private readonly storage: MastraCompositeStore) {\n super();\n }\n\n private async getNotificationsStorage(): Promise<NotificationsStorage> {\n const notifications = await this.storage.getStore('notifications');\n if (!notifications) {\n throw new Error('notification_inbox requires a notifications storage domain');\n }\n return notifications;\n }\n\n async createNotification(input: CreateNotificationInput) {\n return (await this.getNotificationsStorage()).createNotification(input);\n }\n\n async listNotifications(input: ListNotificationsInput) {\n return (await this.getNotificationsStorage()).listNotifications(input);\n }\n\n async listDueNotifications(input: ListDueNotificationsInput) {\n return (await this.getNotificationsStorage()).listDueNotifications(input);\n }\n\n async getNotification(input: { threadId: string; id: string }) {\n return (await this.getNotificationsStorage()).getNotification(input);\n }\n\n async updateNotification(input: UpdateNotificationInput) {\n return (await this.getNotificationsStorage()).updateNotification(input);\n }\n\n async dangerouslyClearAll() {\n return (await this.getNotificationsStorage()).dangerouslyClearAll();\n }\n}\n\nexport type PostToolObserver = (context: ToolAfterHookContext) => void | Promise<void>;\n\nexport function createToolHooks(hookManager?: HookManager, postToolObserver?: PostToolObserver): ToolHooks | undefined {\n if (!hookManager && !postToolObserver) return undefined;\n\n return {\n beforeToolCall: async ({ toolName, input }) => {\n if (!hookManager) return;\n const preResult = await hookManager.runPreToolUse(toolName, input);\n if (!preResult.allowed) {\n return {\n proceed: false as const,\n output: {\n error: preResult.blockReason ?? `Blocked by PreToolUse hook for tool \"${toolName}\"`,\n },\n };\n }\n },\n afterToolCall: async context => {\n const { toolName, input, output, error } = context;\n if (hookManager) {\n const failed = error !== undefined;\n await hookManager\n .runPostToolUse(\n toolName,\n input,\n failed ? { error: error instanceof Error ? error.message : String(error) } : output,\n failed,\n )\n .catch(() => undefined);\n }\n await Promise.resolve()\n .then(() => postToolObserver?.(context))\n .catch(error => {\n console.warn(`[MastraCode] Post-tool observer failed for ${toolName}.`, error);\n });\n },\n };\n}\n\ntype DynamicToolProvider =\n | Record<string, ToolLike | undefined>\n | ((ctx: {\n requestContext: RequestContext;\n }) => Record<string, ToolLike | undefined> | Promise<Record<string, ToolLike | undefined>>);\n\nexport function createDynamicTools(\n mcpManager?: McpManager,\n extraTools?: DynamicToolProvider,\n disabledTools?: string[],\n storage?: MastraCompositeStore,\n pluginTools?: Record<string, ToolLike>,\n) {\n return function getDynamicTools({\n requestContext,\n }: {\n requestContext: RequestContext;\n }): Record<string, ToolLike> | Promise<Record<string, ToolLike>> {\n const ctx = requestContext.get('controller') as AgentControllerRequestContext<MastraCodeComposedState> | undefined;\n const state = ctx?.getState();\n\n const modelId = ctx?.session?.modelId;\n const isAnthropicModel = modelId?.startsWith('anthropic/');\n const isOpenAIModel = modelId?.startsWith('openai/');\n\n // Filesystem, grep, glob, edit, write, execute_command, and process\n // management tools are now provided by the workspace (see workspace.ts).\n // Only tools without a workspace equivalent remain here.\n const tools: Record<string, ToolLike> = {\n request_access: requestSandboxAccessTool,\n };\n\n if (storage) {\n tools[MC_TOOLS.NOTIFICATION_INBOX] = createNotificationInboxTool({\n storage: new LazyNotificationsStorage(storage),\n });\n }\n\n if (hasTavilyKey()) {\n tools.web_search = createWebSearchTool();\n tools.web_extract = createWebExtractTool();\n } else if (isAnthropicModel) {\n const anthropic = createAnthropic({});\n tools.web_search = anthropic.tools.webSearch_20250305();\n } else if (isOpenAIModel) {\n const openai = createOpenAI({});\n tools.web_search = openai.tools.webSearch();\n }\n\n if (mcpManager) {\n const mcpTools = mcpManager.getTools();\n Object.assign(tools, mcpTools);\n }\n\n const finish = (resolvedExtra: Record<string, ToolLike | undefined> | undefined) => {\n if (resolvedExtra) {\n for (const [name, tool] of Object.entries(resolvedExtra)) {\n if (tool && !(name in tools)) {\n tools[name] = tool;\n }\n }\n }\n\n if (pluginTools) {\n for (const [name, tool] of Object.entries(pluginTools)) {\n if (!(name in tools)) {\n tools[name] = tool;\n }\n }\n }\n\n // Remove tools explicitly disabled via config so the model never sees them.\n if (disabledTools?.length) {\n for (const toolName of disabledTools) {\n delete tools[toolName];\n }\n }\n\n // Remove tools that have a per-tool 'deny' policy so the model never sees them.\n const permissionRules = state?.permissionRules;\n if (permissionRules?.tools) {\n for (const [name, policy] of Object.entries(permissionRules.tools)) {\n if (policy === 'deny') {\n delete tools[name];\n }\n }\n }\n\n return tools;\n };\n\n if (typeof extraTools === 'function') {\n const resolved = extraTools({ requestContext });\n // Stay synchronous for sync providers; only go async when the provider does.\n if (resolved && typeof (resolved as PromiseLike<unknown>).then === 'function') {\n return Promise.resolve(resolved).then(finish);\n }\n return finish(resolved as Record<string, ToolLike | undefined>);\n }\n\n return finish(extraTools);\n };\n}\n"],"mappings":";;;;;;;;AAwBA,IAAM,2BAAN,cAAuC,qBAAqB;CAC7B;CAA7B,YAAY,SAAgD;EAC1D,MAAM;EADqB,KAAA,UAAA;CAE7B;CAEA,MAAc,0BAAyD;EACrE,MAAM,gBAAgB,MAAM,KAAK,QAAQ,SAAS,eAAe;EACjE,IAAI,CAAC,eACH,MAAM,IAAI,MAAM,4DAA4D;EAE9E,OAAO;CACT;CAEA,MAAM,mBAAmB,OAAgC;EACvD,QAAQ,MAAM,KAAK,wBAAwB,EAAA,CAAG,mBAAmB,KAAK;CACxE;CAEA,MAAM,kBAAkB,OAA+B;EACrD,QAAQ,MAAM,KAAK,wBAAwB,EAAA,CAAG,kBAAkB,KAAK;CACvE;CAEA,MAAM,qBAAqB,OAAkC;EAC3D,QAAQ,MAAM,KAAK,wBAAwB,EAAA,CAAG,qBAAqB,KAAK;CAC1E;CAEA,MAAM,gBAAgB,OAAyC;EAC7D,QAAQ,MAAM,KAAK,wBAAwB,EAAA,CAAG,gBAAgB,KAAK;CACrE;CAEA,MAAM,mBAAmB,OAAgC;EACvD,QAAQ,MAAM,KAAK,wBAAwB,EAAA,CAAG,mBAAmB,KAAK;CACxE;CAEA,MAAM,sBAAsB;EAC1B,QAAQ,MAAM,KAAK,wBAAwB,EAAA,CAAG,oBAAoB;CACpE;AACF;AAIA,SAAgB,gBAAgB,aAA2B,kBAA4D;CACrH,IAAI,CAAC,eAAe,CAAC,kBAAkB,OAAO,KAAA;CAE9C,OAAO;EACL,gBAAgB,OAAO,EAAE,UAAU,YAAY;GAC7C,IAAI,CAAC,aAAa;GAClB,MAAM,YAAY,MAAM,YAAY,cAAc,UAAU,KAAK;GACjE,IAAI,CAAC,UAAU,SACb,OAAO;IACL,SAAS;IACT,QAAQ,EACN,OAAO,UAAU,eAAe,wCAAwC,SAAS,GACnF;GACF;EAEJ;EACA,eAAe,OAAM,YAAW;GAC9B,MAAM,EAAE,UAAU,OAAO,QAAQ,UAAU;GAC3C,IAAI,aAAa;IACf,MAAM,SAAS,UAAU,KAAA;IACzB,MAAM,YACH,eACC,UACA,OACA,SAAS,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,IAAI,QAC7E,MACF,CAAC,CACA,YAAY,KAAA,CAAS;GAC1B;GACA,MAAM,QAAQ,QAAQ,CAAC,CACpB,WAAW,mBAAmB,OAAO,CAAC,CAAC,CACvC,OAAM,UAAS;IACd,QAAQ,KAAK,8CAA8C,SAAS,IAAI,KAAK;GAC/E,CAAC;EACL;CACF;AACF;AAQA,SAAgB,mBACd,YACA,YACA,eACA,SACA,aACA;CACA,OAAO,SAAS,gBAAgB,EAC9B,kBAG+D;EAC/D,MAAM,MAAM,eAAe,IAAI,YAAY;EAC3C,MAAM,QAAQ,KAAK,SAAS;EAE5B,MAAM,UAAU,KAAK,SAAS;EAC9B,MAAM,mBAAmB,SAAS,WAAW,YAAY;EACzD,MAAM,gBAAgB,SAAS,WAAW,SAAS;EAKnD,MAAM,QAAkC,EACtC,gBAAgB,yBAClB;EAEA,IAAI,SACF,MAAM,SAAS,sBAAsB,4BAA4B,EAC/D,SAAS,IAAI,yBAAyB,OAAO,EAC/C,CAAC;EAGH,IAAI,aAAa,GAAG;GAClB,MAAM,aAAa,oBAAoB;GACvC,MAAM,cAAc,qBAAqB;EAC3C,OAAO,IAAI,kBAET,MAAM,aADY,gBAAgB,CAAC,CACR,CAAC,CAAC,MAAM,mBAAmB;OACjD,IAAI,eAET,MAAM,aADS,aAAa,CAAC,CACL,CAAC,CAAC,MAAM,UAAU;EAG5C,IAAI,YAAY;GACd,MAAM,WAAW,WAAW,SAAS;GACrC,OAAO,OAAO,OAAO,QAAQ;EAC/B;EAEA,MAAM,UAAU,kBAAoE;GAClF,IAAI,eACG;SAAA,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,aAAa,GACrD,IAAI,QAAQ,EAAE,QAAQ,QACpB,MAAM,QAAQ;GAAA;GAKpB,IAAI,aACG;SAAA,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,WAAW,GACnD,IAAI,EAAE,QAAQ,QACZ,MAAM,QAAQ;GAAA;GAMpB,IAAI,eAAe,QACjB,KAAK,MAAM,YAAY,eACrB,OAAO,MAAM;GAKjB,MAAM,kBAAkB,OAAO;GAC/B,IAAI,iBAAiB,OACd;SAAA,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,gBAAgB,KAAK,GAC/D,IAAI,WAAW,QACb,OAAO,MAAM;GAAA;GAKnB,OAAO;EACT;EAEA,IAAI,OAAO,eAAe,YAAY;GACpC,MAAM,WAAW,WAAW,EAAE,eAAe,CAAC;GAE9C,IAAI,YAAY,OAAQ,SAAkC,SAAS,YACjE,OAAO,QAAQ,QAAQ,QAAQ,CAAC,CAAC,KAAK,MAAM;GAE9C,OAAO,OAAO,QAAgD;EAChE;EAEA,OAAO,OAAO,UAAU;CAC1B;AACF"}
1
+ {"version":3,"file":"tools.js","names":[],"sources":["../../src/agents/tools.ts"],"sourcesContent":["import { createAnthropic } from '@ai-sdk/anthropic';\nimport { createOpenAI } from '@ai-sdk/openai';\nimport type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport { createNotificationInboxTool, NotificationsStorage } from '@mastra/core/notifications';\nimport type {\n CreateNotificationInput,\n ListDueNotificationsInput,\n ListNotificationsInput,\n UpdateNotificationInput,\n} from '@mastra/core/notifications';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { MastraCompositeStore } from '@mastra/core/storage';\nimport type { ToolAfterHookContext, ToolHooks } from '@mastra/core/tools';\nimport type { HookManager } from '../hooks/index.js';\nimport type { McpManager } from '../mcp/index.js';\nimport type { MastraCodeComposedState } from '../schema.js';\nimport { MC_TOOLS } from '../tool-names.js';\nimport { createWebSearchTool, createWebExtractTool, hasTavilyKey, requestSandboxAccessTool } from '../tools/index.js';\nimport { createWorkflowTool } from '../tools/workflows/create-workflow.js';\nimport { deleteWorkflowTool } from '../tools/workflows/delete-workflow.js';\nimport { getWorkflowTool } from '../tools/workflows/get-workflow.js';\nimport { listWorkflowsTool } from '../tools/workflows/list-workflows.js';\nimport { runWorkflowTool } from '../tools/workflows/run-workflow.js';\nimport { WORKFLOW_MANAGEMENT_TOOL_IDS } from '../tools/workflows/tool-ids.js';\n\n/** Minimal shape for tools passed to createDynamicTools. */\nexport type ToolLike = {\n execute?: (...args: any[]) => Promise<unknown> | unknown;\n} & Record<string, any>;\n\nexport class LazyNotificationsStorage extends NotificationsStorage {\n constructor(private readonly storage: MastraCompositeStore) {\n super();\n }\n\n private async getNotificationsStorage(): Promise<NotificationsStorage> {\n const notifications = await this.storage.getStore('notifications');\n if (!notifications) {\n throw new Error('notification_inbox requires a notifications storage domain');\n }\n return notifications;\n }\n\n async createNotification(input: CreateNotificationInput) {\n return (await this.getNotificationsStorage()).createNotification(input);\n }\n\n async listNotifications(input: ListNotificationsInput) {\n return (await this.getNotificationsStorage()).listNotifications(input);\n }\n\n async listDueNotifications(input: ListDueNotificationsInput) {\n return (await this.getNotificationsStorage()).listDueNotifications(input);\n }\n\n async getNotification(input: { threadId: string; id: string }) {\n return (await this.getNotificationsStorage()).getNotification(input);\n }\n\n async updateNotification(input: UpdateNotificationInput) {\n return (await this.getNotificationsStorage()).updateNotification(input);\n }\n\n async dangerouslyClearAll() {\n return (await this.getNotificationsStorage()).dangerouslyClearAll();\n }\n}\n\nexport type PostToolObserver = (context: ToolAfterHookContext) => void | Promise<void>;\n\nexport function createToolHooks(hookManager?: HookManager, postToolObserver?: PostToolObserver): ToolHooks | undefined {\n if (!hookManager && !postToolObserver) return undefined;\n\n return {\n beforeToolCall: async ({ toolName, input }) => {\n if (!hookManager) return;\n const preResult = await hookManager.runPreToolUse(toolName, input);\n if (!preResult.allowed) {\n return {\n proceed: false as const,\n output: {\n error: preResult.blockReason ?? `Blocked by PreToolUse hook for tool \"${toolName}\"`,\n },\n };\n }\n },\n afterToolCall: async context => {\n const { toolName, input, output, error } = context;\n if (hookManager) {\n const failed = error !== undefined;\n await hookManager\n .runPostToolUse(\n toolName,\n input,\n failed ? { error: error instanceof Error ? error.message : String(error) } : output,\n failed,\n )\n .catch(() => undefined);\n }\n await Promise.resolve()\n .then(() => postToolObserver?.(context))\n .catch(error => {\n console.warn(`[MastraCode] Post-tool observer failed for ${toolName}.`, error);\n });\n },\n };\n}\n\ntype DynamicToolProvider =\n | Record<string, ToolLike | undefined>\n | ((ctx: {\n requestContext: RequestContext;\n }) => Record<string, ToolLike | undefined> | Promise<Record<string, ToolLike | undefined>>);\n\nexport function createDynamicTools(\n mcpManager?: McpManager,\n extraTools?: DynamicToolProvider,\n disabledTools?: string[],\n storage?: MastraCompositeStore,\n pluginTools?: Record<string, ToolLike>,\n) {\n return function getDynamicTools({\n requestContext,\n }: {\n requestContext: RequestContext;\n }): Record<string, ToolLike> | Promise<Record<string, ToolLike>> {\n const ctx = requestContext.get('controller') as AgentControllerRequestContext<MastraCodeComposedState> | undefined;\n const state = ctx?.getState();\n\n const modelId = ctx?.session?.modelId;\n const isAnthropicModel = modelId?.startsWith('anthropic/');\n const isOpenAIModel = modelId?.startsWith('openai/');\n\n // Filesystem, grep, glob, edit, write, execute_command, and process\n // management tools are now provided by the workspace (see workspace.ts).\n // Only tools without a workspace equivalent remain here.\n const tools: Record<string, ToolLike> = {\n request_access: requestSandboxAccessTool,\n // Workflow surface. `create-workflow` delegates to the workflow-builder\n // sub-agent; the other four are Dynamic Workflow management operations.\n // Permission categories live in permissions.ts (TOOL_CATEGORY_MAP).\n [WORKFLOW_MANAGEMENT_TOOL_IDS.createWorkflow]: createWorkflowTool,\n [WORKFLOW_MANAGEMENT_TOOL_IDS.listWorkflows]: listWorkflowsTool,\n [WORKFLOW_MANAGEMENT_TOOL_IDS.getWorkflow]: getWorkflowTool,\n [WORKFLOW_MANAGEMENT_TOOL_IDS.runWorkflow]: runWorkflowTool,\n [WORKFLOW_MANAGEMENT_TOOL_IDS.deleteWorkflow]: deleteWorkflowTool,\n };\n\n if (storage) {\n tools[MC_TOOLS.NOTIFICATION_INBOX] = createNotificationInboxTool({\n storage: new LazyNotificationsStorage(storage),\n });\n }\n\n if (hasTavilyKey()) {\n tools.web_search = createWebSearchTool();\n tools.web_extract = createWebExtractTool();\n } else if (isAnthropicModel) {\n const anthropic = createAnthropic({});\n tools.web_search = anthropic.tools.webSearch_20250305();\n } else if (isOpenAIModel) {\n const openai = createOpenAI({});\n tools.web_search = openai.tools.webSearch();\n }\n\n if (mcpManager) {\n const mcpTools = mcpManager.getTools();\n Object.assign(tools, mcpTools);\n }\n\n const finish = (resolvedExtra: Record<string, ToolLike | undefined> | undefined) => {\n if (resolvedExtra) {\n for (const [name, tool] of Object.entries(resolvedExtra)) {\n if (tool && !(name in tools)) {\n tools[name] = tool;\n }\n }\n }\n\n if (pluginTools) {\n for (const [name, tool] of Object.entries(pluginTools)) {\n if (!(name in tools)) {\n tools[name] = tool;\n }\n }\n }\n\n // Remove tools explicitly disabled via config so the model never sees them.\n if (disabledTools?.length) {\n for (const toolName of disabledTools) {\n delete tools[toolName];\n }\n }\n\n // Remove tools that have a per-tool 'deny' policy so the model never sees them.\n const permissionRules = state?.permissionRules;\n if (permissionRules?.tools) {\n for (const [name, policy] of Object.entries(permissionRules.tools)) {\n if (policy === 'deny') {\n delete tools[name];\n }\n }\n }\n\n return tools;\n };\n\n if (typeof extraTools === 'function') {\n const resolved = extraTools({ requestContext });\n // Stay synchronous for sync providers; only go async when the provider does.\n if (resolved && typeof (resolved as PromiseLike<unknown>).then === 'function') {\n return Promise.resolve(resolved).then(finish);\n }\n return finish(resolved as Record<string, ToolLike | undefined>);\n }\n\n return finish(extraTools);\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const workflowBuilderAgent: import("@mastra/core/agent").Agent<"workflow-builder", import("@mastra/core/agent").ToolsInput, undefined, unknown, import("@mastra/core/agent").AgentEditorConfig | undefined>;
2
+ //# sourceMappingURL=workflow-builder-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-builder-agent.d.ts","sourceRoot":"","sources":["../../src/agents/workflow-builder-agent.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,oBAAoB,iLA2D/B,CAAC"}
@@ -0,0 +1,80 @@
1
+ import { getDynamicModel } from "./model.js";
2
+ import { WORKFLOW_AUTHORING_TOOL_IDS } from "../tools/workflows/tool-ids.js";
3
+ import { listAvailableAgentsTool } from "../tools/workflows/list-available-agents.js";
4
+ import { listAvailableToolsTool } from "../tools/workflows/list-available-tools.js";
5
+ import { listAvailableWorkflowsTool } from "../tools/workflows/list-available-workflows.js";
6
+ import { saveWorkflowTool } from "../tools/workflows/save-workflow.js";
7
+ import { createWorkflowBuilderAgent } from "@mastra/core/workflows/builder";
8
+ //#region src/agents/workflow-builder-agent.ts
9
+ /**
10
+ * Workflow Builder sub-agent.
11
+ *
12
+ * The parent code-agent (build/plan/explore modes) delegates to this agent
13
+ * via the `create-workflow` tool. Keeping the long workflow-authoring system
14
+ * prompt here — instead of inlining it into every parent mode — keeps the
15
+ * parent modes lean and lets the same author logic ship to Studio later.
16
+ *
17
+ * The sub-agent's tool set is intentionally tiny: discover what's available,
18
+ * construct the entire definition in one thought, save it. No setter loop,
19
+ * no per-step mutations.
20
+ */
21
+ const workflowBuilderAgent = createWorkflowBuilderAgent({
22
+ id: "workflow-builder",
23
+ name: "Workflow Builder",
24
+ description: "Turns plain-language workflow descriptions into runnable, persisted workflow definitions.",
25
+ tools: {
26
+ [WORKFLOW_AUTHORING_TOOL_IDS.listAgents]: listAvailableAgentsTool,
27
+ [WORKFLOW_AUTHORING_TOOL_IDS.listTools]: listAvailableToolsTool,
28
+ [WORKFLOW_AUTHORING_TOOL_IDS.listWorkflows]: listAvailableWorkflowsTool,
29
+ [WORKFLOW_AUTHORING_TOOL_IDS.saveWorkflow]: saveWorkflowTool
30
+ },
31
+ surfaceInstructions: `# Mastra Code authoring policy
32
+
33
+ Your job: turn the user's verbatim plain-language request into a complete Dynamic Workflow definition and persist it with save-workflow. Success means save-workflow returned \`{ ok: true, id }\` for the workflow the user asked for; do not claim success before that result.
34
+
35
+ Save each definition successfully **exactly once**: after \`save-workflow\` returns \`{ ok: true, id }\`, never save that workflow again. The workflow the user asked for is always saved LAST. You may save other workflows before it **only** when they are helper workflows the requested workflow references as \`{ type: "workflow" }\` entries — never to probe the schema or split one workflow into pieces the user did not ask for. A rejected save is not a successful save; correct the reported issues and make the one sequential corrected attempt permitted by the protocol below.
36
+
37
+ # \`code-agent\` — when to use it as an agent step
38
+
39
+ The Mastra instance registers \`code-agent\` (mastracode's coding agent) alongside the workflow-builder. When discovery surfaces it in \`list-available-agents\`, know that under the hood it has full access to workspace tools (view / edit / run commands), MCP tools, and web search — and it *reasons* over a prompt to pick the right ones.
40
+
41
+ Use it as an \`agent\` step when the workflow needs judgment or open-ended tool orchestration you can't hardcode — e.g. "read these files and figure out what changed", "review these logs and summarise the failures", "call the right MCP tool to open a Linear issue based on this content".
42
+
43
+ When the workflow needs a **specific, deterministic** operation (like \`execute_command wc -l file.ts\` or a single fixed web-search call), prefer a plain \`tool\` step — cheaper, no LLM in the middle, and reproducible.
44
+
45
+ # Workspace tool output shapes — read this before wiring a file-oriented workflow
46
+
47
+ The workspace tools you are most likely to compose with return **strings, not objects**, and the shared bridge-agent and \`initData\` re-threading guidance applies to them directly:
48
+
49
+ - \`find_files\` returns a formatted \`string\` listing, and the entries are **bare basenames with no path prefix** (e.g. \`app-tools.ts\\nserver.ts\`). A downstream step told only "summarise each file" therefore has no idea which folder they live in.
50
+ - \`find_files\` — inputSchema \`{ path?: string, ... }\`, outputSchema tree-formatted text (string).
51
+ - \`view\` — inputSchema \`{ path: string, ... }\`, outputSchema \`string | { __workspaceMedia: true, text: string, mediaType: string, data: string }\`.
52
+
53
+ Two consequences, both covered by the shared playbook's worked examples:
54
+
55
+ 1. A string listing is not iterable, so \`foreach\` needs a bridge \`agent\` step with a top-level array \`outputSchema\` between the listing tool and the loop.
56
+ 2. Because the listing strips the folder path, the mapping that builds the bridge agent's prompt MUST re-thread the original path with \`\${initData.<pathField>}\` alongside \`\${stepResults.<listing-step>}\`. Skipping this is the most common cause of downstream "file not found" failures.
57
+
58
+ Always confirm these shapes against \`list-available-tools\` rather than trusting the summary above.
59
+
60
+ # Mastra Code discovery notes
61
+
62
+ The three shared listing tools behave here exactly as the shared playbook describes; each row's \`id\` is the value you copy into \`agentId\` / \`toolId\` / \`workflowId\`. \`list-available-workflows\` includes both code-defined and Dynamic Workflows, and its catalog is always available on this surface.
63
+
64
+ Your fourth tool is \`save-workflow\`, which persists and live-registers a definition. Make one sequential complete call per attempt, only after composition and the shared pre-action check.
65
+
66
+ # Mastra Code execution and response protocol
67
+
68
+ 1. Complete discovery, composition, and the shared pre-action check before calling \`save-workflow\`.
69
+ 2. If the design needs helper workflows (for example, per-branch wrappers so \`parallel\` branches can consume different fields — see the shared nested-workflow guidance), save each helper FIRST, one complete definition per call, in dependency order. Each \`save-workflow\` success live-registers that helper, which makes it a valid \`workflowId\` for the next definition. Confirm with \`list-available-workflows\` before referencing it, and give each helper a real \`id\` and \`description\` — helpers are permanent, user-visible registry entries, not scratch space.
70
+ 3. Call \`save-workflow\` with one complete \`{ id, description, inputSchema, outputSchema, graph }\` definition for the requested workflow. There are no incremental setter tools and no parallel save attempts.
71
+ 4. Wait for the tool result. Success means exactly that \`save-workflow\` returned \`{ ok: true, id }\`; at that point the workflow is persisted and live-registered.
72
+ 5. If the tool rejects the definition, do not claim success. Use the returned diagnostics and authoritative discovery to correct every named issue, rerun the shared pre-action check, and make one sequential corrected complete save attempt. Do not rationalize a registry mismatch as a missing engine feature.
73
+ 6. After success, follow the shared summary rules and end with the concrete run command \`/workflows run <id> {…}\` for the requested workflow. If you saved helper workflows, name them so the user knows they now exist in the registry.
74
+ `,
75
+ model: getDynamicModel
76
+ });
77
+ //#endregion
78
+ export { workflowBuilderAgent };
79
+
80
+ //# sourceMappingURL=workflow-builder-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-builder-agent.js","names":[],"sources":["../../src/agents/workflow-builder-agent.ts"],"sourcesContent":["/**\n * Workflow Builder sub-agent.\n *\n * The parent code-agent (build/plan/explore modes) delegates to this agent\n * via the `create-workflow` tool. Keeping the long workflow-authoring system\n * prompt here — instead of inlining it into every parent mode — keeps the\n * parent modes lean and lets the same author logic ship to Studio later.\n *\n * The sub-agent's tool set is intentionally tiny: discover what's available,\n * construct the entire definition in one thought, save it. No setter loop,\n * no per-step mutations.\n */\nimport { createWorkflowBuilderAgent } from '@mastra/core/workflows/builder';\nimport { listAvailableAgentsTool } from '../tools/workflows/list-available-agents.js';\nimport { listAvailableToolsTool } from '../tools/workflows/list-available-tools.js';\nimport { listAvailableWorkflowsTool } from '../tools/workflows/list-available-workflows.js';\nimport { saveWorkflowTool } from '../tools/workflows/save-workflow.js';\nimport { WORKFLOW_AUTHORING_TOOL_IDS } from '../tools/workflows/tool-ids.js';\nimport { getDynamicModel } from './model.js';\n\nexport const workflowBuilderAgent = createWorkflowBuilderAgent({\n id: 'workflow-builder',\n name: 'Workflow Builder',\n description: 'Turns plain-language workflow descriptions into runnable, persisted workflow definitions.',\n tools: {\n [WORKFLOW_AUTHORING_TOOL_IDS.listAgents]: listAvailableAgentsTool,\n [WORKFLOW_AUTHORING_TOOL_IDS.listTools]: listAvailableToolsTool,\n [WORKFLOW_AUTHORING_TOOL_IDS.listWorkflows]: listAvailableWorkflowsTool,\n [WORKFLOW_AUTHORING_TOOL_IDS.saveWorkflow]: saveWorkflowTool,\n },\n surfaceInstructions: `# Mastra Code authoring policy\n\nYour job: turn the user's verbatim plain-language request into a complete Dynamic Workflow definition and persist it with save-workflow. Success means save-workflow returned \\`{ ok: true, id }\\` for the workflow the user asked for; do not claim success before that result.\n\nSave each definition successfully **exactly once**: after \\`save-workflow\\` returns \\`{ ok: true, id }\\`, never save that workflow again. The workflow the user asked for is always saved LAST. You may save other workflows before it **only** when they are helper workflows the requested workflow references as \\`{ type: \"workflow\" }\\` entries — never to probe the schema or split one workflow into pieces the user did not ask for. A rejected save is not a successful save; correct the reported issues and make the one sequential corrected attempt permitted by the protocol below.\n\n# \\`code-agent\\` — when to use it as an agent step\n\nThe Mastra instance registers \\`code-agent\\` (mastracode's coding agent) alongside the workflow-builder. When discovery surfaces it in \\`list-available-agents\\`, know that under the hood it has full access to workspace tools (view / edit / run commands), MCP tools, and web search — and it *reasons* over a prompt to pick the right ones.\n\nUse it as an \\`agent\\` step when the workflow needs judgment or open-ended tool orchestration you can't hardcode — e.g. \"read these files and figure out what changed\", \"review these logs and summarise the failures\", \"call the right MCP tool to open a Linear issue based on this content\".\n\nWhen the workflow needs a **specific, deterministic** operation (like \\`execute_command wc -l file.ts\\` or a single fixed web-search call), prefer a plain \\`tool\\` step — cheaper, no LLM in the middle, and reproducible.\n\n# Workspace tool output shapes — read this before wiring a file-oriented workflow\n\nThe workspace tools you are most likely to compose with return **strings, not objects**, and the shared bridge-agent and \\`initData\\` re-threading guidance applies to them directly:\n\n- \\`find_files\\` returns a formatted \\`string\\` listing, and the entries are **bare basenames with no path prefix** (e.g. \\`app-tools.ts\\\\nserver.ts\\`). A downstream step told only \"summarise each file\" therefore has no idea which folder they live in.\n- \\`find_files\\` — inputSchema \\`{ path?: string, ... }\\`, outputSchema tree-formatted text (string).\n- \\`view\\` — inputSchema \\`{ path: string, ... }\\`, outputSchema \\`string | { __workspaceMedia: true, text: string, mediaType: string, data: string }\\`.\n\nTwo consequences, both covered by the shared playbook's worked examples:\n\n1. A string listing is not iterable, so \\`foreach\\` needs a bridge \\`agent\\` step with a top-level array \\`outputSchema\\` between the listing tool and the loop.\n2. Because the listing strips the folder path, the mapping that builds the bridge agent's prompt MUST re-thread the original path with \\`\\${initData.<pathField>}\\` alongside \\`\\${stepResults.<listing-step>}\\`. Skipping this is the most common cause of downstream \"file not found\" failures.\n\nAlways confirm these shapes against \\`list-available-tools\\` rather than trusting the summary above.\n\n# Mastra Code discovery notes\n\nThe three shared listing tools behave here exactly as the shared playbook describes; each row's \\`id\\` is the value you copy into \\`agentId\\` / \\`toolId\\` / \\`workflowId\\`. \\`list-available-workflows\\` includes both code-defined and Dynamic Workflows, and its catalog is always available on this surface.\n\nYour fourth tool is \\`save-workflow\\`, which persists and live-registers a definition. Make one sequential complete call per attempt, only after composition and the shared pre-action check.\n\n# Mastra Code execution and response protocol\n\n1. Complete discovery, composition, and the shared pre-action check before calling \\`save-workflow\\`.\n2. If the design needs helper workflows (for example, per-branch wrappers so \\`parallel\\` branches can consume different fields — see the shared nested-workflow guidance), save each helper FIRST, one complete definition per call, in dependency order. Each \\`save-workflow\\` success live-registers that helper, which makes it a valid \\`workflowId\\` for the next definition. Confirm with \\`list-available-workflows\\` before referencing it, and give each helper a real \\`id\\` and \\`description\\` — helpers are permanent, user-visible registry entries, not scratch space.\n3. Call \\`save-workflow\\` with one complete \\`{ id, description, inputSchema, outputSchema, graph }\\` definition for the requested workflow. There are no incremental setter tools and no parallel save attempts.\n4. Wait for the tool result. Success means exactly that \\`save-workflow\\` returned \\`{ ok: true, id }\\`; at that point the workflow is persisted and live-registered.\n5. If the tool rejects the definition, do not claim success. Use the returned diagnostics and authoritative discovery to correct every named issue, rerun the shared pre-action check, and make one sequential corrected complete save attempt. Do not rationalize a registry mismatch as a missing engine feature.\n6. After success, follow the shared summary rules and end with the concrete run command \\`/workflows run <id> {…}\\` for the requested workflow. If you saved helper workflows, name them so the user knows they now exist in the registry.\n`,\n // Same dynamic model resolver mastracode's main code-agent uses — picks up\n // the user's configured provider/model from session state. When the parent\n // code-agent delegates to this sub-agent (via `create-workflow`), the\n // request context propagates so the same model resolves.\n model: getDynamicModel,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,uBAAuB,2BAA2B;CAC7D,IAAI;CACJ,MAAM;CACN,aAAa;CACb,OAAO;GACJ,4BAA4B,aAAa;GACzC,4BAA4B,YAAY;GACxC,4BAA4B,gBAAgB;GAC5C,4BAA4B,eAAe;CAC9C;CACA,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDrB,OAAO;AACT,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/headless/cli.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEzE,kFAAkF;AAClF,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAcvD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,CAsC9D;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CA+BzC;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CA+G9E"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/headless/cli.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEzE,kFAAkF;AAClF,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAcvD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,CAsC9D;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CA+BzC;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAuH9E"}
@@ -179,6 +179,9 @@ async function runMCCli(predrainedInput) {
179
179
  exitCode = 1;
180
180
  } finally {
181
181
  releaseAllThreadLocks();
182
+ try {
183
+ boot.stopPluginSignalProviders();
184
+ } catch {}
182
185
  const closeSignalsPubSub = boot.signalsPubSub?.close;
183
186
  await Promise.allSettled([
184
187
  mcpManager?.disconnect(),