@mastra/code-sdk 1.0.3-alpha.0 → 1.1.0-alpha.2

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 (258) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/dist/acp/agent.js +155 -167
  3. package/dist/acp/agent.js.map +1 -1
  4. package/dist/acp/event-mapper.js +193 -168
  5. package/dist/acp/event-mapper.js.map +1 -1
  6. package/dist/acp/index.js +60 -49
  7. package/dist/acp/index.js.map +1 -1
  8. package/dist/acp/server.js +31 -30
  9. package/dist/acp/server.js.map +1 -1
  10. package/dist/acp.js +1 -4
  11. package/dist/agents/credential-resolver.js +40 -29
  12. package/dist/agents/credential-resolver.js.map +1 -1
  13. package/dist/agents/custom-provider-source.js +16 -9
  14. package/dist/agents/custom-provider-source.js.map +1 -1
  15. package/dist/agents/instructions.js +27 -36
  16. package/dist/agents/instructions.js.map +1 -1
  17. package/dist/agents/mastracode-gateway.js +355 -428
  18. package/dist/agents/mastracode-gateway.js.map +1 -1
  19. package/dist/agents/memory.js +87 -78
  20. package/dist/agents/memory.js.map +1 -1
  21. package/dist/agents/model.js +114 -119
  22. package/dist/agents/model.js.map +1 -1
  23. package/dist/agents/modes/build.js +12 -13
  24. package/dist/agents/modes/build.js.map +1 -1
  25. package/dist/agents/modes/explore.js +14 -13
  26. package/dist/agents/modes/explore.js.map +1 -1
  27. package/dist/agents/modes/plan.js +14 -15
  28. package/dist/agents/modes/plan.js.map +1 -1
  29. package/dist/agents/prompts/agent-instructions.js +78 -69
  30. package/dist/agents/prompts/agent-instructions.js.map +1 -1
  31. package/dist/agents/prompts/build.js +19 -16
  32. package/dist/agents/prompts/build.js.map +1 -1
  33. package/dist/agents/prompts/fast.js +8 -4
  34. package/dist/agents/prompts/fast.js.map +1 -1
  35. package/dist/agents/prompts/index.js +48 -47
  36. package/dist/agents/prompts/index.js.map +1 -1
  37. package/dist/agents/prompts/model.js +6 -5
  38. package/dist/agents/prompts/model.js.map +1 -1
  39. package/dist/agents/prompts/plan.js +20 -16
  40. package/dist/agents/prompts/plan.js.map +1 -1
  41. package/dist/agents/prompts/tool-guidance.js +77 -109
  42. package/dist/agents/prompts/tool-guidance.js.map +1 -1
  43. package/dist/agents/sandbox-filesystem.js +245 -259
  44. package/dist/agents/sandbox-filesystem.js.map +1 -1
  45. package/dist/agents/sandbox-reattach.js +9 -11
  46. package/dist/agents/sandbox-reattach.js.map +1 -1
  47. package/dist/agents/thread-caveman-state.js +92 -81
  48. package/dist/agents/thread-caveman-state.js.map +1 -1
  49. package/dist/agents/tool-availability.js +62 -80
  50. package/dist/agents/tool-availability.js.map +1 -1
  51. package/dist/agents/tools.js +99 -139
  52. package/dist/agents/tools.js.map +1 -1
  53. package/dist/agents/workspace.js +232 -225
  54. package/dist/agents/workspace.js.map +1 -1
  55. package/dist/analytics.js +139 -128
  56. package/dist/analytics.js.map +1 -1
  57. package/dist/auth/authorization-input.js +39 -25
  58. package/dist/auth/authorization-input.js.map +1 -1
  59. package/dist/auth/device-code.js +112 -80
  60. package/dist/auth/device-code.js.map +1 -1
  61. package/dist/auth/index.js +2 -9
  62. package/dist/auth/pkce.js +27 -16
  63. package/dist/auth/pkce.js.map +1 -1
  64. package/dist/auth/providers/anthropic.js +107 -93
  65. package/dist/auth/providers/anthropic.js.map +1 -1
  66. package/dist/auth/providers/github-copilot.js +304 -293
  67. package/dist/auth/providers/github-copilot.js.map +1 -1
  68. package/dist/auth/providers/openai-codex.js +442 -460
  69. package/dist/auth/providers/openai-codex.js.map +1 -1
  70. package/dist/auth/providers/xai.js +179 -145
  71. package/dist/auth/providers/xai.js.map +1 -1
  72. package/dist/auth/storage.js +182 -175
  73. package/dist/auth/storage.js.map +1 -1
  74. package/dist/auth/types.js +1 -1
  75. package/dist/clipboard/index.js +206 -172
  76. package/dist/clipboard/index.js.map +1 -1
  77. package/dist/constants.js +11 -16
  78. package/dist/constants.js.map +1 -1
  79. package/dist/error-classification.js +19 -11
  80. package/dist/error-classification.js.map +1 -1
  81. package/dist/evals/context-builder.js +145 -104
  82. package/dist/evals/context-builder.js.map +1 -1
  83. package/dist/evals/index.js +4 -7
  84. package/dist/evals/scorers/classify-command.js +62 -41
  85. package/dist/evals/scorers/classify-command.js.map +1 -1
  86. package/dist/evals/scorers/efficiency.js +239 -181
  87. package/dist/evals/scorers/efficiency.js.map +1 -1
  88. package/dist/evals/scorers/extract-tools.js +51 -47
  89. package/dist/evals/scorers/extract-tools.js.map +1 -1
  90. package/dist/evals/scorers/index.js +1 -5
  91. package/dist/evals/scorers/outcome.js +321 -212
  92. package/dist/evals/scorers/outcome.js.map +1 -1
  93. package/dist/goal-manager.js +266 -261
  94. package/dist/goal-manager.js.map +1 -1
  95. package/dist/goal-signal.js +14 -13
  96. package/dist/goal-signal.js.map +1 -1
  97. package/dist/headless/cli.js +153 -154
  98. package/dist/headless/cli.js.map +1 -1
  99. package/dist/headless/flags.js +180 -178
  100. package/dist/headless/flags.js.map +1 -1
  101. package/dist/headless/format.js +72 -71
  102. package/dist/headless/format.js.map +1 -1
  103. package/dist/headless/index.js +5 -31
  104. package/dist/headless/policy.js +35 -31
  105. package/dist/headless/policy.js.map +1 -1
  106. package/dist/headless/run-mc.js +332 -334
  107. package/dist/headless/run-mc.js.map +1 -1
  108. package/dist/headless/types.js +16 -7
  109. package/dist/headless/types.js.map +1 -1
  110. package/dist/hooks/config.js +56 -61
  111. package/dist/hooks/config.js.map +1 -1
  112. package/dist/hooks/executor.js +118 -116
  113. package/dist/hooks/executor.js.map +1 -1
  114. package/dist/hooks/index.js +4 -15
  115. package/dist/hooks/manager.js +221 -280
  116. package/dist/hooks/manager.js.map +1 -1
  117. package/dist/hooks/types.js +5 -4
  118. package/dist/hooks/types.js.map +1 -1
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +632 -712
  121. package/dist/index.js.map +1 -1
  122. package/dist/ipc/ipc-reporter.js +19 -22
  123. package/dist/ipc/ipc-reporter.js.map +1 -1
  124. package/dist/lsp/client.js +248 -306
  125. package/dist/lsp/client.js.map +1 -1
  126. package/dist/lsp/index.js +1 -6
  127. package/dist/lsp/language.js +39 -43
  128. package/dist/lsp/language.js.map +1 -1
  129. package/dist/lsp/manager.js +78 -93
  130. package/dist/lsp/manager.js.map +1 -1
  131. package/dist/lsp/server.js +151 -120
  132. package/dist/lsp/server.js.map +1 -1
  133. package/dist/lsp/workspace.js +50 -47
  134. package/dist/lsp/workspace.js.map +1 -1
  135. package/dist/mcp/config.js +210 -199
  136. package/dist/mcp/config.js.map +1 -1
  137. package/dist/mcp/index.js +2 -9
  138. package/dist/mcp/manager.js +482 -475
  139. package/dist/mcp/manager.js.map +1 -1
  140. package/dist/mcp/types.js +1 -1
  141. package/dist/onboarding/custom-packs.js +14 -17
  142. package/dist/onboarding/custom-packs.js.map +1 -1
  143. package/dist/onboarding/custom-providers.js +22 -20
  144. package/dist/onboarding/custom-providers.js.map +1 -1
  145. package/dist/onboarding/index.d.ts +1 -1
  146. package/dist/onboarding/index.d.ts.map +1 -1
  147. package/dist/onboarding/index.js +3 -21
  148. package/dist/onboarding/om-settings.d.ts +5 -0
  149. package/dist/onboarding/om-settings.d.ts.map +1 -1
  150. package/dist/onboarding/om-settings.js +41 -20
  151. package/dist/onboarding/om-settings.js.map +1 -1
  152. package/dist/onboarding/packs.d.ts +4 -6
  153. package/dist/onboarding/packs.d.ts.map +1 -1
  154. package/dist/onboarding/packs.js +154 -105
  155. package/dist/onboarding/packs.js.map +1 -1
  156. package/dist/onboarding/settings.js +575 -517
  157. package/dist/onboarding/settings.js.map +1 -1
  158. package/dist/permissions.js +112 -99
  159. package/dist/permissions.js.map +1 -1
  160. package/dist/plugin.js +21 -23
  161. package/dist/plugin.js.map +1 -1
  162. package/dist/plugins/dependencies.js +64 -87
  163. package/dist/plugins/dependencies.js.map +1 -1
  164. package/dist/plugins/install.js +159 -169
  165. package/dist/plugins/install.js.map +1 -1
  166. package/dist/plugins/loader.js +170 -185
  167. package/dist/plugins/loader.js.map +1 -1
  168. package/dist/plugins/manager.js +374 -380
  169. package/dist/plugins/manager.js.map +1 -1
  170. package/dist/plugins/manifest.js +38 -63
  171. package/dist/plugins/manifest.js.map +1 -1
  172. package/dist/plugins/package-link.js +48 -64
  173. package/dist/plugins/package-link.js.map +1 -1
  174. package/dist/plugins/paths.js +18 -19
  175. package/dist/plugins/paths.js.map +1 -1
  176. package/dist/plugins/registry.js +97 -81
  177. package/dist/plugins/registry.js.map +1 -1
  178. package/dist/plugins/scaffold.js +62 -98
  179. package/dist/plugins/scaffold.js.map +1 -1
  180. package/dist/plugins/types.js +1 -1
  181. package/dist/processors/plan-rejection-abort.js +45 -44
  182. package/dist/processors/plan-rejection-abort.js.map +1 -1
  183. package/dist/providers/amazon-bedrock-gateway.js +134 -125
  184. package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
  185. package/dist/providers/amazon-bedrock.js +68 -47
  186. package/dist/providers/amazon-bedrock.js.map +1 -1
  187. package/dist/providers/claude-max.js +153 -133
  188. package/dist/providers/claude-max.js.map +1 -1
  189. package/dist/providers/github-copilot.js +232 -230
  190. package/dist/providers/github-copilot.js.map +1 -1
  191. package/dist/providers/openai-codex.js +271 -260
  192. package/dist/providers/openai-codex.js.map +1 -1
  193. package/dist/providers/xai.js +57 -50
  194. package/dist/providers/xai.js.map +1 -1
  195. package/dist/schema.js +91 -89
  196. package/dist/schema.js.map +1 -1
  197. package/dist/theme-palette.js +18 -14
  198. package/dist/theme-palette.js.map +1 -1
  199. package/dist/tool-names.js +46 -37
  200. package/dist/tool-names.js.map +1 -1
  201. package/dist/tools/index.js +2 -8
  202. package/dist/tools/request-sandbox-access.js +71 -80
  203. package/dist/tools/request-sandbox-access.js.map +1 -1
  204. package/dist/tools/utils.js +26 -16
  205. package/dist/tools/utils.js.map +1 -1
  206. package/dist/tools/web-search.js +51 -55
  207. package/dist/tools/web-search.js.map +1 -1
  208. package/dist/utils/binaries.js +65 -61
  209. package/dist/utils/binaries.js.map +1 -1
  210. package/dist/utils/debug-log.js +51 -47
  211. package/dist/utils/debug-log.js.map +1 -1
  212. package/dist/utils/errors.js +157 -192
  213. package/dist/utils/errors.js.map +1 -1
  214. package/dist/utils/gateway-sync.js +49 -37
  215. package/dist/utils/gateway-sync.js.map +1 -1
  216. package/dist/utils/path-security.js +7 -6
  217. package/dist/utils/path-security.js.map +1 -1
  218. package/dist/utils/plan-diff.js +58 -39
  219. package/dist/utils/plan-diff.js.map +1 -1
  220. package/dist/utils/plans.js +92 -74
  221. package/dist/utils/plans.js.map +1 -1
  222. package/dist/utils/project.js +318 -256
  223. package/dist/utils/project.js.map +1 -1
  224. package/dist/utils/signals-pubsub.js +117 -99
  225. package/dist/utils/signals-pubsub.js.map +1 -1
  226. package/dist/utils/slash-command-loader.js +118 -154
  227. package/dist/utils/slash-command-loader.js.map +1 -1
  228. package/dist/utils/slash-command-processor.js +92 -83
  229. package/dist/utils/slash-command-processor.js.map +1 -1
  230. package/dist/utils/stdin-pipe.js +87 -63
  231. package/dist/utils/stdin-pipe.js.map +1 -1
  232. package/dist/utils/storage-factory.js +104 -84
  233. package/dist/utils/storage-factory.js.map +1 -1
  234. package/dist/utils/storage-maintenance.js +249 -211
  235. package/dist/utils/storage-maintenance.js.map +1 -1
  236. package/dist/utils/thread-lock.js +96 -92
  237. package/dist/utils/thread-lock.js.map +1 -1
  238. package/dist/utils/token-estimator.js +12 -12
  239. package/dist/utils/token-estimator.js.map +1 -1
  240. package/dist/utils/update-check.d.ts +1 -1
  241. package/dist/utils/update-check.js +341 -259
  242. package/dist/utils/update-check.js.map +1 -1
  243. package/dist/voice/stt-registry.js +131 -113
  244. package/dist/voice/stt-registry.js.map +1 -1
  245. package/package.json +11 -11
  246. package/dist/acp.js.map +0 -1
  247. package/dist/auth/index.js.map +0 -1
  248. package/dist/auth/types.js.map +0 -1
  249. package/dist/evals/index.js.map +0 -1
  250. package/dist/evals/scorers/index.js.map +0 -1
  251. package/dist/headless/index.js.map +0 -1
  252. package/dist/hooks/index.js.map +0 -1
  253. package/dist/lsp/index.js.map +0 -1
  254. package/dist/mcp/index.js.map +0 -1
  255. package/dist/mcp/types.js.map +0 -1
  256. package/dist/onboarding/index.js.map +0 -1
  257. package/dist/plugins/types.js.map +0 -1
  258. package/dist/tools/index.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/headless/run-mc.ts"],"sourcesContent":["/**\n * Core programmatic runner for MastraCode headless runs.\n *\n * `runMC` is a pure async runner: it takes an already-built `controller` +\n * `session` (from `createMastraCode(...)`), resolves run config, subscribes to\n * the session, applies a {@link ResolutionPolicy} for approvals/suspensions,\n * sends the prompt, and aggregates events into a {@link RunMCResult}.\n *\n * It never touches `process.*` and never calls `process.exit`. The returned\n * {@link MCRun} is async-iterable over controller events and also resolves to a\n * final result via `result`.\n */\nimport type { AgentControllerEvent, MastraDBMessage, MastraMessagePart, Session } from '@mastra/core/agent-controller';\n\nimport { GoalManager } from '../goal-manager.js';\nimport { createGoalReminderSignal } from '../goal-signal.js';\n\nimport { autoApprovePolicy } from './policy.js';\nimport type { MCRun, ResolutionPolicy, RunMCOptions, RunMCResult, RunMCStatus } from './types.js';\n\nfunction extractAssistantText(message: MastraDBMessage): string {\n return message.content.parts\n .filter((p): p is MastraMessagePart & { text: string } => p.type === 'text' && typeof p.text === 'string')\n .map(p => p.text)\n .join('');\n}\n\nfunction exitCodeForStatus(status: RunMCStatus): number {\n switch (status) {\n case 'completed':\n case 'done':\n return 0;\n case 'timeout':\n return 2;\n default:\n return 1;\n }\n}\n\ninterface MutableResult {\n text: string;\n finishReason?: string;\n usage?: RunMCResult['usage'];\n toolCalls: RunMCResult['toolCalls'];\n toolResults: RunMCResult['toolResults'];\n error?: RunMCResult['error'];\n threadId?: string;\n}\n\nfunction aggregate(event: AgentControllerEvent, acc: MutableResult): void {\n switch (event.type) {\n case 'message_end':\n if (event.message.role === 'assistant') {\n acc.text += extractAssistantText(event.message);\n }\n break;\n case 'tool_start':\n acc.toolCalls.push({ id: event.toolCallId, name: event.toolName, args: event.args });\n break;\n case 'tool_end': {\n const matching = acc.toolCalls.find(c => c.id === event.toolCallId);\n acc.toolResults.push({\n id: event.toolCallId,\n name: matching?.name ?? '',\n result: event.result,\n isError: event.isError,\n });\n break;\n }\n case 'usage_update':\n acc.usage = {\n inputTokens: event.usage.promptTokens,\n outputTokens: event.usage.completionTokens,\n totalTokens: event.usage.totalTokens,\n };\n break;\n case 'error':\n acc.error = {\n name: event.error.name,\n message: event.error.message,\n stack: event.error.stack,\n };\n break;\n }\n}\n\n/** Resolve a thread by its exact ID. Titles are not unique, so we don't match on them. */\nasync function resolveThread<TState extends Record<string, unknown>>(\n session: Session<TState>,\n threadId: string,\n): Promise<{ threadId: string } | { error: string }> {\n const threads = await session.thread.list();\n\n const byId = threads.find(t => t.id === threadId);\n if (byId) return { threadId: byId.id };\n\n return { error: `No thread found with ID \"${threadId}\"` };\n}\n\n/**\n * A simple back-pressured async queue. Events are pushed in; consumers pull via\n * the async iterator. `close()` ends iteration after draining buffered events.\n *\n * Buffered events are bounded by `maxBuffer`: if a consumer never iterates (the\n * result-only path, `await run.result` without `for await (...)`) — or simply\n * falls far behind — the oldest buffered events are dropped instead of growing\n * without limit. The aggregated {@link RunMCResult} is built independently of\n * this queue, so dropping buffered events never affects the final result.\n */\nclass EventQueue<T> {\n #buffer: T[] = [];\n #resolvers: Array<(r: IteratorResult<T>) => void> = [];\n #closed = false;\n readonly #maxBuffer: number;\n\n constructor(maxBuffer = 10_000) {\n this.#maxBuffer = maxBuffer;\n }\n\n push(value: T): void {\n if (this.#closed) return;\n const resolve = this.#resolvers.shift();\n if (resolve) {\n resolve({ value, done: false });\n return;\n }\n this.#buffer.push(value);\n if (this.#buffer.length > this.#maxBuffer) {\n // Bound memory: drop the oldest event once over the cap.\n this.#buffer.shift();\n }\n }\n\n close(): void {\n if (this.#closed) return;\n this.#closed = true;\n for (const resolve of this.#resolvers.splice(0)) {\n resolve({ value: undefined as unknown as T, done: true });\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T> {\n return {\n next: (): Promise<IteratorResult<T>> => {\n if (this.#buffer.length > 0) {\n return Promise.resolve({ value: this.#buffer.shift()!, done: false });\n }\n if (this.#closed) {\n return Promise.resolve({ value: undefined as unknown as T, done: true });\n }\n return new Promise<IteratorResult<T>>(resolve => this.#resolvers.push(resolve));\n },\n };\n }\n}\n\n/**\n * Run a headless MastraCode turn. Returns an {@link MCRun} handle that is\n * async-iterable over controller events and resolves to a {@link RunMCResult}.\n */\nexport function runMC<TState extends Record<string, unknown>>(options: RunMCOptions<TState>): MCRun {\n const { controller, session } = options;\n const goal = options.goal;\n const policy: ResolutionPolicy = options.policy ?? autoApprovePolicy;\n\n const queue = new EventQueue<AgentControllerEvent>();\n const acc: MutableResult = { text: '', toolCalls: [], toolResults: [] };\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let timedOut = false;\n let aborted = false;\n let maxTurnsExceeded = false;\n let assistantTurns = 0;\n let settled = false;\n let unsubscribe: (() => void) | undefined;\n let resolveResult!: (r: RunMCResult) => void;\n\n const result = new Promise<RunMCResult>(resolve => {\n resolveResult = resolve;\n });\n\n function finish(status: RunMCStatus, data: Partial<RunMCResult> = {}): void {\n if (settled) return;\n settled = true;\n if (timeoutId) clearTimeout(timeoutId);\n unsubscribe?.();\n queue.close();\n resolveResult({\n status,\n text: acc.text,\n finishReason: acc.finishReason,\n usage: acc.usage,\n toolCalls: acc.toolCalls,\n toolResults: acc.toolResults,\n threadId: acc.threadId ?? session.thread.getId() ?? undefined,\n error: acc.error,\n exitCode: exitCodeForStatus(status),\n ...data,\n });\n }\n\n function fail(message: string, name = 'Error'): void {\n if (!acc.error) acc.error = { name, message };\n finish('error');\n }\n\n function abort(): void {\n if (settled) return;\n aborted = true;\n session.abort();\n }\n\n if (options.signal) {\n if (options.signal.aborted) {\n // Defer so the caller can attach iteration / result handlers first.\n queueMicrotask(() => abort());\n } else {\n options.signal.addEventListener('abort', () => abort(), { once: true });\n }\n }\n\n function armTimeout(): void {\n if (!options.timeoutMs || settled) return;\n if (timeoutId) clearTimeout(timeoutId);\n timeoutId = setTimeout(() => {\n timedOut = true;\n session.abort();\n if (goal) finish('timeout');\n }, options.timeoutMs);\n }\n\n // Kick off the run asynchronously so the MCRun handle is returned synchronously.\n void (async () => {\n armTimeout();\n\n // --- Config resolution (model / mode / thinking) ---\n try {\n if (options.model) {\n const available = await controller.listAvailableModels();\n const match = available.find(m => m.id === options.model);\n if (!match) return fail(`Unknown model: \"${options.model}\"`);\n if (!match.hasApiKey) {\n const keyHint = match.apiKeyEnvVar ? ` Set ${match.apiKeyEnvVar} to use this model.` : '';\n return fail(`Model \"${options.model}\" has no API key configured.${keyHint}`);\n }\n await session.model.switch({ modelId: options.model });\n } else if (options.mode) {\n const modelId = options.modeDefaults?.[options.mode];\n if (modelId) {\n const available = await controller.listAvailableModels();\n const match = available.find(m => m.id === modelId);\n if (!match) return fail(`Unknown model \"${modelId}\" configured for mode \"${options.mode}\"`);\n if (!match.hasApiKey) {\n const keyHint = match.apiKeyEnvVar ? ` Set ${match.apiKeyEnvVar} to use this model.` : '';\n return fail(`Model \"${modelId}\" (mode: ${options.mode}) has no API key configured.${keyHint}`);\n }\n await session.model.switch({ modelId });\n }\n // No configured model for mode → fall through to default (no failure).\n }\n\n if (options.thinkingLevel) {\n await session.state.set({ thinkingLevel: options.thinkingLevel } as unknown as Partial<TState>);\n }\n } catch (err) {\n return fail(`Failed to resolve run config: ${(err as Error).message}`);\n }\n\n // --- Subscribe ---\n unsubscribe = session.subscribe(event => {\n if (settled) return;\n if (goal) armTimeout();\n\n if (event.type === 'tool_approval_required') {\n let decision: 'approve' | 'deny';\n try {\n decision = policy.onToolApproval(event);\n } catch (err) {\n fail(`Resolution policy failed: ${(err as Error).message}`);\n return;\n }\n session.respondToToolApproval({\n decision: decision === 'approve' ? 'approve' : 'decline',\n toolCallId: event.toolCallId,\n });\n queue.push(event);\n return;\n }\n\n if (event.type === 'tool_suspended') {\n let outcome: ReturnType<ResolutionPolicy['onSuspension']>;\n try {\n outcome = policy.onSuspension(event);\n } catch (err) {\n fail(`Resolution policy failed: ${(err as Error).message}`);\n return;\n }\n if ('abort' in outcome) {\n queue.push(event);\n abort();\n return;\n }\n void session.respondToToolSuspension({ toolCallId: event.toolCallId, resumeData: outcome.resumeData });\n queue.push(event);\n return;\n }\n\n aggregate(event, acc);\n queue.push(event);\n\n if (event.type === 'error' && goal) {\n finish('error');\n return;\n }\n\n // Count agentic turns (one assistant response = one turn). When the cap is\n // reached, abort the run; agent_end then resolves as 'max_turns'.\n if (event.type === 'message_end' && event.message.role === 'assistant' && options.maxTurns !== undefined) {\n assistantTurns += 1;\n if (assistantTurns >= options.maxTurns && !maxTurnsExceeded) {\n maxTurnsExceeded = true;\n abort();\n }\n }\n\n if (event.type === 'goal_evaluation' && goal && !event.payload.pending) {\n if (event.payload.status === 'done' || event.payload.status === 'paused') {\n finish(event.payload.status, {\n objective: goal.objective,\n goalEvent: event,\n reason: event.payload.reason ?? event.payload.results?.[0]?.reason,\n iterations: event.payload.iteration,\n maxRuns: event.payload.maxRuns,\n });\n }\n return;\n }\n\n if (event.type === 'agent_end') {\n acc.finishReason = event.reason;\n // Goal evaluations can arrive after the agent stream ends, so goal runs\n // remain active until a terminal goal_evaluation is emitted.\n if (goal) return;\n if (timedOut) {\n finish('timeout');\n } else if (event.reason === 'error') {\n finish('error');\n } else if (maxTurnsExceeded && event.reason !== 'complete') {\n // The cap forced an abort while the agent still had work to do.\n finish('max_turns');\n } else if ((event.reason === 'aborted' || aborted) && !maxTurnsExceeded) {\n finish('aborted');\n } else {\n finish('completed');\n }\n }\n });\n\n // --- Resource id ---\n try {\n if (options.resourceId) {\n await controller.setResourceId(session, { resourceId: options.resourceId });\n }\n } catch (err) {\n return fail(`Failed to set resource id: ${(err as Error).message}`);\n }\n\n // --- Thread selection ---\n try {\n const thread = options.thread;\n if (thread?.id) {\n const resolved = await resolveThread(session, thread.id);\n if ('error' in resolved) return fail(resolved.error);\n await session.thread.switch({ threadId: resolved.threadId });\n } else if (thread?.continueLatest) {\n const threads = await session.thread.list();\n if (threads.length > 0) {\n const sorted = [...threads].sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());\n await session.thread.switch({ threadId: sorted[0]!.id });\n }\n }\n } catch (err) {\n return fail(`Failed to select thread: ${(err as Error).message}`);\n }\n\n // --- Clone ---\n if (options.thread?.clone) {\n try {\n await session.thread.clone();\n } catch (err) {\n return fail(`Failed to clone thread: ${(err as Error).message}`);\n }\n }\n\n // --- Title ---\n if (options.title) {\n try {\n await session.thread.rename({ title: options.title });\n } catch (err) {\n return fail(`Failed to set thread title: ${(err as Error).message}`);\n }\n }\n\n // --- Start ---\n try {\n if (goal) {\n const threadId = session.thread.getId();\n if (!threadId || !(await session.thread.getById({ threadId }))) {\n await session.thread.create();\n }\n\n const goalManager = goal.goalManager ?? new GoalManager();\n const state = {\n controller,\n session,\n goalManager,\n pendingNewThread: false,\n planStartedGoalId: undefined,\n } as any;\n const objective = await goalManager.setGoal(state, goal.objective, goal.judgeModelId, goal.maxRuns);\n if (!objective) return fail('Failed to set goal.');\n\n const agent = controller.getCurrentAgent(session);\n const persisted = await agent.getObjective({ threadId: session.thread.getId()! });\n if (!persisted || persisted.id !== objective.id) {\n return fail('Failed to persist goal objective before sending goal signal.');\n }\n\n await goalManager.saveToThread(state);\n if (!settled) await session.sendSignal(createGoalReminderSignal(objective)).accepted;\n } else {\n if (!options.prompt) return fail('A prompt or goal is required.');\n await session.sendMessage({ content: options.prompt });\n }\n } catch (err) {\n return fail(`Failed to start run: ${(err as Error).message}`);\n }\n })();\n\n return {\n result,\n abort,\n [Symbol.asyncIterator](): AsyncIterator<AgentControllerEvent> {\n return queue[Symbol.asyncIterator]();\n },\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"file":"run-mc.js","names":["#maxBuffer","#closed","#resolvers","#buffer"],"sources":["../../src/headless/run-mc.ts"],"sourcesContent":["/**\n * Core programmatic runner for MastraCode headless runs.\n *\n * `runMC` is a pure async runner: it takes an already-built `controller` +\n * `session` (from `createMastraCode(...)`), resolves run config, subscribes to\n * the session, applies a {@link ResolutionPolicy} for approvals/suspensions,\n * sends the prompt, and aggregates events into a {@link RunMCResult}.\n *\n * It never touches `process.*` and never calls `process.exit`. The returned\n * {@link MCRun} is async-iterable over controller events and also resolves to a\n * final result via `result`.\n */\nimport type { AgentControllerEvent, MastraDBMessage, MastraMessagePart, Session } from '@mastra/core/agent-controller';\n\nimport { GoalManager } from '../goal-manager.js';\nimport { createGoalReminderSignal } from '../goal-signal.js';\n\nimport { autoApprovePolicy } from './policy.js';\nimport type { MCRun, ResolutionPolicy, RunMCOptions, RunMCResult, RunMCStatus } from './types.js';\n\nfunction extractAssistantText(message: MastraDBMessage): string {\n return message.content.parts\n .filter((p): p is MastraMessagePart & { text: string } => p.type === 'text' && typeof p.text === 'string')\n .map(p => p.text)\n .join('');\n}\n\nfunction exitCodeForStatus(status: RunMCStatus): number {\n switch (status) {\n case 'completed':\n case 'done':\n return 0;\n case 'timeout':\n return 2;\n default:\n return 1;\n }\n}\n\ninterface MutableResult {\n text: string;\n finishReason?: string;\n usage?: RunMCResult['usage'];\n toolCalls: RunMCResult['toolCalls'];\n toolResults: RunMCResult['toolResults'];\n error?: RunMCResult['error'];\n threadId?: string;\n}\n\nfunction aggregate(event: AgentControllerEvent, acc: MutableResult): void {\n switch (event.type) {\n case 'message_end':\n if (event.message.role === 'assistant') {\n acc.text += extractAssistantText(event.message);\n }\n break;\n case 'tool_start':\n acc.toolCalls.push({ id: event.toolCallId, name: event.toolName, args: event.args });\n break;\n case 'tool_end': {\n const matching = acc.toolCalls.find(c => c.id === event.toolCallId);\n acc.toolResults.push({\n id: event.toolCallId,\n name: matching?.name ?? '',\n result: event.result,\n isError: event.isError,\n });\n break;\n }\n case 'usage_update':\n acc.usage = {\n inputTokens: event.usage.promptTokens,\n outputTokens: event.usage.completionTokens,\n totalTokens: event.usage.totalTokens,\n };\n break;\n case 'error':\n acc.error = {\n name: event.error.name,\n message: event.error.message,\n stack: event.error.stack,\n };\n break;\n }\n}\n\n/** Resolve a thread by its exact ID. Titles are not unique, so we don't match on them. */\nasync function resolveThread<TState extends Record<string, unknown>>(\n session: Session<TState>,\n threadId: string,\n): Promise<{ threadId: string } | { error: string }> {\n const threads = await session.thread.list();\n\n const byId = threads.find(t => t.id === threadId);\n if (byId) return { threadId: byId.id };\n\n return { error: `No thread found with ID \"${threadId}\"` };\n}\n\n/**\n * A simple back-pressured async queue. Events are pushed in; consumers pull via\n * the async iterator. `close()` ends iteration after draining buffered events.\n *\n * Buffered events are bounded by `maxBuffer`: if a consumer never iterates (the\n * result-only path, `await run.result` without `for await (...)`) — or simply\n * falls far behind — the oldest buffered events are dropped instead of growing\n * without limit. The aggregated {@link RunMCResult} is built independently of\n * this queue, so dropping buffered events never affects the final result.\n */\nclass EventQueue<T> {\n #buffer: T[] = [];\n #resolvers: Array<(r: IteratorResult<T>) => void> = [];\n #closed = false;\n readonly #maxBuffer: number;\n\n constructor(maxBuffer = 10_000) {\n this.#maxBuffer = maxBuffer;\n }\n\n push(value: T): void {\n if (this.#closed) return;\n const resolve = this.#resolvers.shift();\n if (resolve) {\n resolve({ value, done: false });\n return;\n }\n this.#buffer.push(value);\n if (this.#buffer.length > this.#maxBuffer) {\n // Bound memory: drop the oldest event once over the cap.\n this.#buffer.shift();\n }\n }\n\n close(): void {\n if (this.#closed) return;\n this.#closed = true;\n for (const resolve of this.#resolvers.splice(0)) {\n resolve({ value: undefined as unknown as T, done: true });\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T> {\n return {\n next: (): Promise<IteratorResult<T>> => {\n if (this.#buffer.length > 0) {\n return Promise.resolve({ value: this.#buffer.shift()!, done: false });\n }\n if (this.#closed) {\n return Promise.resolve({ value: undefined as unknown as T, done: true });\n }\n return new Promise<IteratorResult<T>>(resolve => this.#resolvers.push(resolve));\n },\n };\n }\n}\n\n/**\n * Run a headless MastraCode turn. Returns an {@link MCRun} handle that is\n * async-iterable over controller events and resolves to a {@link RunMCResult}.\n */\nexport function runMC<TState extends Record<string, unknown>>(options: RunMCOptions<TState>): MCRun {\n const { controller, session } = options;\n const goal = options.goal;\n const policy: ResolutionPolicy = options.policy ?? autoApprovePolicy;\n\n const queue = new EventQueue<AgentControllerEvent>();\n const acc: MutableResult = { text: '', toolCalls: [], toolResults: [] };\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let timedOut = false;\n let aborted = false;\n let maxTurnsExceeded = false;\n let assistantTurns = 0;\n let settled = false;\n let unsubscribe: (() => void) | undefined;\n let resolveResult!: (r: RunMCResult) => void;\n\n const result = new Promise<RunMCResult>(resolve => {\n resolveResult = resolve;\n });\n\n function finish(status: RunMCStatus, data: Partial<RunMCResult> = {}): void {\n if (settled) return;\n settled = true;\n if (timeoutId) clearTimeout(timeoutId);\n unsubscribe?.();\n queue.close();\n resolveResult({\n status,\n text: acc.text,\n finishReason: acc.finishReason,\n usage: acc.usage,\n toolCalls: acc.toolCalls,\n toolResults: acc.toolResults,\n threadId: acc.threadId ?? session.thread.getId() ?? undefined,\n error: acc.error,\n exitCode: exitCodeForStatus(status),\n ...data,\n });\n }\n\n function fail(message: string, name = 'Error'): void {\n if (!acc.error) acc.error = { name, message };\n finish('error');\n }\n\n function abort(): void {\n if (settled) return;\n aborted = true;\n session.abort();\n }\n\n if (options.signal) {\n if (options.signal.aborted) {\n // Defer so the caller can attach iteration / result handlers first.\n queueMicrotask(() => abort());\n } else {\n options.signal.addEventListener('abort', () => abort(), { once: true });\n }\n }\n\n function armTimeout(): void {\n if (!options.timeoutMs || settled) return;\n if (timeoutId) clearTimeout(timeoutId);\n timeoutId = setTimeout(() => {\n timedOut = true;\n session.abort();\n if (goal) finish('timeout');\n }, options.timeoutMs);\n }\n\n // Kick off the run asynchronously so the MCRun handle is returned synchronously.\n void (async () => {\n armTimeout();\n\n // --- Config resolution (model / mode / thinking) ---\n try {\n if (options.model) {\n const available = await controller.listAvailableModels();\n const match = available.find(m => m.id === options.model);\n if (!match) return fail(`Unknown model: \"${options.model}\"`);\n if (!match.hasApiKey) {\n const keyHint = match.apiKeyEnvVar ? ` Set ${match.apiKeyEnvVar} to use this model.` : '';\n return fail(`Model \"${options.model}\" has no API key configured.${keyHint}`);\n }\n await session.model.switch({ modelId: options.model });\n } else if (options.mode) {\n const modelId = options.modeDefaults?.[options.mode];\n if (modelId) {\n const available = await controller.listAvailableModels();\n const match = available.find(m => m.id === modelId);\n if (!match) return fail(`Unknown model \"${modelId}\" configured for mode \"${options.mode}\"`);\n if (!match.hasApiKey) {\n const keyHint = match.apiKeyEnvVar ? ` Set ${match.apiKeyEnvVar} to use this model.` : '';\n return fail(`Model \"${modelId}\" (mode: ${options.mode}) has no API key configured.${keyHint}`);\n }\n await session.model.switch({ modelId });\n }\n // No configured model for mode → fall through to default (no failure).\n }\n\n if (options.thinkingLevel) {\n await session.state.set({ thinkingLevel: options.thinkingLevel } as unknown as Partial<TState>);\n }\n } catch (err) {\n return fail(`Failed to resolve run config: ${(err as Error).message}`);\n }\n\n // --- Subscribe ---\n unsubscribe = session.subscribe(event => {\n if (settled) return;\n if (goal) armTimeout();\n\n if (event.type === 'tool_approval_required') {\n let decision: 'approve' | 'deny';\n try {\n decision = policy.onToolApproval(event);\n } catch (err) {\n fail(`Resolution policy failed: ${(err as Error).message}`);\n return;\n }\n session.respondToToolApproval({\n decision: decision === 'approve' ? 'approve' : 'decline',\n toolCallId: event.toolCallId,\n });\n queue.push(event);\n return;\n }\n\n if (event.type === 'tool_suspended') {\n let outcome: ReturnType<ResolutionPolicy['onSuspension']>;\n try {\n outcome = policy.onSuspension(event);\n } catch (err) {\n fail(`Resolution policy failed: ${(err as Error).message}`);\n return;\n }\n if ('abort' in outcome) {\n queue.push(event);\n abort();\n return;\n }\n void session.respondToToolSuspension({ toolCallId: event.toolCallId, resumeData: outcome.resumeData });\n queue.push(event);\n return;\n }\n\n aggregate(event, acc);\n queue.push(event);\n\n if (event.type === 'error' && goal) {\n finish('error');\n return;\n }\n\n // Count agentic turns (one assistant response = one turn). When the cap is\n // reached, abort the run; agent_end then resolves as 'max_turns'.\n if (event.type === 'message_end' && event.message.role === 'assistant' && options.maxTurns !== undefined) {\n assistantTurns += 1;\n if (assistantTurns >= options.maxTurns && !maxTurnsExceeded) {\n maxTurnsExceeded = true;\n abort();\n }\n }\n\n if (event.type === 'goal_evaluation' && goal && !event.payload.pending) {\n if (event.payload.status === 'done' || event.payload.status === 'paused') {\n finish(event.payload.status, {\n objective: goal.objective,\n goalEvent: event,\n reason: event.payload.reason ?? event.payload.results?.[0]?.reason,\n iterations: event.payload.iteration,\n maxRuns: event.payload.maxRuns,\n });\n }\n return;\n }\n\n if (event.type === 'agent_end') {\n acc.finishReason = event.reason;\n // Goal evaluations can arrive after the agent stream ends, so goal runs\n // remain active until a terminal goal_evaluation is emitted.\n if (goal) return;\n if (timedOut) {\n finish('timeout');\n } else if (event.reason === 'error') {\n finish('error');\n } else if (maxTurnsExceeded && event.reason !== 'complete') {\n // The cap forced an abort while the agent still had work to do.\n finish('max_turns');\n } else if ((event.reason === 'aborted' || aborted) && !maxTurnsExceeded) {\n finish('aborted');\n } else {\n finish('completed');\n }\n }\n });\n\n // --- Resource id ---\n try {\n if (options.resourceId) {\n await controller.setResourceId(session, { resourceId: options.resourceId });\n }\n } catch (err) {\n return fail(`Failed to set resource id: ${(err as Error).message}`);\n }\n\n // --- Thread selection ---\n try {\n const thread = options.thread;\n if (thread?.id) {\n const resolved = await resolveThread(session, thread.id);\n if ('error' in resolved) return fail(resolved.error);\n await session.thread.switch({ threadId: resolved.threadId });\n } else if (thread?.continueLatest) {\n const threads = await session.thread.list();\n if (threads.length > 0) {\n const sorted = [...threads].sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());\n await session.thread.switch({ threadId: sorted[0]!.id });\n }\n }\n } catch (err) {\n return fail(`Failed to select thread: ${(err as Error).message}`);\n }\n\n // --- Clone ---\n if (options.thread?.clone) {\n try {\n await session.thread.clone();\n } catch (err) {\n return fail(`Failed to clone thread: ${(err as Error).message}`);\n }\n }\n\n // --- Title ---\n if (options.title) {\n try {\n await session.thread.rename({ title: options.title });\n } catch (err) {\n return fail(`Failed to set thread title: ${(err as Error).message}`);\n }\n }\n\n // --- Start ---\n try {\n if (goal) {\n const threadId = session.thread.getId();\n if (!threadId || !(await session.thread.getById({ threadId }))) {\n await session.thread.create();\n }\n\n const goalManager = goal.goalManager ?? new GoalManager();\n const state = {\n controller,\n session,\n goalManager,\n pendingNewThread: false,\n planStartedGoalId: undefined,\n } as any;\n const objective = await goalManager.setGoal(state, goal.objective, goal.judgeModelId, goal.maxRuns);\n if (!objective) return fail('Failed to set goal.');\n\n const agent = controller.getCurrentAgent(session);\n const persisted = await agent.getObjective({ threadId: session.thread.getId()! });\n if (!persisted || persisted.id !== objective.id) {\n return fail('Failed to persist goal objective before sending goal signal.');\n }\n\n await goalManager.saveToThread(state);\n if (!settled) await session.sendSignal(createGoalReminderSignal(objective)).accepted;\n } else {\n if (!options.prompt) return fail('A prompt or goal is required.');\n await session.sendMessage({ content: options.prompt });\n }\n } catch (err) {\n return fail(`Failed to start run: ${(err as Error).message}`);\n }\n })();\n\n return {\n result,\n abort,\n [Symbol.asyncIterator](): AsyncIterator<AgentControllerEvent> {\n return queue[Symbol.asyncIterator]();\n },\n };\n}\n"],"mappings":"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"}
@@ -1,9 +1,18 @@
1
- const VALID_MODES = ["build", "plan", "fast"];
2
- const VALID_THINKING_LEVELS = ["off", "low", "medium", "high", "xhigh"];
1
+ //#region src/headless/types.ts
2
+ const VALID_MODES = [
3
+ "build",
4
+ "plan",
5
+ "fast"
6
+ ];
7
+ const VALID_THINKING_LEVELS = [
8
+ "off",
9
+ "low",
10
+ "medium",
11
+ "high",
12
+ "xhigh"
13
+ ];
3
14
  const VALID_PERMISSION_MODES = ["auto", "deny"];
4
- export {
5
- VALID_MODES,
6
- VALID_PERMISSION_MODES,
7
- VALID_THINKING_LEVELS
8
- };
15
+ //#endregion
16
+ export { VALID_MODES, VALID_PERMISSION_MODES, VALID_THINKING_LEVELS };
17
+
9
18
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/headless/types.ts"],"sourcesContent":["/**\n * Shared types for the headless / programmatic MastraCode API.\n *\n * These types are consumed by the core runner (`runMC`), the resolution policy,\n * the output formatters, and the CLI adapter. They are intentionally free of any\n * `process.*` access so the core API is usable from CI / Node code.\n */\nimport type { AgentController, AgentControllerEvent, Session } from '@mastra/core/agent-controller';\n\nimport type { GoalManager } from '../goal-manager.js';\n\nexport type RunMode = 'build' | 'plan' | 'fast';\nexport type ThinkingLevel = 'off' | 'low' | 'medium' | 'high' | 'xhigh';\n\nexport const VALID_MODES = ['build', 'plan', 'fast'] as const;\nexport const VALID_THINKING_LEVELS = ['off', 'low', 'medium', 'high', 'xhigh'] as const;\n\n/**\n * Named permission modes for non-interactive runs. Maps to a built-in\n * {@link ResolutionPolicy}:\n * - `auto` — approve every tool and auto-resolve suspensions (the default).\n * - `deny` — refuse every tool approval and abort on any suspension.\n */\nexport type PermissionMode = 'auto' | 'deny';\nexport const VALID_PERMISSION_MODES = ['auto', 'deny'] as const;\n\n/** How `runMC` should resume `tool_approval_required` and `tool_suspended` events. */\nexport interface ResolutionPolicy {\n /**\n * Called for every `tool_approval_required` event. Return the decision; the\n * runner forwards it to `session.respondToToolApproval`.\n */\n onToolApproval(event: Extract<AgentControllerEvent, { type: 'tool_approval_required' }>): 'approve' | 'deny';\n /**\n * Called for every `tool_suspended` event. Return `resumeData` to resume the\n * tool, or `{ abort: true }` to abort the run.\n */\n onSuspension(\n event: Extract<AgentControllerEvent, { type: 'tool_suspended' }>,\n ): { resumeData: unknown } | { abort: true };\n}\n\n/** Thread selection / mutation options resolved up front by `runMC`. */\nexport interface RunMCThreadOptions {\n /** Resume a specific thread by its exact id. */\n id?: string;\n /** Resume the most recently updated thread instead of creating a new one. */\n continueLatest?: boolean;\n /** Clone the resolved (or current) thread before running — work on a copy. */\n clone?: boolean;\n}\n\ninterface RunMCBaseOptions<TState extends Record<string, unknown> = Record<string, unknown>> {\n /** Controller built via `createMastraCode(...)`. */\n controller: AgentController<TState>;\n /** Session built via `createMastraCode(...)`. */\n session: Session<TState>;\n\n /** Explicit model id override. Takes precedence over `mode`. */\n model?: string;\n /** Execution mode; resolves a model from `modeDefaults` when `model` is absent. */\n mode?: RunMode;\n /** Per-mode default model ids (resolved from settings at startup). */\n modeDefaults?: Record<string, string>;\n /** Thinking-effort level. */\n thinkingLevel?: ThinkingLevel;\n /** Thread selection / mutation. */\n thread?: RunMCThreadOptions;\n /** Resource id for thread scoping. */\n resourceId?: string;\n /** Set or rename the thread title before running. */\n title?: string;\n /** Abort with `status: 'timeout'` (exit code 2) after this many ms without an event. */\n timeoutMs?: number;\n /**\n * Maximum number of agentic turns (assistant responses). When the limit is\n * reached the run aborts with `status: 'max_turns'` (exit code 1). No limit\n * by default.\n */\n maxTurns?: number;\n /** How approvals / suspensions are resolved. Defaults to {@link autoApprovePolicy}. */\n policy?: ResolutionPolicy;\n /** External abort signal; aborting it aborts the run. */\n signal?: AbortSignal;\n}\n\nexport interface RunMCGoalOptions {\n objective: string;\n judgeModelId: string;\n maxRuns: number;\n goalManager?: GoalManager;\n}\n\nexport type RunMCOptions<TState extends Record<string, unknown> = Record<string, unknown>> = RunMCBaseOptions<TState> &\n (\n | {\n /** The task to run as a regular headless turn. */\n prompt: string;\n goal?: never;\n }\n | {\n prompt?: never;\n /** Run a persisted goal instead of a regular prompt. */\n goal: RunMCGoalOptions;\n }\n );\n\nexport type RunMCStatus = 'completed' | 'done' | 'paused' | 'error' | 'aborted' | 'timeout' | 'max_turns';\n\nexport interface RunMCUsage {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n}\n\nexport interface RunMCToolCall {\n id: string;\n name: string;\n args: unknown;\n}\n\nexport interface RunMCToolResult {\n id: string;\n name: string;\n result: unknown;\n isError: boolean;\n}\n\nexport interface RunMCError {\n name: string;\n message: string;\n stack?: string;\n}\n\nexport interface RunMCResult {\n status: RunMCStatus;\n /** Aggregated assistant text across all message_end events. */\n text: string;\n /** Goal objective when this was a goal run. */\n objective?: string;\n /** Terminal goal evaluation when this was a goal run. */\n goalEvent?: Extract<AgentControllerEvent, { type: 'goal_evaluation' }>;\n reason?: string;\n iterations?: number;\n maxRuns?: number;\n /** Underlying finish reason from `agent_end`, when the run finished normally. */\n finishReason?: string;\n usage?: RunMCUsage;\n toolCalls: RunMCToolCall[];\n toolResults: RunMCToolResult[];\n threadId?: string;\n error?: RunMCError;\n /** 0 success, 1 error/aborted/max_turns, 2 timeout. */\n exitCode: number;\n}\n\n/**\n * A handle to an in-flight `runMC` run. It is async-iterable over controller\n * events and also resolves to a final {@link RunMCResult} via `result`.\n *\n * Both `for await (const e of run)` and `await run.result` work on the same run;\n * awaiting `result` without iterating still drains events internally.\n */\nexport interface MCRun extends AsyncIterable<AgentControllerEvent> {\n /** Resolves once the run completes, times out, errors, or is aborted. */\n result: Promise<RunMCResult>;\n /** Abort the in-flight run. */\n abort(): void;\n}\n"],"mappings":"AAcO,MAAM,cAAc,CAAC,SAAS,QAAQ,MAAM;AAC5C,MAAM,wBAAwB,CAAC,OAAO,OAAO,UAAU,QAAQ,OAAO;AAStE,MAAM,yBAAyB,CAAC,QAAQ,MAAM;","names":[]}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/headless/types.ts"],"sourcesContent":["/**\n * Shared types for the headless / programmatic MastraCode API.\n *\n * These types are consumed by the core runner (`runMC`), the resolution policy,\n * the output formatters, and the CLI adapter. They are intentionally free of any\n * `process.*` access so the core API is usable from CI / Node code.\n */\nimport type { AgentController, AgentControllerEvent, Session } from '@mastra/core/agent-controller';\n\nimport type { GoalManager } from '../goal-manager.js';\n\nexport type RunMode = 'build' | 'plan' | 'fast';\nexport type ThinkingLevel = 'off' | 'low' | 'medium' | 'high' | 'xhigh';\n\nexport const VALID_MODES = ['build', 'plan', 'fast'] as const;\nexport const VALID_THINKING_LEVELS = ['off', 'low', 'medium', 'high', 'xhigh'] as const;\n\n/**\n * Named permission modes for non-interactive runs. Maps to a built-in\n * {@link ResolutionPolicy}:\n * - `auto` — approve every tool and auto-resolve suspensions (the default).\n * - `deny` — refuse every tool approval and abort on any suspension.\n */\nexport type PermissionMode = 'auto' | 'deny';\nexport const VALID_PERMISSION_MODES = ['auto', 'deny'] as const;\n\n/** How `runMC` should resume `tool_approval_required` and `tool_suspended` events. */\nexport interface ResolutionPolicy {\n /**\n * Called for every `tool_approval_required` event. Return the decision; the\n * runner forwards it to `session.respondToToolApproval`.\n */\n onToolApproval(event: Extract<AgentControllerEvent, { type: 'tool_approval_required' }>): 'approve' | 'deny';\n /**\n * Called for every `tool_suspended` event. Return `resumeData` to resume the\n * tool, or `{ abort: true }` to abort the run.\n */\n onSuspension(\n event: Extract<AgentControllerEvent, { type: 'tool_suspended' }>,\n ): { resumeData: unknown } | { abort: true };\n}\n\n/** Thread selection / mutation options resolved up front by `runMC`. */\nexport interface RunMCThreadOptions {\n /** Resume a specific thread by its exact id. */\n id?: string;\n /** Resume the most recently updated thread instead of creating a new one. */\n continueLatest?: boolean;\n /** Clone the resolved (or current) thread before running — work on a copy. */\n clone?: boolean;\n}\n\ninterface RunMCBaseOptions<TState extends Record<string, unknown> = Record<string, unknown>> {\n /** Controller built via `createMastraCode(...)`. */\n controller: AgentController<TState>;\n /** Session built via `createMastraCode(...)`. */\n session: Session<TState>;\n\n /** Explicit model id override. Takes precedence over `mode`. */\n model?: string;\n /** Execution mode; resolves a model from `modeDefaults` when `model` is absent. */\n mode?: RunMode;\n /** Per-mode default model ids (resolved from settings at startup). */\n modeDefaults?: Record<string, string>;\n /** Thinking-effort level. */\n thinkingLevel?: ThinkingLevel;\n /** Thread selection / mutation. */\n thread?: RunMCThreadOptions;\n /** Resource id for thread scoping. */\n resourceId?: string;\n /** Set or rename the thread title before running. */\n title?: string;\n /** Abort with `status: 'timeout'` (exit code 2) after this many ms without an event. */\n timeoutMs?: number;\n /**\n * Maximum number of agentic turns (assistant responses). When the limit is\n * reached the run aborts with `status: 'max_turns'` (exit code 1). No limit\n * by default.\n */\n maxTurns?: number;\n /** How approvals / suspensions are resolved. Defaults to {@link autoApprovePolicy}. */\n policy?: ResolutionPolicy;\n /** External abort signal; aborting it aborts the run. */\n signal?: AbortSignal;\n}\n\nexport interface RunMCGoalOptions {\n objective: string;\n judgeModelId: string;\n maxRuns: number;\n goalManager?: GoalManager;\n}\n\nexport type RunMCOptions<TState extends Record<string, unknown> = Record<string, unknown>> = RunMCBaseOptions<TState> &\n (\n | {\n /** The task to run as a regular headless turn. */\n prompt: string;\n goal?: never;\n }\n | {\n prompt?: never;\n /** Run a persisted goal instead of a regular prompt. */\n goal: RunMCGoalOptions;\n }\n );\n\nexport type RunMCStatus = 'completed' | 'done' | 'paused' | 'error' | 'aborted' | 'timeout' | 'max_turns';\n\nexport interface RunMCUsage {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n}\n\nexport interface RunMCToolCall {\n id: string;\n name: string;\n args: unknown;\n}\n\nexport interface RunMCToolResult {\n id: string;\n name: string;\n result: unknown;\n isError: boolean;\n}\n\nexport interface RunMCError {\n name: string;\n message: string;\n stack?: string;\n}\n\nexport interface RunMCResult {\n status: RunMCStatus;\n /** Aggregated assistant text across all message_end events. */\n text: string;\n /** Goal objective when this was a goal run. */\n objective?: string;\n /** Terminal goal evaluation when this was a goal run. */\n goalEvent?: Extract<AgentControllerEvent, { type: 'goal_evaluation' }>;\n reason?: string;\n iterations?: number;\n maxRuns?: number;\n /** Underlying finish reason from `agent_end`, when the run finished normally. */\n finishReason?: string;\n usage?: RunMCUsage;\n toolCalls: RunMCToolCall[];\n toolResults: RunMCToolResult[];\n threadId?: string;\n error?: RunMCError;\n /** 0 success, 1 error/aborted/max_turns, 2 timeout. */\n exitCode: number;\n}\n\n/**\n * A handle to an in-flight `runMC` run. It is async-iterable over controller\n * events and also resolves to a final {@link RunMCResult} via `result`.\n *\n * Both `for await (const e of run)` and `await run.result` work on the same run;\n * awaiting `result` without iterating still drains events internally.\n */\nexport interface MCRun extends AsyncIterable<AgentControllerEvent> {\n /** Resolves once the run completes, times out, errors, or is aborted. */\n result: Promise<RunMCResult>;\n /** Abort the in-flight run. */\n abort(): void;\n}\n"],"mappings":";AAcA,MAAa,cAAc;CAAC;CAAS;CAAQ;AAAM;AACnD,MAAa,wBAAwB;CAAC;CAAO;CAAO;CAAU;CAAQ;AAAO;AAS7E,MAAa,yBAAyB,CAAC,QAAQ,MAAM"}
@@ -1,78 +1,73 @@
1
- import * as fs from "node:fs";
2
- import * as os from "node:os";
3
- import * as path from "node:path";
4
1
  import { DEFAULT_CONFIG_DIR } from "../constants.js";
2
+ import * as fs$1 from "fs";
3
+ import * as os$1 from "os";
4
+ import * as path$1 from "path";
5
+ //#region src/hooks/config.ts
6
+ /**
7
+ * Hook configuration loading from filesystem.
8
+ * Loads from global (~/.mastracode/hooks.json) and project (.mastracode/hooks.json).
9
+ * Global hooks run first, project hooks append.
10
+ */
5
11
  const VALID_EVENTS = [
6
- "PreToolUse",
7
- "PostToolUse",
8
- "Stop",
9
- "UserPromptSubmit",
10
- "SessionStart",
11
- "SessionEnd",
12
- "Notification",
13
- "AgentStart",
14
- "AgentEnd",
15
- "PermissionRequest",
16
- "PermissionResult",
17
- "Interrupt",
18
- "SubagentStart",
19
- "SubagentEnd"
12
+ "PreToolUse",
13
+ "PostToolUse",
14
+ "Stop",
15
+ "UserPromptSubmit",
16
+ "SessionStart",
17
+ "SessionEnd",
18
+ "Notification",
19
+ "AgentStart",
20
+ "AgentEnd",
21
+ "PermissionRequest",
22
+ "PermissionResult",
23
+ "Interrupt",
24
+ "SubagentStart",
25
+ "SubagentEnd"
20
26
  ];
21
27
  function loadHooksConfig(projectDir, configDirName = DEFAULT_CONFIG_DIR, homeDir) {
22
- const globalPath = getGlobalHooksPath(configDirName, homeDir);
23
- const projectPath = getProjectHooksPath(projectDir, configDirName);
24
- const globalConfig = loadSingleConfig(globalPath);
25
- const projectConfig = loadSingleConfig(projectPath);
26
- return mergeConfigs(globalConfig, projectConfig);
28
+ const globalPath = getGlobalHooksPath(configDirName, homeDir);
29
+ const projectPath = getProjectHooksPath(projectDir, configDirName);
30
+ return mergeConfigs(loadSingleConfig(globalPath), loadSingleConfig(projectPath));
27
31
  }
28
32
  function getProjectHooksPath(projectDir, configDirName = DEFAULT_CONFIG_DIR) {
29
- return path.join(projectDir, configDirName, "hooks.json");
33
+ return path$1.join(projectDir, configDirName, "hooks.json");
30
34
  }
31
- function getGlobalHooksPath(configDirName = DEFAULT_CONFIG_DIR, homeDir = os.homedir()) {
32
- return path.join(homeDir, configDirName, "hooks.json");
35
+ function getGlobalHooksPath(configDirName = DEFAULT_CONFIG_DIR, homeDir = os$1.homedir()) {
36
+ return path$1.join(homeDir, configDirName, "hooks.json");
33
37
  }
34
38
  function loadSingleConfig(filePath) {
35
- try {
36
- if (!fs.existsSync(filePath)) return {};
37
- const raw = fs.readFileSync(filePath, "utf-8");
38
- return validateConfig(JSON.parse(raw));
39
- } catch {
40
- return {};
41
- }
39
+ try {
40
+ if (!fs$1.existsSync(filePath)) return {};
41
+ const raw = fs$1.readFileSync(filePath, "utf-8");
42
+ return validateConfig(JSON.parse(raw));
43
+ } catch {
44
+ return {};
45
+ }
42
46
  }
43
47
  function validateConfig(raw) {
44
- if (!raw || typeof raw !== "object") return {};
45
- const config = {};
46
- const obj = raw;
47
- for (const event of VALID_EVENTS) {
48
- if (Array.isArray(obj[event])) {
49
- const hooks = obj[event].filter(isValidHook);
50
- if (hooks.length > 0) {
51
- config[event] = hooks;
52
- }
53
- }
54
- }
55
- return config;
48
+ if (!raw || typeof raw !== "object") return {};
49
+ const config = {};
50
+ const obj = raw;
51
+ for (const event of VALID_EVENTS) if (Array.isArray(obj[event])) {
52
+ const hooks = obj[event].filter(isValidHook);
53
+ if (hooks.length > 0) config[event] = hooks;
54
+ }
55
+ return config;
56
56
  }
57
57
  function isValidHook(raw) {
58
- if (!raw || typeof raw !== "object") return false;
59
- const obj = raw;
60
- return obj.type === "command" && typeof obj.command === "string";
58
+ if (!raw || typeof raw !== "object") return false;
59
+ const obj = raw;
60
+ return obj.type === "command" && typeof obj.command === "string";
61
61
  }
62
62
  function mergeConfigs(global, project) {
63
- const merged = {};
64
- for (const event of VALID_EVENTS) {
65
- const combined = [...global[event] ?? [], ...project[event] ?? []];
66
- if (combined.length > 0) {
67
- merged[event] = combined;
68
- }
69
- }
70
- return merged;
63
+ const merged = {};
64
+ for (const event of VALID_EVENTS) {
65
+ const combined = [...global[event] ?? [], ...project[event] ?? []];
66
+ if (combined.length > 0) merged[event] = combined;
67
+ }
68
+ return merged;
71
69
  }
72
- export {
73
- VALID_EVENTS,
74
- getGlobalHooksPath,
75
- getProjectHooksPath,
76
- loadHooksConfig
77
- };
70
+ //#endregion
71
+ export { VALID_EVENTS, getGlobalHooksPath, getProjectHooksPath, loadHooksConfig };
72
+
78
73
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/config.ts"],"sourcesContent":["/**\n * Hook configuration loading from filesystem.\n * Loads from global (~/.mastracode/hooks.json) and project (.mastracode/hooks.json).\n * Global hooks run first, project hooks append.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport type { HooksConfig, HookDefinition, HookEventName } from './types.js';\n\nexport const VALID_EVENTS: HookEventName[] = [\n 'PreToolUse',\n 'PostToolUse',\n 'Stop',\n 'UserPromptSubmit',\n 'SessionStart',\n 'SessionEnd',\n 'Notification',\n 'AgentStart',\n 'AgentEnd',\n 'PermissionRequest',\n 'PermissionResult',\n 'Interrupt',\n 'SubagentStart',\n 'SubagentEnd',\n];\n\nexport function loadHooksConfig(projectDir: string, configDirName = DEFAULT_CONFIG_DIR, homeDir?: string): HooksConfig {\n const globalPath = getGlobalHooksPath(configDirName, homeDir);\n const projectPath = getProjectHooksPath(projectDir, configDirName);\n\n const globalConfig = loadSingleConfig(globalPath);\n const projectConfig = loadSingleConfig(projectPath);\n\n return mergeConfigs(globalConfig, projectConfig);\n}\n\nexport function getProjectHooksPath(projectDir: string, configDirName = DEFAULT_CONFIG_DIR): string {\n return path.join(projectDir, configDirName, 'hooks.json');\n}\n\nexport function getGlobalHooksPath(configDirName = DEFAULT_CONFIG_DIR, homeDir = os.homedir()): string {\n return path.join(homeDir, configDirName, 'hooks.json');\n}\n\nfunction loadSingleConfig(filePath: string): HooksConfig {\n try {\n if (!fs.existsSync(filePath)) return {};\n const raw = fs.readFileSync(filePath, 'utf-8');\n return validateConfig(JSON.parse(raw));\n } catch {\n return {};\n }\n}\n\nfunction validateConfig(raw: unknown): HooksConfig {\n if (!raw || typeof raw !== 'object') return {};\n\n const config: HooksConfig = {};\n const obj = raw as Record<string, unknown>;\n\n for (const event of VALID_EVENTS) {\n if (Array.isArray(obj[event])) {\n const hooks = (obj[event] as unknown[]).filter(isValidHook);\n if (hooks.length > 0) {\n config[event] = hooks;\n }\n }\n }\n\n return config;\n}\n\nfunction isValidHook(raw: unknown): raw is HookDefinition {\n if (!raw || typeof raw !== 'object') return false;\n const obj = raw as Record<string, unknown>;\n return obj.type === 'command' && typeof obj.command === 'string';\n}\n\nfunction mergeConfigs(global: HooksConfig, project: HooksConfig): HooksConfig {\n const merged: HooksConfig = {};\n\n for (const event of VALID_EVENTS) {\n const combined = [...(global[event] ?? []), ...(project[event] ?? [])];\n if (combined.length > 0) {\n merged[event] = combined;\n }\n }\n\n return merged;\n}\n"],"mappings":"AAMA,YAAY,QAAQ;AACpB,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,0BAA0B;AAG5B,MAAM,eAAgC;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,gBAAgB,YAAoB,gBAAgB,oBAAoB,SAA+B;AACrH,QAAM,aAAa,mBAAmB,eAAe,OAAO;AAC5D,QAAM,cAAc,oBAAoB,YAAY,aAAa;AAEjE,QAAM,eAAe,iBAAiB,UAAU;AAChD,QAAM,gBAAgB,iBAAiB,WAAW;AAElD,SAAO,aAAa,cAAc,aAAa;AACjD;AAEO,SAAS,oBAAoB,YAAoB,gBAAgB,oBAA4B;AAClG,SAAO,KAAK,KAAK,YAAY,eAAe,YAAY;AAC1D;AAEO,SAAS,mBAAmB,gBAAgB,oBAAoB,UAAU,GAAG,QAAQ,GAAW;AACrG,SAAO,KAAK,KAAK,SAAS,eAAe,YAAY;AACvD;AAEA,SAAS,iBAAiB,UAA+B;AACvD,MAAI;AACF,QAAI,CAAC,GAAG,WAAW,QAAQ,EAAG,QAAO,CAAC;AACtC,UAAM,MAAM,GAAG,aAAa,UAAU,OAAO;AAC7C,WAAO,eAAe,KAAK,MAAM,GAAG,CAAC;AAAA,EACvC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,eAAe,KAA2B;AACjD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO,CAAC;AAE7C,QAAM,SAAsB,CAAC;AAC7B,QAAM,MAAM;AAEZ,aAAW,SAAS,cAAc;AAChC,QAAI,MAAM,QAAQ,IAAI,KAAK,CAAC,GAAG;AAC7B,YAAM,QAAS,IAAI,KAAK,EAAgB,OAAO,WAAW;AAC1D,UAAI,MAAM,SAAS,GAAG;AACpB,eAAO,KAAK,IAAI;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,YAAY,KAAqC;AACxD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,MAAM;AACZ,SAAO,IAAI,SAAS,aAAa,OAAO,IAAI,YAAY;AAC1D;AAEA,SAAS,aAAa,QAAqB,SAAmC;AAC5E,QAAM,SAAsB,CAAC;AAE7B,aAAW,SAAS,cAAc;AAChC,UAAM,WAAW,CAAC,GAAI,OAAO,KAAK,KAAK,CAAC,GAAI,GAAI,QAAQ,KAAK,KAAK,CAAC,CAAE;AACrE,QAAI,SAAS,SAAS,GAAG;AACvB,aAAO,KAAK,IAAI;AAAA,IAClB;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"file":"config.js","names":["path","os","fs"],"sources":["../../src/hooks/config.ts"],"sourcesContent":["/**\n * Hook configuration loading from filesystem.\n * Loads from global (~/.mastracode/hooks.json) and project (.mastracode/hooks.json).\n * Global hooks run first, project hooks append.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport type { HooksConfig, HookDefinition, HookEventName } from './types.js';\n\nexport const VALID_EVENTS: HookEventName[] = [\n 'PreToolUse',\n 'PostToolUse',\n 'Stop',\n 'UserPromptSubmit',\n 'SessionStart',\n 'SessionEnd',\n 'Notification',\n 'AgentStart',\n 'AgentEnd',\n 'PermissionRequest',\n 'PermissionResult',\n 'Interrupt',\n 'SubagentStart',\n 'SubagentEnd',\n];\n\nexport function loadHooksConfig(projectDir: string, configDirName = DEFAULT_CONFIG_DIR, homeDir?: string): HooksConfig {\n const globalPath = getGlobalHooksPath(configDirName, homeDir);\n const projectPath = getProjectHooksPath(projectDir, configDirName);\n\n const globalConfig = loadSingleConfig(globalPath);\n const projectConfig = loadSingleConfig(projectPath);\n\n return mergeConfigs(globalConfig, projectConfig);\n}\n\nexport function getProjectHooksPath(projectDir: string, configDirName = DEFAULT_CONFIG_DIR): string {\n return path.join(projectDir, configDirName, 'hooks.json');\n}\n\nexport function getGlobalHooksPath(configDirName = DEFAULT_CONFIG_DIR, homeDir = os.homedir()): string {\n return path.join(homeDir, configDirName, 'hooks.json');\n}\n\nfunction loadSingleConfig(filePath: string): HooksConfig {\n try {\n if (!fs.existsSync(filePath)) return {};\n const raw = fs.readFileSync(filePath, 'utf-8');\n return validateConfig(JSON.parse(raw));\n } catch {\n return {};\n }\n}\n\nfunction validateConfig(raw: unknown): HooksConfig {\n if (!raw || typeof raw !== 'object') return {};\n\n const config: HooksConfig = {};\n const obj = raw as Record<string, unknown>;\n\n for (const event of VALID_EVENTS) {\n if (Array.isArray(obj[event])) {\n const hooks = (obj[event] as unknown[]).filter(isValidHook);\n if (hooks.length > 0) {\n config[event] = hooks;\n }\n }\n }\n\n return config;\n}\n\nfunction isValidHook(raw: unknown): raw is HookDefinition {\n if (!raw || typeof raw !== 'object') return false;\n const obj = raw as Record<string, unknown>;\n return obj.type === 'command' && typeof obj.command === 'string';\n}\n\nfunction mergeConfigs(global: HooksConfig, project: HooksConfig): HooksConfig {\n const merged: HooksConfig = {};\n\n for (const event of VALID_EVENTS) {\n const combined = [...(global[event] ?? []), ...(project[event] ?? [])];\n if (combined.length > 0) {\n merged[event] = combined;\n }\n }\n\n return merged;\n}\n"],"mappings":";;;;;;;;;;AAYA,MAAa,eAAgC;CAC3C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,SAAgB,gBAAgB,YAAoB,gBAAgB,oBAAoB,SAA+B;CACrH,MAAM,aAAa,mBAAmB,eAAe,OAAO;CAC5D,MAAM,cAAc,oBAAoB,YAAY,aAAa;CAKjE,OAAO,aAHc,iBAAiB,UAGP,GAFT,iBAAiB,WAEO,CAAC;AACjD;AAEA,SAAgB,oBAAoB,YAAoB,gBAAgB,oBAA4B;CAClG,OAAOA,OAAK,KAAK,YAAY,eAAe,YAAY;AAC1D;AAEA,SAAgB,mBAAmB,gBAAgB,oBAAoB,UAAUC,KAAG,QAAQ,GAAW;CACrG,OAAOD,OAAK,KAAK,SAAS,eAAe,YAAY;AACvD;AAEA,SAAS,iBAAiB,UAA+B;CACvD,IAAI;EACF,IAAI,CAACE,KAAG,WAAW,QAAQ,GAAG,OAAO,CAAC;EACtC,MAAM,MAAMA,KAAG,aAAa,UAAU,OAAO;EAC7C,OAAO,eAAe,KAAK,MAAM,GAAG,CAAC;CACvC,QAAQ;EACN,OAAO,CAAC;CACV;AACF;AAEA,SAAS,eAAe,KAA2B;CACjD,IAAI,CAAC,OAAO,OAAO,QAAQ,UAAU,OAAO,CAAC;CAE7C,MAAM,SAAsB,CAAC;CAC7B,MAAM,MAAM;CAEZ,KAAK,MAAM,SAAS,cAClB,IAAI,MAAM,QAAQ,IAAI,MAAM,GAAG;EAC7B,MAAM,QAAS,IAAI,MAAM,CAAe,OAAO,WAAW;EAC1D,IAAI,MAAM,SAAS,GACjB,OAAO,SAAS;CAEpB;CAGF,OAAO;AACT;AAEA,SAAS,YAAY,KAAqC;CACxD,IAAI,CAAC,OAAO,OAAO,QAAQ,UAAU,OAAO;CAC5C,MAAM,MAAM;CACZ,OAAO,IAAI,SAAS,aAAa,OAAO,IAAI,YAAY;AAC1D;AAEA,SAAS,aAAa,QAAqB,SAAmC;CAC5E,MAAM,SAAsB,CAAC;CAE7B,KAAK,MAAM,SAAS,cAAc;EAChC,MAAM,WAAW,CAAC,GAAI,OAAO,UAAU,CAAC,GAAI,GAAI,QAAQ,UAAU,CAAC,CAAE;EACrE,IAAI,SAAS,SAAS,GACpB,OAAO,SAAS;CAEpB;CAEA,OAAO;AACT"}
@@ -1,125 +1,127 @@
1
- import { spawn } from "node:child_process";
2
1
  import { isBlockingEvent } from "./types.js";
2
+ import { spawn } from "child_process";
3
+ //#region src/hooks/executor.ts
4
+ /**
5
+ * Hook process execution.
6
+ * Spawns shell commands, handles stdin/stdout/exit-code protocol.
7
+ */
3
8
  const DEFAULT_TIMEOUT = 1e4;
4
9
  async function executeHook(hook, stdinPayload) {
5
- const timeout = hook.timeout ?? DEFAULT_TIMEOUT;
6
- const startTime = Date.now();
7
- return new Promise((resolve) => {
8
- const isWindows = process.platform === "win32";
9
- const shell = isWindows ? "cmd" : "/bin/sh";
10
- const shellArgs = isWindows ? ["/c", hook.command] : ["-c", hook.command];
11
- const child = spawn(shell, shellArgs, {
12
- stdio: ["pipe", "pipe", "pipe"],
13
- cwd: stdinPayload.cwd,
14
- env: {
15
- ...process.env,
16
- MASTRA_HOOK_EVENT: stdinPayload.hook_event_name
17
- }
18
- });
19
- let stdout = "";
20
- let stderr = "";
21
- let timedOut = false;
22
- let resolved = false;
23
- const timer = setTimeout(() => {
24
- timedOut = true;
25
- child.kill("SIGKILL");
26
- }, timeout);
27
- child.stdout?.on("data", (data) => {
28
- stdout += data.toString();
29
- });
30
- child.stderr?.on("data", (data) => {
31
- stderr += data.toString();
32
- });
33
- child.on("close", (exitCode) => {
34
- clearTimeout(timer);
35
- if (resolved) return;
36
- resolved = true;
37
- let parsedStdout;
38
- if (stdout.trim()) {
39
- try {
40
- parsedStdout = JSON.parse(stdout.trim());
41
- } catch {
42
- }
43
- }
44
- resolve({
45
- hook,
46
- exitCode: exitCode ?? 1,
47
- stdout: parsedStdout,
48
- stderr: stderr.trim() || void 0,
49
- timedOut,
50
- durationMs: Date.now() - startTime
51
- });
52
- });
53
- child.on("error", (error) => {
54
- clearTimeout(timer);
55
- if (resolved) return;
56
- resolved = true;
57
- resolve({
58
- hook,
59
- exitCode: 1,
60
- stderr: error.message,
61
- timedOut: false,
62
- durationMs: Date.now() - startTime
63
- });
64
- });
65
- try {
66
- child.stdin?.write(JSON.stringify(stdinPayload));
67
- child.stdin?.end();
68
- } catch {
69
- }
70
- });
10
+ const timeout = hook.timeout ?? DEFAULT_TIMEOUT;
11
+ const startTime = Date.now();
12
+ return new Promise((resolve) => {
13
+ const isWindows = process.platform === "win32";
14
+ const child = spawn(isWindows ? "cmd" : "/bin/sh", isWindows ? ["/c", hook.command] : ["-c", hook.command], {
15
+ stdio: [
16
+ "pipe",
17
+ "pipe",
18
+ "pipe"
19
+ ],
20
+ cwd: stdinPayload.cwd,
21
+ env: {
22
+ ...process.env,
23
+ MASTRA_HOOK_EVENT: stdinPayload.hook_event_name
24
+ }
25
+ });
26
+ let stdout = "";
27
+ let stderr = "";
28
+ let timedOut = false;
29
+ let resolved = false;
30
+ const timer = setTimeout(() => {
31
+ timedOut = true;
32
+ child.kill("SIGKILL");
33
+ }, timeout);
34
+ child.stdout?.on("data", (data) => {
35
+ stdout += data.toString();
36
+ });
37
+ child.stderr?.on("data", (data) => {
38
+ stderr += data.toString();
39
+ });
40
+ child.on("close", (exitCode) => {
41
+ clearTimeout(timer);
42
+ if (resolved) return;
43
+ resolved = true;
44
+ let parsedStdout;
45
+ if (stdout.trim()) try {
46
+ parsedStdout = JSON.parse(stdout.trim());
47
+ } catch {}
48
+ resolve({
49
+ hook,
50
+ exitCode: exitCode ?? 1,
51
+ stdout: parsedStdout,
52
+ stderr: stderr.trim() || void 0,
53
+ timedOut,
54
+ durationMs: Date.now() - startTime
55
+ });
56
+ });
57
+ child.on("error", (error) => {
58
+ clearTimeout(timer);
59
+ if (resolved) return;
60
+ resolved = true;
61
+ resolve({
62
+ hook,
63
+ exitCode: 1,
64
+ stderr: error.message,
65
+ timedOut: false,
66
+ durationMs: Date.now() - startTime
67
+ });
68
+ });
69
+ try {
70
+ child.stdin?.write(JSON.stringify(stdinPayload));
71
+ child.stdin?.end();
72
+ } catch {}
73
+ });
71
74
  }
72
75
  function matchesHook(hook, context) {
73
- if (!hook.matcher) return true;
74
- if (hook.matcher.tool_name) {
75
- if (!context.tool_name) return false;
76
- try {
77
- return new RegExp(hook.matcher.tool_name).test(context.tool_name);
78
- } catch {
79
- return false;
80
- }
81
- }
82
- return true;
76
+ if (!hook.matcher) return true;
77
+ if (hook.matcher.tool_name) {
78
+ if (!context.tool_name) return false;
79
+ try {
80
+ return new RegExp(hook.matcher.tool_name).test(context.tool_name);
81
+ } catch {
82
+ return false;
83
+ }
84
+ }
85
+ return true;
83
86
  }
84
87
  async function runHooksForEvent(hooks, stdinPayload, matchContext = {}) {
85
- const results = [];
86
- const warnings = [];
87
- let additionalContext;
88
- const applicable = hooks.filter((h) => matchesHook(h, matchContext));
89
- if (applicable.length === 0) {
90
- return { allowed: true, results: [], warnings: [] };
91
- }
92
- const blocking = isBlockingEvent(stdinPayload.hook_event_name);
93
- for (const hook of applicable) {
94
- const result = await executeHook(hook, stdinPayload);
95
- results.push(result);
96
- if (result.stdout?.additionalContext) {
97
- additionalContext = additionalContext ? `${additionalContext}
98
- ${result.stdout.additionalContext}` : result.stdout.additionalContext;
99
- }
100
- if (result.timedOut) {
101
- warnings.push(`Hook timed out after ${hook.timeout ?? DEFAULT_TIMEOUT}ms: ${hook.command}`);
102
- continue;
103
- }
104
- if (result.exitCode === 2 && blocking) {
105
- const reason = result.stdout?.reason || result.stderr || `Blocked by hook: ${hook.description || hook.command}`;
106
- return {
107
- allowed: false,
108
- blockReason: reason,
109
- additionalContext,
110
- results,
111
- warnings
112
- };
113
- }
114
- if (result.exitCode === 0) continue;
115
- const warnMsg = result.stderr || `Hook exited with code ${result.exitCode}`;
116
- warnings.push(`${hook.description || hook.command}: ${warnMsg}`);
117
- }
118
- return { allowed: true, additionalContext, results, warnings };
88
+ const results = [];
89
+ const warnings = [];
90
+ let additionalContext;
91
+ const applicable = hooks.filter((h) => matchesHook(h, matchContext));
92
+ if (applicable.length === 0) return {
93
+ allowed: true,
94
+ results: [],
95
+ warnings: []
96
+ };
97
+ const blocking = isBlockingEvent(stdinPayload.hook_event_name);
98
+ for (const hook of applicable) {
99
+ const result = await executeHook(hook, stdinPayload);
100
+ results.push(result);
101
+ if (result.stdout?.additionalContext) additionalContext = additionalContext ? `${additionalContext}\n${result.stdout.additionalContext}` : result.stdout.additionalContext;
102
+ if (result.timedOut) {
103
+ warnings.push(`Hook timed out after ${hook.timeout ?? DEFAULT_TIMEOUT}ms: ${hook.command}`);
104
+ continue;
105
+ }
106
+ if (result.exitCode === 2 && blocking) return {
107
+ allowed: false,
108
+ blockReason: result.stdout?.reason || result.stderr || `Blocked by hook: ${hook.description || hook.command}`,
109
+ additionalContext,
110
+ results,
111
+ warnings
112
+ };
113
+ if (result.exitCode === 0) continue;
114
+ const warnMsg = result.stderr || `Hook exited with code ${result.exitCode}`;
115
+ warnings.push(`${hook.description || hook.command}: ${warnMsg}`);
116
+ }
117
+ return {
118
+ allowed: true,
119
+ additionalContext,
120
+ results,
121
+ warnings
122
+ };
119
123
  }
120
- export {
121
- executeHook,
122
- matchesHook,
123
- runHooksForEvent
124
- };
124
+ //#endregion
125
+ export { executeHook, matchesHook, runHooksForEvent };
126
+
125
127
  //# sourceMappingURL=executor.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/executor.ts"],"sourcesContent":["/**\n * Hook process execution.\n * Spawns shell commands, handles stdin/stdout/exit-code protocol.\n */\n\nimport { spawn } from 'node:child_process';\nimport type { HookDefinition, HookStdin, HookResult, HookStdout, HookEventResult } from './types.js';\nimport { isBlockingEvent } from './types.js';\n\nconst DEFAULT_TIMEOUT = 10_000;\n\nexport async function executeHook(hook: HookDefinition, stdinPayload: HookStdin): Promise<HookResult> {\n const timeout = hook.timeout ?? DEFAULT_TIMEOUT;\n const startTime = Date.now();\n\n return new Promise<HookResult>(resolve => {\n const isWindows = process.platform === 'win32';\n const shell = isWindows ? 'cmd' : '/bin/sh';\n const shellArgs = isWindows ? ['/c', hook.command] : ['-c', hook.command];\n\n const child = spawn(shell, shellArgs, {\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: stdinPayload.cwd,\n env: {\n ...process.env,\n MASTRA_HOOK_EVENT: stdinPayload.hook_event_name,\n },\n });\n\n let stdout = '';\n let stderr = '';\n let timedOut = false;\n let resolved = false;\n\n const timer = setTimeout(() => {\n timedOut = true;\n child.kill('SIGKILL');\n }, timeout);\n\n child.stdout?.on('data', (data: Buffer) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('close', exitCode => {\n clearTimeout(timer);\n if (resolved) return;\n resolved = true;\n\n let parsedStdout: HookStdout | undefined;\n if (stdout.trim()) {\n try {\n parsedStdout = JSON.parse(stdout.trim()) as HookStdout;\n } catch {\n // Not valid JSON — ignore\n }\n }\n\n resolve({\n hook,\n exitCode: exitCode ?? 1,\n stdout: parsedStdout,\n stderr: stderr.trim() || undefined,\n timedOut,\n durationMs: Date.now() - startTime,\n });\n });\n\n child.on('error', error => {\n clearTimeout(timer);\n if (resolved) return;\n resolved = true;\n\n resolve({\n hook,\n exitCode: 1,\n stderr: error.message,\n timedOut: false,\n durationMs: Date.now() - startTime,\n });\n });\n\n try {\n child.stdin?.write(JSON.stringify(stdinPayload));\n child.stdin?.end();\n } catch {\n // stdin write failure — process continues\n }\n });\n}\n\nexport function matchesHook(hook: HookDefinition, context: { tool_name?: string }): boolean {\n if (!hook.matcher) return true;\n\n if (hook.matcher.tool_name) {\n if (!context.tool_name) return false;\n try {\n return new RegExp(hook.matcher.tool_name).test(context.tool_name);\n } catch {\n return false;\n }\n }\n\n return true;\n}\n\nexport async function runHooksForEvent(\n hooks: HookDefinition[],\n stdinPayload: HookStdin,\n matchContext: { tool_name?: string } = {},\n): Promise<HookEventResult> {\n const results: HookResult[] = [];\n const warnings: string[] = [];\n let additionalContext: string | undefined;\n\n const applicable = hooks.filter(h => matchesHook(h, matchContext));\n if (applicable.length === 0) {\n return { allowed: true, results: [], warnings: [] };\n }\n\n const blocking = isBlockingEvent(stdinPayload.hook_event_name);\n\n for (const hook of applicable) {\n const result = await executeHook(hook, stdinPayload);\n results.push(result);\n\n if (result.stdout?.additionalContext) {\n additionalContext = additionalContext\n ? `${additionalContext}\\n${result.stdout.additionalContext}`\n : result.stdout.additionalContext;\n }\n\n if (result.timedOut) {\n warnings.push(`Hook timed out after ${hook.timeout ?? DEFAULT_TIMEOUT}ms: ${hook.command}`);\n continue;\n }\n\n if (result.exitCode === 2 && blocking) {\n const reason = result.stdout?.reason || result.stderr || `Blocked by hook: ${hook.description || hook.command}`;\n\n return {\n allowed: false,\n blockReason: reason,\n additionalContext,\n results,\n warnings,\n };\n }\n\n if (result.exitCode === 0) continue;\n\n const warnMsg = result.stderr || `Hook exited with code ${result.exitCode}`;\n warnings.push(`${hook.description || hook.command}: ${warnMsg}`);\n }\n\n return { allowed: true, additionalContext, results, warnings };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"file":"executor.js","names":[],"sources":["../../src/hooks/executor.ts"],"sourcesContent":["/**\n * Hook process execution.\n * Spawns shell commands, handles stdin/stdout/exit-code protocol.\n */\n\nimport { spawn } from 'node:child_process';\nimport type { HookDefinition, HookStdin, HookResult, HookStdout, HookEventResult } from './types.js';\nimport { isBlockingEvent } from './types.js';\n\nconst DEFAULT_TIMEOUT = 10_000;\n\nexport async function executeHook(hook: HookDefinition, stdinPayload: HookStdin): Promise<HookResult> {\n const timeout = hook.timeout ?? DEFAULT_TIMEOUT;\n const startTime = Date.now();\n\n return new Promise<HookResult>(resolve => {\n const isWindows = process.platform === 'win32';\n const shell = isWindows ? 'cmd' : '/bin/sh';\n const shellArgs = isWindows ? ['/c', hook.command] : ['-c', hook.command];\n\n const child = spawn(shell, shellArgs, {\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: stdinPayload.cwd,\n env: {\n ...process.env,\n MASTRA_HOOK_EVENT: stdinPayload.hook_event_name,\n },\n });\n\n let stdout = '';\n let stderr = '';\n let timedOut = false;\n let resolved = false;\n\n const timer = setTimeout(() => {\n timedOut = true;\n child.kill('SIGKILL');\n }, timeout);\n\n child.stdout?.on('data', (data: Buffer) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('close', exitCode => {\n clearTimeout(timer);\n if (resolved) return;\n resolved = true;\n\n let parsedStdout: HookStdout | undefined;\n if (stdout.trim()) {\n try {\n parsedStdout = JSON.parse(stdout.trim()) as HookStdout;\n } catch {\n // Not valid JSON — ignore\n }\n }\n\n resolve({\n hook,\n exitCode: exitCode ?? 1,\n stdout: parsedStdout,\n stderr: stderr.trim() || undefined,\n timedOut,\n durationMs: Date.now() - startTime,\n });\n });\n\n child.on('error', error => {\n clearTimeout(timer);\n if (resolved) return;\n resolved = true;\n\n resolve({\n hook,\n exitCode: 1,\n stderr: error.message,\n timedOut: false,\n durationMs: Date.now() - startTime,\n });\n });\n\n try {\n child.stdin?.write(JSON.stringify(stdinPayload));\n child.stdin?.end();\n } catch {\n // stdin write failure — process continues\n }\n });\n}\n\nexport function matchesHook(hook: HookDefinition, context: { tool_name?: string }): boolean {\n if (!hook.matcher) return true;\n\n if (hook.matcher.tool_name) {\n if (!context.tool_name) return false;\n try {\n return new RegExp(hook.matcher.tool_name).test(context.tool_name);\n } catch {\n return false;\n }\n }\n\n return true;\n}\n\nexport async function runHooksForEvent(\n hooks: HookDefinition[],\n stdinPayload: HookStdin,\n matchContext: { tool_name?: string } = {},\n): Promise<HookEventResult> {\n const results: HookResult[] = [];\n const warnings: string[] = [];\n let additionalContext: string | undefined;\n\n const applicable = hooks.filter(h => matchesHook(h, matchContext));\n if (applicable.length === 0) {\n return { allowed: true, results: [], warnings: [] };\n }\n\n const blocking = isBlockingEvent(stdinPayload.hook_event_name);\n\n for (const hook of applicable) {\n const result = await executeHook(hook, stdinPayload);\n results.push(result);\n\n if (result.stdout?.additionalContext) {\n additionalContext = additionalContext\n ? `${additionalContext}\\n${result.stdout.additionalContext}`\n : result.stdout.additionalContext;\n }\n\n if (result.timedOut) {\n warnings.push(`Hook timed out after ${hook.timeout ?? DEFAULT_TIMEOUT}ms: ${hook.command}`);\n continue;\n }\n\n if (result.exitCode === 2 && blocking) {\n const reason = result.stdout?.reason || result.stderr || `Blocked by hook: ${hook.description || hook.command}`;\n\n return {\n allowed: false,\n blockReason: reason,\n additionalContext,\n results,\n warnings,\n };\n }\n\n if (result.exitCode === 0) continue;\n\n const warnMsg = result.stderr || `Hook exited with code ${result.exitCode}`;\n warnings.push(`${hook.description || hook.command}: ${warnMsg}`);\n }\n\n return { allowed: true, additionalContext, results, warnings };\n}\n"],"mappings":"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"}