@mastra/code-sdk 1.0.3-alpha.1 → 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 +38 -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 +12 -12
  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/plugins/install.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { execa } from 'execa';\n\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport { getEntryPackageRoot, installPluginDependenciesForEntry } from './dependencies.js';\nimport type { PluginInstallExecutionOptions } from './dependencies.js';\nimport { loadPluginFromEntry } from './loader.js';\nimport { getSingleManifestPlugin } from './manifest.js';\nimport { ensureMastraCodePackageLink } from './package-link.js';\nimport { getPluginRoot, getPluginScopePaths } from './paths.js';\nimport type { PluginPathOptions } from './paths.js';\nimport { loadPluginRegistry, removePluginRecord, savePluginRegistry, setPluginRecord } from './registry.js';\nimport type { InstalledPluginRecord, PluginScope } from './types.js';\n\nexport type InstallPluginOptions = PluginPathOptions &\n PluginInstallExecutionOptions & {\n entry?: string;\n ref?: string;\n githubCliPath?: string;\n };\n\nexport type DiscoveredLocalPlugin = {\n name: string;\n path: string;\n entry: string;\n};\n\nconst ENTRY_CANDIDATES = ['src/index.ts', 'index.ts'];\n\nexport const NON_INTERACTIVE_GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: '0' };\n\nconst NON_INTERACTIVE_EXEC_OPTIONS = { env: NON_INTERACTIVE_GIT_ENV };\n\nexport async function installLocalPlugin(\n localPath: string,\n scope: PluginScope,\n options: InstallPluginOptions,\n): Promise<string> {\n const sourcePath = path.resolve(options.projectRoot, localPath);\n if (!fs.existsSync(sourcePath) || !fs.statSync(sourcePath).isDirectory()) {\n throw new Error(`Local plugin path does not exist or is not a directory: ${localPath}`);\n }\n\n const entry = detectEntry(sourcePath, options.entry);\n ensureMastraCodePackageLink(sourcePath);\n const plugin = await loadPluginFromEntry(path.join(sourcePath, entry));\n const registryPath = getPluginScopePaths(scope, options).registryPath;\n const registry = removePluginRecord(loadPluginRegistry(registryPath), plugin.id);\n const record: InstalledPluginRecord = {\n enabled: true,\n source: 'local',\n specifier: localPath,\n path: sourcePath,\n entry,\n ...(plugin.version ? { version: plugin.version } : {}),\n };\n\n savePluginRegistry(registryPath, setPluginRecord(registry, plugin.id, record));\n return plugin.id;\n}\n\nexport async function installGithubPlugin(\n url: string,\n scope: PluginScope,\n options: InstallPluginOptions,\n): Promise<string> {\n const parsed = parseGithubUrl(url);\n const paths = getPluginScopePaths(scope, options);\n const checkoutDir = path.join(paths.sourcesPath, 'github', `${parsed.owner}-${parsed.repo}`);\n\n const githubCli = options.githubCliPath ?? 'gh';\n await assertGithubCliAvailable(githubCli);\n await assertGithubCliAuthenticated(githubCli);\n\n fs.rmSync(checkoutDir, { recursive: true, force: true });\n fs.mkdirSync(path.dirname(checkoutDir), { recursive: true });\n const ref = options.ref ?? parsed.ref;\n const cloneArgs = ['repo', 'clone', parsed.repoSpec, checkoutDir, ...(ref ? [] : ['--', '--depth', '1'])];\n await runPluginInstallCommand(githubCli, cloneArgs, { env: NON_INTERACTIVE_GIT_ENV }, options);\n if (ref) {\n await runPluginInstallCommand(\n 'git',\n ['checkout', ref],\n { cwd: checkoutDir, env: NON_INTERACTIVE_GIT_ENV },\n options,\n );\n }\n\n const entry = detectEntry(checkoutDir, options.entry);\n await installPluginDependenciesForEntry(checkoutDir, entry, options);\n ensureMastraCodePackageLink(getEntryPackageRoot(checkoutDir, entry));\n const plugin = await loadPluginFromEntry(path.join(checkoutDir, entry));\n const registry = removePluginRecord(loadPluginRegistry(paths.registryPath), plugin.id);\n const relativePath = path.relative(getPluginRoot(scope, options), checkoutDir);\n const record: InstalledPluginRecord = {\n enabled: true,\n source: 'github',\n specifier: url,\n path: relativePath,\n entry,\n ...(ref ? { ref } : {}),\n ...(plugin.version ? { version: plugin.version } : {}),\n };\n\n savePluginRegistry(paths.registryPath, setPluginRecord(registry, plugin.id, record));\n return plugin.id;\n}\n\nexport function discoverLocalPlugins(searchRoot: string, options: PluginPathOptions): DiscoveredLocalPlugin[] {\n const root = path.resolve(options.projectRoot, searchRoot);\n const localSourcesRoot = path.join(root, options.configDir ?? DEFAULT_CONFIG_DIR, 'plugins', 'sources', 'local');\n const scanRoot = isLocalSourcesDir(root) ? root : localSourcesRoot;\n\n const seen = new Set<string>();\n return discoverPluginDirs(scanRoot)\n .filter(candidate => {\n if (seen.has(candidate.path)) return false;\n seen.add(candidate.path);\n return true;\n })\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction isLocalSourcesDir(dir: string): boolean {\n const normalized = dir.split(path.sep).join('/');\n return normalized.endsWith('/plugins/sources/local');\n}\n\nfunction discoverPluginDirs(root: string): DiscoveredLocalPlugin[] {\n if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) return [];\n return fs\n .readdirSync(root, { withFileTypes: true })\n .filter(entry => entry.isDirectory())\n .flatMap(entry => {\n const pluginDir = path.join(root, entry.name);\n const detectedEntry = tryDetectEntry(pluginDir);\n return detectedEntry ? [{ name: entry.name, path: pluginDir, entry: detectedEntry }] : [];\n });\n}\n\nfunction tryDetectEntry(pluginDir: string): string | undefined {\n try {\n return detectEntry(pluginDir);\n } catch {\n return undefined;\n }\n}\n\nexport function detectEntry(pluginDir: string, explicitEntry?: string): string {\n const root = path.resolve(pluginDir);\n if (explicitEntry) {\n const entryPath = path.resolve(pluginDir, explicitEntry);\n if (!isInsideDirectory(entryPath, root)) {\n throw new Error('Plugin entry must be inside the plugin directory');\n }\n if (fs.existsSync(entryPath) && fs.statSync(entryPath).isDirectory()) {\n const nestedEntry = detectEntry(entryPath);\n return path.relative(root, path.join(entryPath, nestedEntry));\n }\n if (path.extname(entryPath) !== '.ts') {\n throw new Error('Plugin entry must be a .ts file');\n }\n if (!fs.existsSync(entryPath) || !fs.statSync(entryPath).isFile()) {\n throw new Error(`Plugin entry file does not exist: ${explicitEntry}`);\n }\n return path.relative(root, entryPath);\n }\n\n const manifestPlugin = getSingleManifestPlugin(pluginDir);\n if (manifestPlugin) {\n return detectEntry(pluginDir, manifestPlugin.entry);\n }\n\n for (const candidate of ENTRY_CANDIDATES) {\n const entryPath = path.join(pluginDir, candidate);\n if (fs.existsSync(entryPath) && fs.statSync(entryPath).isFile()) {\n return candidate;\n }\n }\n\n throw new Error(`Could not find a plugin entry file. Tried: ${ENTRY_CANDIDATES.join(', ')}`);\n}\n\nfunction isInsideDirectory(targetPath: string, root: string): boolean {\n return targetPath === root || targetPath.startsWith(root + path.sep);\n}\n\nasync function runPluginInstallCommand(\n command: string,\n args: string[],\n execaOptions: typeof NON_INTERACTIVE_EXEC_OPTIONS & { cwd?: string },\n options: PluginInstallExecutionOptions,\n): Promise<void> {\n const child = execa(command, args, {\n ...execaOptions,\n stdout: options.onOutput ? 'pipe' : 'ignore',\n stderr: options.onOutput ? 'pipe' : 'ignore',\n cancelSignal: options.signal,\n });\n if (options.onOutput) {\n child.stdout?.on('data', options.onOutput);\n child.stderr?.on('data', options.onOutput);\n }\n await child;\n}\n\nasync function assertGithubCliAvailable(githubCli: string): Promise<void> {\n try {\n await execa(githubCli, ['--version'], NON_INTERACTIVE_EXEC_OPTIONS);\n } catch {\n throw new Error('GitHub CLI is required to install GitHub plugins. Install gh and run gh auth login.');\n }\n}\n\nasync function assertGithubCliAuthenticated(githubCli: string): Promise<void> {\n try {\n await execa(githubCli, ['auth', 'status'], NON_INTERACTIVE_EXEC_OPTIONS);\n } catch {\n throw new Error('GitHub CLI is not authenticated. Run gh auth login, then install the plugin again.');\n }\n}\n\nfunction parseGithubUrl(specifier: string): { owner: string; repo: string; repoSpec: string; ref?: string } {\n const [urlPart, ref] = specifier.split('#', 2);\n if (!urlPart) {\n throw new Error(`Invalid GitHub URL: ${specifier}`);\n }\n let url: URL;\n try {\n url = new URL(urlPart);\n } catch {\n throw new Error(`Invalid GitHub URL: ${specifier}`);\n }\n\n if (url.hostname !== 'github.com') {\n throw new Error('Only github.com plugin URLs are supported');\n }\n\n const [owner, rawRepo, ...rest] = url.pathname.split('/').filter(Boolean);\n if (!owner || !rawRepo || rest.length > 0) {\n throw new Error('GitHub plugin URL must be in the form https://github.com/owner/repo');\n }\n\n const repo = rawRepo.replace(/\\.git$/, '');\n if (!/^[A-Za-z0-9_.-]+$/.test(owner) || !/^[A-Za-z0-9_.-]+$/.test(repo)) {\n throw new Error('GitHub owner and repo may only contain letters, numbers, dots, underscores, and dashes');\n }\n\n return {\n owner,\n repo,\n repoSpec: `${owner}/${repo}`,\n ...(ref ? { ref } : {}),\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"file":"install.js","names":[],"sources":["../../src/plugins/install.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { execa } from 'execa';\n\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport { getEntryPackageRoot, installPluginDependenciesForEntry } from './dependencies.js';\nimport type { PluginInstallExecutionOptions } from './dependencies.js';\nimport { loadPluginFromEntry } from './loader.js';\nimport { getSingleManifestPlugin } from './manifest.js';\nimport { ensureMastraCodePackageLink } from './package-link.js';\nimport { getPluginRoot, getPluginScopePaths } from './paths.js';\nimport type { PluginPathOptions } from './paths.js';\nimport { loadPluginRegistry, removePluginRecord, savePluginRegistry, setPluginRecord } from './registry.js';\nimport type { InstalledPluginRecord, PluginScope } from './types.js';\n\nexport type InstallPluginOptions = PluginPathOptions &\n PluginInstallExecutionOptions & {\n entry?: string;\n ref?: string;\n githubCliPath?: string;\n };\n\nexport type DiscoveredLocalPlugin = {\n name: string;\n path: string;\n entry: string;\n};\n\nconst ENTRY_CANDIDATES = ['src/index.ts', 'index.ts'];\n\nexport const NON_INTERACTIVE_GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: '0' };\n\nconst NON_INTERACTIVE_EXEC_OPTIONS = { env: NON_INTERACTIVE_GIT_ENV };\n\nexport async function installLocalPlugin(\n localPath: string,\n scope: PluginScope,\n options: InstallPluginOptions,\n): Promise<string> {\n const sourcePath = path.resolve(options.projectRoot, localPath);\n if (!fs.existsSync(sourcePath) || !fs.statSync(sourcePath).isDirectory()) {\n throw new Error(`Local plugin path does not exist or is not a directory: ${localPath}`);\n }\n\n const entry = detectEntry(sourcePath, options.entry);\n ensureMastraCodePackageLink(sourcePath);\n const plugin = await loadPluginFromEntry(path.join(sourcePath, entry));\n const registryPath = getPluginScopePaths(scope, options).registryPath;\n const registry = removePluginRecord(loadPluginRegistry(registryPath), plugin.id);\n const record: InstalledPluginRecord = {\n enabled: true,\n source: 'local',\n specifier: localPath,\n path: sourcePath,\n entry,\n ...(plugin.version ? { version: plugin.version } : {}),\n };\n\n savePluginRegistry(registryPath, setPluginRecord(registry, plugin.id, record));\n return plugin.id;\n}\n\nexport async function installGithubPlugin(\n url: string,\n scope: PluginScope,\n options: InstallPluginOptions,\n): Promise<string> {\n const parsed = parseGithubUrl(url);\n const paths = getPluginScopePaths(scope, options);\n const checkoutDir = path.join(paths.sourcesPath, 'github', `${parsed.owner}-${parsed.repo}`);\n\n const githubCli = options.githubCliPath ?? 'gh';\n await assertGithubCliAvailable(githubCli);\n await assertGithubCliAuthenticated(githubCli);\n\n fs.rmSync(checkoutDir, { recursive: true, force: true });\n fs.mkdirSync(path.dirname(checkoutDir), { recursive: true });\n const ref = options.ref ?? parsed.ref;\n const cloneArgs = ['repo', 'clone', parsed.repoSpec, checkoutDir, ...(ref ? [] : ['--', '--depth', '1'])];\n await runPluginInstallCommand(githubCli, cloneArgs, { env: NON_INTERACTIVE_GIT_ENV }, options);\n if (ref) {\n await runPluginInstallCommand(\n 'git',\n ['checkout', ref],\n { cwd: checkoutDir, env: NON_INTERACTIVE_GIT_ENV },\n options,\n );\n }\n\n const entry = detectEntry(checkoutDir, options.entry);\n await installPluginDependenciesForEntry(checkoutDir, entry, options);\n ensureMastraCodePackageLink(getEntryPackageRoot(checkoutDir, entry));\n const plugin = await loadPluginFromEntry(path.join(checkoutDir, entry));\n const registry = removePluginRecord(loadPluginRegistry(paths.registryPath), plugin.id);\n const relativePath = path.relative(getPluginRoot(scope, options), checkoutDir);\n const record: InstalledPluginRecord = {\n enabled: true,\n source: 'github',\n specifier: url,\n path: relativePath,\n entry,\n ...(ref ? { ref } : {}),\n ...(plugin.version ? { version: plugin.version } : {}),\n };\n\n savePluginRegistry(paths.registryPath, setPluginRecord(registry, plugin.id, record));\n return plugin.id;\n}\n\nexport function discoverLocalPlugins(searchRoot: string, options: PluginPathOptions): DiscoveredLocalPlugin[] {\n const root = path.resolve(options.projectRoot, searchRoot);\n const localSourcesRoot = path.join(root, options.configDir ?? DEFAULT_CONFIG_DIR, 'plugins', 'sources', 'local');\n const scanRoot = isLocalSourcesDir(root) ? root : localSourcesRoot;\n\n const seen = new Set<string>();\n return discoverPluginDirs(scanRoot)\n .filter(candidate => {\n if (seen.has(candidate.path)) return false;\n seen.add(candidate.path);\n return true;\n })\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction isLocalSourcesDir(dir: string): boolean {\n const normalized = dir.split(path.sep).join('/');\n return normalized.endsWith('/plugins/sources/local');\n}\n\nfunction discoverPluginDirs(root: string): DiscoveredLocalPlugin[] {\n if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) return [];\n return fs\n .readdirSync(root, { withFileTypes: true })\n .filter(entry => entry.isDirectory())\n .flatMap(entry => {\n const pluginDir = path.join(root, entry.name);\n const detectedEntry = tryDetectEntry(pluginDir);\n return detectedEntry ? [{ name: entry.name, path: pluginDir, entry: detectedEntry }] : [];\n });\n}\n\nfunction tryDetectEntry(pluginDir: string): string | undefined {\n try {\n return detectEntry(pluginDir);\n } catch {\n return undefined;\n }\n}\n\nexport function detectEntry(pluginDir: string, explicitEntry?: string): string {\n const root = path.resolve(pluginDir);\n if (explicitEntry) {\n const entryPath = path.resolve(pluginDir, explicitEntry);\n if (!isInsideDirectory(entryPath, root)) {\n throw new Error('Plugin entry must be inside the plugin directory');\n }\n if (fs.existsSync(entryPath) && fs.statSync(entryPath).isDirectory()) {\n const nestedEntry = detectEntry(entryPath);\n return path.relative(root, path.join(entryPath, nestedEntry));\n }\n if (path.extname(entryPath) !== '.ts') {\n throw new Error('Plugin entry must be a .ts file');\n }\n if (!fs.existsSync(entryPath) || !fs.statSync(entryPath).isFile()) {\n throw new Error(`Plugin entry file does not exist: ${explicitEntry}`);\n }\n return path.relative(root, entryPath);\n }\n\n const manifestPlugin = getSingleManifestPlugin(pluginDir);\n if (manifestPlugin) {\n return detectEntry(pluginDir, manifestPlugin.entry);\n }\n\n for (const candidate of ENTRY_CANDIDATES) {\n const entryPath = path.join(pluginDir, candidate);\n if (fs.existsSync(entryPath) && fs.statSync(entryPath).isFile()) {\n return candidate;\n }\n }\n\n throw new Error(`Could not find a plugin entry file. Tried: ${ENTRY_CANDIDATES.join(', ')}`);\n}\n\nfunction isInsideDirectory(targetPath: string, root: string): boolean {\n return targetPath === root || targetPath.startsWith(root + path.sep);\n}\n\nasync function runPluginInstallCommand(\n command: string,\n args: string[],\n execaOptions: typeof NON_INTERACTIVE_EXEC_OPTIONS & { cwd?: string },\n options: PluginInstallExecutionOptions,\n): Promise<void> {\n const child = execa(command, args, {\n ...execaOptions,\n stdout: options.onOutput ? 'pipe' : 'ignore',\n stderr: options.onOutput ? 'pipe' : 'ignore',\n cancelSignal: options.signal,\n });\n if (options.onOutput) {\n child.stdout?.on('data', options.onOutput);\n child.stderr?.on('data', options.onOutput);\n }\n await child;\n}\n\nasync function assertGithubCliAvailable(githubCli: string): Promise<void> {\n try {\n await execa(githubCli, ['--version'], NON_INTERACTIVE_EXEC_OPTIONS);\n } catch {\n throw new Error('GitHub CLI is required to install GitHub plugins. Install gh and run gh auth login.');\n }\n}\n\nasync function assertGithubCliAuthenticated(githubCli: string): Promise<void> {\n try {\n await execa(githubCli, ['auth', 'status'], NON_INTERACTIVE_EXEC_OPTIONS);\n } catch {\n throw new Error('GitHub CLI is not authenticated. Run gh auth login, then install the plugin again.');\n }\n}\n\nfunction parseGithubUrl(specifier: string): { owner: string; repo: string; repoSpec: string; ref?: string } {\n const [urlPart, ref] = specifier.split('#', 2);\n if (!urlPart) {\n throw new Error(`Invalid GitHub URL: ${specifier}`);\n }\n let url: URL;\n try {\n url = new URL(urlPart);\n } catch {\n throw new Error(`Invalid GitHub URL: ${specifier}`);\n }\n\n if (url.hostname !== 'github.com') {\n throw new Error('Only github.com plugin URLs are supported');\n }\n\n const [owner, rawRepo, ...rest] = url.pathname.split('/').filter(Boolean);\n if (!owner || !rawRepo || rest.length > 0) {\n throw new Error('GitHub plugin URL must be in the form https://github.com/owner/repo');\n }\n\n const repo = rawRepo.replace(/\\.git$/, '');\n if (!/^[A-Za-z0-9_.-]+$/.test(owner) || !/^[A-Za-z0-9_.-]+$/.test(repo)) {\n throw new Error('GitHub owner and repo may only contain letters, numbers, dots, underscores, and dashes');\n }\n\n return {\n owner,\n repo,\n repoSpec: `${owner}/${repo}`,\n ...(ref ? { ref } : {}),\n };\n}\n"],"mappings":"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"}
@@ -1,221 +1,206 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { pathToFileURL } from "node:url";
4
1
  import { getPluginRoot } from "./paths.js";
5
2
  import { loadPluginRegistry, mergePluginRegistries } from "./registry.js";
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import { pathToFileURL } from "url";
6
+ //#region src/plugins/loader.ts
6
7
  async function loadPlugins(options) {
7
- const globalRegistry = options.globalRegistry ?? loadPluginRegistry(path.join(getPluginRoot("global", options), "plugins.json"));
8
- const projectRegistry = options.projectRegistry ?? loadPluginRegistry(path.join(getPluginRoot("project", options), "plugins.json"));
9
- const records = mergePluginRegistries(globalRegistry, projectRegistry);
10
- const loaded = [];
11
- for (const record of records) {
12
- if (record.blocked) {
13
- loaded.push({ ...record, status: "blocked", tools: {}, toolNames: [] });
14
- continue;
15
- }
16
- if (!record.enabled) {
17
- loaded.push({ ...record, status: "inactive", tools: {}, toolNames: [] });
18
- continue;
19
- }
20
- loaded.push(await loadPluginRecord(record, options));
21
- }
22
- return markToolConflicts(loaded);
8
+ const records = mergePluginRegistries(options.globalRegistry ?? loadPluginRegistry(path.join(getPluginRoot("global", options), "plugins.json")), options.projectRegistry ?? loadPluginRegistry(path.join(getPluginRoot("project", options), "plugins.json")));
9
+ const loaded = [];
10
+ for (const record of records) {
11
+ if (record.blocked) {
12
+ loaded.push({
13
+ ...record,
14
+ status: "blocked",
15
+ tools: {},
16
+ toolNames: []
17
+ });
18
+ continue;
19
+ }
20
+ if (!record.enabled) {
21
+ loaded.push({
22
+ ...record,
23
+ status: "inactive",
24
+ tools: {},
25
+ toolNames: []
26
+ });
27
+ continue;
28
+ }
29
+ loaded.push(await loadPluginRecord(record, options));
30
+ }
31
+ return markToolConflicts(loaded);
23
32
  }
24
33
  async function loadPluginRecord(record, options) {
25
- try {
26
- const entryPath = resolvePluginEntryPath(record, options);
27
- const plugin = await importPluginModule(entryPath);
28
- if (plugin.id !== record.id) {
29
- throw new Error(`Plugin id mismatch: registry has "${record.id}" but module exports "${plugin.id}"`);
30
- }
31
- const configSchema = validatePluginConfigSchema(plugin.config);
32
- const configValues = resolvePluginConfigValues(configSchema, record.config);
33
- const pluginDir = path.dirname(entryPath);
34
- const pluginRoot = resolvePluginRoot(record, options);
35
- const context = {
36
- cwd: options.projectRoot,
37
- scope: record.scope,
38
- pluginDir,
39
- config: configValues
40
- };
41
- const { tools, renderConfigs } = await resolvePluginTools(plugin, context);
42
- const instructions = await resolvePluginInstructions(plugin, context);
43
- return {
44
- ...record,
45
- name: plugin.name,
46
- version: plugin.version ?? record.version,
47
- description: plugin.description,
48
- instructions,
49
- status: "active",
50
- tools,
51
- renderConfigs,
52
- toolNames: Object.keys(tools).sort(),
53
- skillPaths: resolveExistingAssetDirs(pluginRoot, "skills"),
54
- commandPaths: resolveExistingAssetDirs(pluginRoot, "commands"),
55
- configSchema,
56
- configValues
57
- };
58
- } catch (error) {
59
- return {
60
- ...record,
61
- status: "load failed",
62
- error: error instanceof Error ? error.message : String(error),
63
- tools: {},
64
- toolNames: []
65
- };
66
- }
34
+ try {
35
+ const entryPath = resolvePluginEntryPath(record, options);
36
+ const plugin = await importPluginModule(entryPath);
37
+ if (plugin.id !== record.id) throw new Error(`Plugin id mismatch: registry has "${record.id}" but module exports "${plugin.id}"`);
38
+ const configSchema = validatePluginConfigSchema(plugin.config);
39
+ const configValues = resolvePluginConfigValues(configSchema, record.config);
40
+ const pluginDir = path.dirname(entryPath);
41
+ const pluginRoot = resolvePluginRoot(record, options);
42
+ const context = {
43
+ cwd: options.projectRoot,
44
+ scope: record.scope,
45
+ pluginDir,
46
+ config: configValues
47
+ };
48
+ const { tools, renderConfigs } = await resolvePluginTools(plugin, context);
49
+ const instructions = await resolvePluginInstructions(plugin, context);
50
+ return {
51
+ ...record,
52
+ name: plugin.name,
53
+ version: plugin.version ?? record.version,
54
+ description: plugin.description,
55
+ instructions,
56
+ status: "active",
57
+ tools,
58
+ renderConfigs,
59
+ toolNames: Object.keys(tools).sort(),
60
+ skillPaths: resolveExistingAssetDirs(pluginRoot, "skills"),
61
+ commandPaths: resolveExistingAssetDirs(pluginRoot, "commands"),
62
+ configSchema,
63
+ configValues
64
+ };
65
+ } catch (error) {
66
+ return {
67
+ ...record,
68
+ status: "load failed",
69
+ error: error instanceof Error ? error.message : String(error),
70
+ tools: {},
71
+ toolNames: []
72
+ };
73
+ }
67
74
  }
68
75
  async function loadPluginFromEntry(entryPath) {
69
- return validatePluginExport(await importPluginModule(entryPath));
76
+ return validatePluginExport(await importPluginModule(entryPath));
70
77
  }
71
78
  function resolvePluginRoot(record, options) {
72
- const scopeRoot = path.resolve(getPluginRoot(record.scope, options));
73
- const pluginRoot = path.resolve(path.isAbsolute(record.path) ? record.path : path.join(scopeRoot, record.path));
74
- if (record.source === "github" && !isInsideDirectory(pluginRoot, scopeRoot)) {
75
- throw new Error(`Plugin path for "${record.id}" must be inside the ${record.scope} plugin directory`);
76
- }
77
- return pluginRoot;
79
+ const scopeRoot = path.resolve(getPluginRoot(record.scope, options));
80
+ const pluginRoot = path.resolve(path.isAbsolute(record.path) ? record.path : path.join(scopeRoot, record.path));
81
+ if (record.source === "github" && !isInsideDirectory(pluginRoot, scopeRoot)) throw new Error(`Plugin path for "${record.id}" must be inside the ${record.scope} plugin directory`);
82
+ return pluginRoot;
78
83
  }
79
84
  function resolvePluginEntryPath(record, options) {
80
- const pluginRoot = resolvePluginRoot(record, options);
81
- const entryPath = path.resolve(pluginRoot, record.entry);
82
- if (!isInsideDirectory(entryPath, pluginRoot)) {
83
- throw new Error(`Plugin entry for "${record.id}" must be inside the plugin directory`);
84
- }
85
- return entryPath;
85
+ const pluginRoot = resolvePluginRoot(record, options);
86
+ const entryPath = path.resolve(pluginRoot, record.entry);
87
+ if (!isInsideDirectory(entryPath, pluginRoot)) throw new Error(`Plugin entry for "${record.id}" must be inside the plugin directory`);
88
+ return entryPath;
86
89
  }
87
90
  function isInsideDirectory(targetPath, root) {
88
- const resolvedTarget = path.resolve(targetPath);
89
- const resolvedRoot = path.resolve(root);
90
- return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(resolvedRoot + path.sep);
91
+ const resolvedTarget = path.resolve(targetPath);
92
+ const resolvedRoot = path.resolve(root);
93
+ return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(resolvedRoot + path.sep);
91
94
  }
92
95
  function resolveExistingAssetDirs(pluginRoot, dirname) {
93
- const dir = path.join(pluginRoot, dirname);
94
- try {
95
- return fs.statSync(dir).isDirectory() ? [dir] : [];
96
- } catch {
97
- return [];
98
- }
96
+ const dir = path.join(pluginRoot, dirname);
97
+ try {
98
+ return fs.statSync(dir).isDirectory() ? [dir] : [];
99
+ } catch {
100
+ return [];
101
+ }
99
102
  }
100
103
  async function importPluginModule(entryPath) {
101
- if (path.extname(entryPath) !== ".ts") {
102
- throw new Error(
103
- `Unsupported plugin entry extension "${path.extname(entryPath)}". V1 plugins must use .ts entries.`
104
- );
105
- }
106
- const url = pathToFileURL(entryPath);
107
- const stat = fs.statSync(entryPath, { bigint: true });
108
- url.searchParams.set("mtimeNs", stat.mtimeNs.toString());
109
- url.searchParams.set("size", stat.size.toString());
110
- const mod = await import(url.href);
111
- return validatePluginExport(mod.default ?? mod.plugin);
104
+ if (path.extname(entryPath) !== ".ts") throw new Error(`Unsupported plugin entry extension "${path.extname(entryPath)}". V1 plugins must use .ts entries.`);
105
+ const url = pathToFileURL(entryPath);
106
+ const stat = fs.statSync(entryPath, { bigint: true });
107
+ url.searchParams.set("mtimeNs", stat.mtimeNs.toString());
108
+ url.searchParams.set("size", stat.size.toString());
109
+ const mod = await import(url.href);
110
+ return validatePluginExport(mod.default ?? mod.plugin);
112
111
  }
113
112
  function validatePluginExport(value) {
114
- if (!value || typeof value !== "object") {
115
- throw new Error('Plugin module must export a plugin object as default or named "plugin" export');
116
- }
117
- const plugin = value;
118
- if (typeof plugin.id !== "string" || plugin.id.trim().length === 0) {
119
- throw new Error("Plugin id must be a non-empty string");
120
- }
121
- if (plugin.tools !== void 0 && typeof plugin.tools !== "object" && typeof plugin.tools !== "function") {
122
- throw new Error("Plugin tools must be an object or function");
123
- }
124
- return plugin;
113
+ if (!value || typeof value !== "object") throw new Error("Plugin module must export a plugin object as default or named \"plugin\" export");
114
+ const plugin = value;
115
+ if (typeof plugin.id !== "string" || plugin.id.trim().length === 0) throw new Error("Plugin id must be a non-empty string");
116
+ if (plugin.tools !== void 0 && typeof plugin.tools !== "object" && typeof plugin.tools !== "function") throw new Error("Plugin tools must be an object or function");
117
+ return plugin;
125
118
  }
126
119
  async function resolvePluginTools(plugin, context) {
127
- if (!plugin.tools) return { tools: {}, renderConfigs: {} };
128
- const entries = typeof plugin.tools === "function" ? await plugin.tools(context) : plugin.tools;
129
- if (!entries || typeof entries !== "object" || Array.isArray(entries)) {
130
- throw new Error("Plugin tools function must return an object");
131
- }
132
- return normalizePluginToolEntries(entries);
120
+ if (!plugin.tools) return {
121
+ tools: {},
122
+ renderConfigs: {}
123
+ };
124
+ const entries = typeof plugin.tools === "function" ? await plugin.tools(context) : plugin.tools;
125
+ if (!entries || typeof entries !== "object" || Array.isArray(entries)) throw new Error("Plugin tools function must return an object");
126
+ return normalizePluginToolEntries(entries);
133
127
  }
134
128
  async function resolvePluginInstructions(plugin, context) {
135
- if (plugin.instructions === void 0) return void 0;
136
- const instructions = typeof plugin.instructions === "function" ? await plugin.instructions(context) : plugin.instructions;
137
- if (typeof instructions !== "string") {
138
- throw new Error("Plugin instructions must be a string");
139
- }
140
- const trimmed = instructions.trim();
141
- return trimmed.length > 0 ? trimmed : void 0;
129
+ if (plugin.instructions === void 0) return void 0;
130
+ const instructions = typeof plugin.instructions === "function" ? await plugin.instructions(context) : plugin.instructions;
131
+ if (typeof instructions !== "string") throw new Error("Plugin instructions must be a string");
132
+ const trimmed = instructions.trim();
133
+ return trimmed.length > 0 ? trimmed : void 0;
142
134
  }
143
135
  function normalizePluginToolEntries(entries) {
144
- const tools = {};
145
- const renderConfigs = {};
146
- for (const [name, entry] of Object.entries(entries)) {
147
- if (!isToolEntryObject(entry)) {
148
- throw new Error(`Plugin tool "${name}" must be an object with a tool property`);
149
- }
150
- tools[name] = entry.tool;
151
- if (entry.render) renderConfigs[name] = entry.render;
152
- }
153
- return { tools, renderConfigs };
136
+ const tools = {};
137
+ const renderConfigs = {};
138
+ for (const [name, entry] of Object.entries(entries)) {
139
+ if (!isToolEntryObject(entry)) throw new Error(`Plugin tool "${name}" must be an object with a tool property`);
140
+ tools[name] = entry.tool;
141
+ if (entry.render) renderConfigs[name] = entry.render;
142
+ }
143
+ return {
144
+ tools,
145
+ renderConfigs
146
+ };
154
147
  }
155
148
  function isToolEntryObject(entry) {
156
- if (!entry || typeof entry !== "object" || !("tool" in entry)) return false;
157
- const tool = entry.tool;
158
- return !!tool && typeof tool === "object" && !Array.isArray(tool);
149
+ if (!entry || typeof entry !== "object" || !("tool" in entry)) return false;
150
+ const tool = entry.tool;
151
+ return !!tool && typeof tool === "object" && !Array.isArray(tool);
159
152
  }
160
153
  function validatePluginConfigSchema(schema) {
161
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) return void 0;
162
- const validated = {};
163
- for (const [key, option] of Object.entries(schema)) {
164
- if (!option || typeof option !== "object" || Array.isArray(option)) continue;
165
- const record = option;
166
- if (record.type !== "model" && record.type !== "boolean" && record.type !== "string") continue;
167
- validated[key] = {
168
- type: record.type,
169
- ...typeof record.label === "string" ? { label: record.label } : {},
170
- ...typeof record.description === "string" ? { description: record.description } : {},
171
- ...typeof record.default === "string" || typeof record.default === "boolean" ? { default: record.default } : {}
172
- };
173
- }
174
- return Object.keys(validated).length > 0 ? validated : void 0;
154
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) return void 0;
155
+ const validated = {};
156
+ for (const [key, option] of Object.entries(schema)) {
157
+ if (!option || typeof option !== "object" || Array.isArray(option)) continue;
158
+ const record = option;
159
+ if (record.type !== "model" && record.type !== "boolean" && record.type !== "string") continue;
160
+ validated[key] = {
161
+ type: record.type,
162
+ ...typeof record.label === "string" ? { label: record.label } : {},
163
+ ...typeof record.description === "string" ? { description: record.description } : {},
164
+ ...typeof record.default === "string" || typeof record.default === "boolean" ? { default: record.default } : {}
165
+ };
166
+ }
167
+ return Object.keys(validated).length > 0 ? validated : void 0;
175
168
  }
176
169
  function resolvePluginConfigValues(schema, recordValues) {
177
- const values = {};
178
- if (!schema) return values;
179
- for (const [key, option] of Object.entries(schema)) {
180
- const value = recordValues?.[key];
181
- if (option.type === "boolean") {
182
- values[key] = typeof value === "boolean" ? value : typeof option.default === "boolean" ? option.default : false;
183
- continue;
184
- }
185
- values[key] = typeof value === "string" ? value : typeof option.default === "string" ? option.default : void 0;
186
- }
187
- return values;
170
+ const values = {};
171
+ if (!schema) return values;
172
+ for (const [key, option] of Object.entries(schema)) {
173
+ const value = recordValues?.[key];
174
+ if (option.type === "boolean") {
175
+ values[key] = typeof value === "boolean" ? value : typeof option.default === "boolean" ? option.default : false;
176
+ continue;
177
+ }
178
+ values[key] = typeof value === "string" ? value : typeof option.default === "string" ? option.default : void 0;
179
+ }
180
+ return values;
188
181
  }
189
182
  function collectActivePluginTools(plugins) {
190
- const tools = {};
191
- for (const plugin of plugins) {
192
- if (plugin.status !== "active") continue;
193
- for (const [name, tool] of Object.entries(plugin.tools)) {
194
- if (!(name in tools)) {
195
- tools[name] = tool;
196
- }
197
- }
198
- }
199
- return tools;
183
+ const tools = {};
184
+ for (const plugin of plugins) {
185
+ if (plugin.status !== "active") continue;
186
+ for (const [name, tool] of Object.entries(plugin.tools)) if (!(name in tools)) tools[name] = tool;
187
+ }
188
+ return tools;
200
189
  }
201
190
  function markToolConflicts(plugins) {
202
- const seen = /* @__PURE__ */ new Map();
203
- return plugins.map((plugin) => {
204
- if (plugin.status !== "active") return plugin;
205
- const conflicts = plugin.toolNames.filter((toolName) => seen.has(toolName));
206
- for (const toolName of plugin.toolNames) {
207
- if (!seen.has(toolName)) seen.set(toolName, plugin.id);
208
- }
209
- return conflicts.length > 0 ? { ...plugin, status: "conflicted", conflicts } : plugin;
210
- });
211
- }
212
- export {
213
- collectActivePluginTools,
214
- isInsideDirectory,
215
- loadPluginFromEntry,
216
- loadPluginRecord,
217
- loadPlugins,
218
- resolvePluginEntryPath,
219
- resolvePluginRoot
220
- };
191
+ const seen = /* @__PURE__ */ new Map();
192
+ return plugins.map((plugin) => {
193
+ if (plugin.status !== "active") return plugin;
194
+ const conflicts = plugin.toolNames.filter((toolName) => seen.has(toolName));
195
+ for (const toolName of plugin.toolNames) if (!seen.has(toolName)) seen.set(toolName, plugin.id);
196
+ return conflicts.length > 0 ? {
197
+ ...plugin,
198
+ status: "conflicted",
199
+ conflicts
200
+ } : plugin;
201
+ });
202
+ }
203
+ //#endregion
204
+ export { collectActivePluginTools, isInsideDirectory, loadPluginFromEntry, loadPluginRecord, loadPlugins, resolvePluginEntryPath, resolvePluginRoot };
205
+
221
206
  //# sourceMappingURL=loader.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/plugins/loader.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport type {\n MastraCodePlugin,\n MastraCodePluginConfigSchema,\n MastraCodePluginConfigValues,\n MastraCodePluginContext,\n MastraCodePluginToolEntries,\n MastraCodePluginTools,\n MastraCodeToolRenderConfig,\n} from '../plugin.js';\nimport { getPluginRoot } from './paths.js';\nimport type { PluginPathOptions } from './paths.js';\nimport { loadPluginRegistry, mergePluginRegistries } from './registry.js';\nimport type { LoadedPlugin, PluginRegistry, ScopedInstalledPluginRecord } from './types.js';\n\nexport type LoadPluginsOptions = PluginPathOptions & {\n globalRegistry?: PluginRegistry;\n projectRegistry?: PluginRegistry;\n};\n\nexport async function loadPlugins(options: LoadPluginsOptions): Promise<LoadedPlugin[]> {\n const globalRegistry =\n options.globalRegistry ?? loadPluginRegistry(path.join(getPluginRoot('global', options), 'plugins.json'));\n const projectRegistry =\n options.projectRegistry ?? loadPluginRegistry(path.join(getPluginRoot('project', options), 'plugins.json'));\n const records = mergePluginRegistries(globalRegistry, projectRegistry);\n const loaded: LoadedPlugin[] = [];\n\n for (const record of records) {\n if (record.blocked) {\n loaded.push({ ...record, status: 'blocked', tools: {}, toolNames: [] });\n continue;\n }\n if (!record.enabled) {\n loaded.push({ ...record, status: 'inactive', tools: {}, toolNames: [] });\n continue;\n }\n\n loaded.push(await loadPluginRecord(record, options));\n }\n\n return markToolConflicts(loaded);\n}\n\nexport async function loadPluginRecord(\n record: ScopedInstalledPluginRecord,\n options: PluginPathOptions,\n): Promise<LoadedPlugin> {\n try {\n const entryPath = resolvePluginEntryPath(record, options);\n const plugin = await importPluginModule(entryPath);\n if (plugin.id !== record.id) {\n throw new Error(`Plugin id mismatch: registry has \"${record.id}\" but module exports \"${plugin.id}\"`);\n }\n\n const configSchema = validatePluginConfigSchema(plugin.config);\n const configValues = resolvePluginConfigValues(configSchema, record.config);\n const pluginDir = path.dirname(entryPath);\n const pluginRoot = resolvePluginRoot(record, options);\n const context: MastraCodePluginContext = {\n cwd: options.projectRoot,\n scope: record.scope,\n pluginDir,\n config: configValues,\n };\n const { tools, renderConfigs } = await resolvePluginTools(plugin, context);\n const instructions = await resolvePluginInstructions(plugin, context);\n\n return {\n ...record,\n name: plugin.name,\n version: plugin.version ?? record.version,\n description: plugin.description,\n instructions,\n status: 'active',\n tools,\n renderConfigs,\n toolNames: Object.keys(tools).sort(),\n skillPaths: resolveExistingAssetDirs(pluginRoot, 'skills'),\n commandPaths: resolveExistingAssetDirs(pluginRoot, 'commands'),\n configSchema,\n configValues,\n };\n } catch (error) {\n return {\n ...record,\n status: 'load failed',\n error: error instanceof Error ? error.message : String(error),\n tools: {},\n toolNames: [],\n };\n }\n}\n\nexport async function loadPluginFromEntry(entryPath: string): Promise<MastraCodePlugin> {\n return validatePluginExport(await importPluginModule(entryPath));\n}\n\nexport function resolvePluginRoot(record: ScopedInstalledPluginRecord, options: PluginPathOptions): string {\n const scopeRoot = path.resolve(getPluginRoot(record.scope, options));\n const pluginRoot = path.resolve(path.isAbsolute(record.path) ? record.path : path.join(scopeRoot, record.path));\n if (record.source === 'github' && !isInsideDirectory(pluginRoot, scopeRoot)) {\n throw new Error(`Plugin path for \"${record.id}\" must be inside the ${record.scope} plugin directory`);\n }\n return pluginRoot;\n}\n\nexport function resolvePluginEntryPath(record: ScopedInstalledPluginRecord, options: PluginPathOptions): string {\n const pluginRoot = resolvePluginRoot(record, options);\n const entryPath = path.resolve(pluginRoot, record.entry);\n if (!isInsideDirectory(entryPath, pluginRoot)) {\n throw new Error(`Plugin entry for \"${record.id}\" must be inside the plugin directory`);\n }\n return entryPath;\n}\n\nexport function isInsideDirectory(targetPath: string, root: string): boolean {\n const resolvedTarget = path.resolve(targetPath);\n const resolvedRoot = path.resolve(root);\n return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(resolvedRoot + path.sep);\n}\n\nfunction resolveExistingAssetDirs(pluginRoot: string, dirname: 'skills' | 'commands'): string[] {\n const dir = path.join(pluginRoot, dirname);\n try {\n return fs.statSync(dir).isDirectory() ? [dir] : [];\n } catch {\n return [];\n }\n}\n\nasync function importPluginModule(entryPath: string): Promise<MastraCodePlugin> {\n if (path.extname(entryPath) !== '.ts') {\n throw new Error(\n `Unsupported plugin entry extension \"${path.extname(entryPath)}\". V1 plugins must use .ts entries.`,\n );\n }\n\n const url = pathToFileURL(entryPath);\n const stat = fs.statSync(entryPath, { bigint: true });\n url.searchParams.set('mtimeNs', stat.mtimeNs.toString());\n url.searchParams.set('size', stat.size.toString());\n const mod = (await import(url.href)) as { default?: unknown; plugin?: unknown };\n return validatePluginExport(mod.default ?? mod.plugin);\n}\n\nfunction validatePluginExport(value: unknown): MastraCodePlugin {\n if (!value || typeof value !== 'object') {\n throw new Error('Plugin module must export a plugin object as default or named \"plugin\" export');\n }\n\n const plugin = value as MastraCodePlugin;\n if (typeof plugin.id !== 'string' || plugin.id.trim().length === 0) {\n throw new Error('Plugin id must be a non-empty string');\n }\n\n if (plugin.tools !== undefined && typeof plugin.tools !== 'object' && typeof plugin.tools !== 'function') {\n throw new Error('Plugin tools must be an object or function');\n }\n\n return plugin;\n}\n\nasync function resolvePluginTools(\n plugin: MastraCodePlugin,\n context: MastraCodePluginContext,\n): Promise<{ tools: MastraCodePluginTools; renderConfigs: Record<string, MastraCodeToolRenderConfig> }> {\n if (!plugin.tools) return { tools: {}, renderConfigs: {} };\n const entries = typeof plugin.tools === 'function' ? await plugin.tools(context) : plugin.tools;\n if (!entries || typeof entries !== 'object' || Array.isArray(entries)) {\n throw new Error('Plugin tools function must return an object');\n }\n return normalizePluginToolEntries(entries);\n}\n\nasync function resolvePluginInstructions(\n plugin: MastraCodePlugin,\n context: MastraCodePluginContext,\n): Promise<string | undefined> {\n if (plugin.instructions === undefined) return undefined;\n const instructions =\n typeof plugin.instructions === 'function' ? await plugin.instructions(context) : plugin.instructions;\n if (typeof instructions !== 'string') {\n throw new Error('Plugin instructions must be a string');\n }\n const trimmed = instructions.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction normalizePluginToolEntries(entries: MastraCodePluginToolEntries): {\n tools: MastraCodePluginTools;\n renderConfigs: Record<string, MastraCodeToolRenderConfig>;\n} {\n const tools: MastraCodePluginTools = {};\n const renderConfigs: Record<string, MastraCodeToolRenderConfig> = {};\n for (const [name, entry] of Object.entries(entries)) {\n if (!isToolEntryObject(entry)) {\n throw new Error(`Plugin tool \"${name}\" must be an object with a tool property`);\n }\n tools[name] = entry.tool;\n if (entry.render) renderConfigs[name] = entry.render;\n }\n return { tools, renderConfigs };\n}\n\nfunction isToolEntryObject(entry: MastraCodePluginToolEntries[string]): entry is MastraCodePluginToolEntries[string] {\n if (!entry || typeof entry !== 'object' || !('tool' in entry)) return false;\n const tool = (entry as { tool?: unknown }).tool;\n return !!tool && typeof tool === 'object' && !Array.isArray(tool);\n}\n\nfunction validatePluginConfigSchema(schema: unknown): MastraCodePluginConfigSchema | undefined {\n if (!schema || typeof schema !== 'object' || Array.isArray(schema)) return undefined;\n const validated: MastraCodePluginConfigSchema = {};\n for (const [key, option] of Object.entries(schema)) {\n if (!option || typeof option !== 'object' || Array.isArray(option)) continue;\n const record = option as Record<string, unknown>;\n if (record.type !== 'model' && record.type !== 'boolean' && record.type !== 'string') continue;\n validated[key] = {\n type: record.type,\n ...(typeof record.label === 'string' ? { label: record.label } : {}),\n ...(typeof record.description === 'string' ? { description: record.description } : {}),\n ...(typeof record.default === 'string' || typeof record.default === 'boolean' ? { default: record.default } : {}),\n };\n }\n return Object.keys(validated).length > 0 ? validated : undefined;\n}\n\nfunction resolvePluginConfigValues(\n schema: MastraCodePluginConfigSchema | undefined,\n recordValues: Record<string, unknown> | undefined,\n): MastraCodePluginConfigValues {\n const values: MastraCodePluginConfigValues = {};\n if (!schema) return values;\n for (const [key, option] of Object.entries(schema)) {\n const value = recordValues?.[key];\n if (option.type === 'boolean') {\n values[key] = typeof value === 'boolean' ? value : typeof option.default === 'boolean' ? option.default : false;\n continue;\n }\n values[key] = typeof value === 'string' ? value : typeof option.default === 'string' ? option.default : undefined;\n }\n return values;\n}\n\nexport function collectActivePluginTools(plugins: LoadedPlugin[]): MastraCodePluginTools {\n const tools: MastraCodePluginTools = {};\n for (const plugin of plugins) {\n if (plugin.status !== 'active') continue;\n for (const [name, tool] of Object.entries(plugin.tools)) {\n if (!(name in tools)) {\n tools[name] = tool;\n }\n }\n }\n return tools;\n}\n\nfunction markToolConflicts(plugins: LoadedPlugin[]): LoadedPlugin[] {\n const seen = new Map<string, string>();\n return plugins.map(plugin => {\n if (plugin.status !== 'active') return plugin;\n const conflicts = plugin.toolNames.filter(toolName => seen.has(toolName));\n for (const toolName of plugin.toolNames) {\n if (!seen.has(toolName)) seen.set(toolName, plugin.id);\n }\n return conflicts.length > 0 ? { ...plugin, status: 'conflicted', conflicts } : plugin;\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"file":"loader.js","names":[],"sources":["../../src/plugins/loader.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport type {\n MastraCodePlugin,\n MastraCodePluginConfigSchema,\n MastraCodePluginConfigValues,\n MastraCodePluginContext,\n MastraCodePluginToolEntries,\n MastraCodePluginTools,\n MastraCodeToolRenderConfig,\n} from '../plugin.js';\nimport { getPluginRoot } from './paths.js';\nimport type { PluginPathOptions } from './paths.js';\nimport { loadPluginRegistry, mergePluginRegistries } from './registry.js';\nimport type { LoadedPlugin, PluginRegistry, ScopedInstalledPluginRecord } from './types.js';\n\nexport type LoadPluginsOptions = PluginPathOptions & {\n globalRegistry?: PluginRegistry;\n projectRegistry?: PluginRegistry;\n};\n\nexport async function loadPlugins(options: LoadPluginsOptions): Promise<LoadedPlugin[]> {\n const globalRegistry =\n options.globalRegistry ?? loadPluginRegistry(path.join(getPluginRoot('global', options), 'plugins.json'));\n const projectRegistry =\n options.projectRegistry ?? loadPluginRegistry(path.join(getPluginRoot('project', options), 'plugins.json'));\n const records = mergePluginRegistries(globalRegistry, projectRegistry);\n const loaded: LoadedPlugin[] = [];\n\n for (const record of records) {\n if (record.blocked) {\n loaded.push({ ...record, status: 'blocked', tools: {}, toolNames: [] });\n continue;\n }\n if (!record.enabled) {\n loaded.push({ ...record, status: 'inactive', tools: {}, toolNames: [] });\n continue;\n }\n\n loaded.push(await loadPluginRecord(record, options));\n }\n\n return markToolConflicts(loaded);\n}\n\nexport async function loadPluginRecord(\n record: ScopedInstalledPluginRecord,\n options: PluginPathOptions,\n): Promise<LoadedPlugin> {\n try {\n const entryPath = resolvePluginEntryPath(record, options);\n const plugin = await importPluginModule(entryPath);\n if (plugin.id !== record.id) {\n throw new Error(`Plugin id mismatch: registry has \"${record.id}\" but module exports \"${plugin.id}\"`);\n }\n\n const configSchema = validatePluginConfigSchema(plugin.config);\n const configValues = resolvePluginConfigValues(configSchema, record.config);\n const pluginDir = path.dirname(entryPath);\n const pluginRoot = resolvePluginRoot(record, options);\n const context: MastraCodePluginContext = {\n cwd: options.projectRoot,\n scope: record.scope,\n pluginDir,\n config: configValues,\n };\n const { tools, renderConfigs } = await resolvePluginTools(plugin, context);\n const instructions = await resolvePluginInstructions(plugin, context);\n\n return {\n ...record,\n name: plugin.name,\n version: plugin.version ?? record.version,\n description: plugin.description,\n instructions,\n status: 'active',\n tools,\n renderConfigs,\n toolNames: Object.keys(tools).sort(),\n skillPaths: resolveExistingAssetDirs(pluginRoot, 'skills'),\n commandPaths: resolveExistingAssetDirs(pluginRoot, 'commands'),\n configSchema,\n configValues,\n };\n } catch (error) {\n return {\n ...record,\n status: 'load failed',\n error: error instanceof Error ? error.message : String(error),\n tools: {},\n toolNames: [],\n };\n }\n}\n\nexport async function loadPluginFromEntry(entryPath: string): Promise<MastraCodePlugin> {\n return validatePluginExport(await importPluginModule(entryPath));\n}\n\nexport function resolvePluginRoot(record: ScopedInstalledPluginRecord, options: PluginPathOptions): string {\n const scopeRoot = path.resolve(getPluginRoot(record.scope, options));\n const pluginRoot = path.resolve(path.isAbsolute(record.path) ? record.path : path.join(scopeRoot, record.path));\n if (record.source === 'github' && !isInsideDirectory(pluginRoot, scopeRoot)) {\n throw new Error(`Plugin path for \"${record.id}\" must be inside the ${record.scope} plugin directory`);\n }\n return pluginRoot;\n}\n\nexport function resolvePluginEntryPath(record: ScopedInstalledPluginRecord, options: PluginPathOptions): string {\n const pluginRoot = resolvePluginRoot(record, options);\n const entryPath = path.resolve(pluginRoot, record.entry);\n if (!isInsideDirectory(entryPath, pluginRoot)) {\n throw new Error(`Plugin entry for \"${record.id}\" must be inside the plugin directory`);\n }\n return entryPath;\n}\n\nexport function isInsideDirectory(targetPath: string, root: string): boolean {\n const resolvedTarget = path.resolve(targetPath);\n const resolvedRoot = path.resolve(root);\n return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(resolvedRoot + path.sep);\n}\n\nfunction resolveExistingAssetDirs(pluginRoot: string, dirname: 'skills' | 'commands'): string[] {\n const dir = path.join(pluginRoot, dirname);\n try {\n return fs.statSync(dir).isDirectory() ? [dir] : [];\n } catch {\n return [];\n }\n}\n\nasync function importPluginModule(entryPath: string): Promise<MastraCodePlugin> {\n if (path.extname(entryPath) !== '.ts') {\n throw new Error(\n `Unsupported plugin entry extension \"${path.extname(entryPath)}\". V1 plugins must use .ts entries.`,\n );\n }\n\n const url = pathToFileURL(entryPath);\n const stat = fs.statSync(entryPath, { bigint: true });\n url.searchParams.set('mtimeNs', stat.mtimeNs.toString());\n url.searchParams.set('size', stat.size.toString());\n const mod = (await import(url.href)) as { default?: unknown; plugin?: unknown };\n return validatePluginExport(mod.default ?? mod.plugin);\n}\n\nfunction validatePluginExport(value: unknown): MastraCodePlugin {\n if (!value || typeof value !== 'object') {\n throw new Error('Plugin module must export a plugin object as default or named \"plugin\" export');\n }\n\n const plugin = value as MastraCodePlugin;\n if (typeof plugin.id !== 'string' || plugin.id.trim().length === 0) {\n throw new Error('Plugin id must be a non-empty string');\n }\n\n if (plugin.tools !== undefined && typeof plugin.tools !== 'object' && typeof plugin.tools !== 'function') {\n throw new Error('Plugin tools must be an object or function');\n }\n\n return plugin;\n}\n\nasync function resolvePluginTools(\n plugin: MastraCodePlugin,\n context: MastraCodePluginContext,\n): Promise<{ tools: MastraCodePluginTools; renderConfigs: Record<string, MastraCodeToolRenderConfig> }> {\n if (!plugin.tools) return { tools: {}, renderConfigs: {} };\n const entries = typeof plugin.tools === 'function' ? await plugin.tools(context) : plugin.tools;\n if (!entries || typeof entries !== 'object' || Array.isArray(entries)) {\n throw new Error('Plugin tools function must return an object');\n }\n return normalizePluginToolEntries(entries);\n}\n\nasync function resolvePluginInstructions(\n plugin: MastraCodePlugin,\n context: MastraCodePluginContext,\n): Promise<string | undefined> {\n if (plugin.instructions === undefined) return undefined;\n const instructions =\n typeof plugin.instructions === 'function' ? await plugin.instructions(context) : plugin.instructions;\n if (typeof instructions !== 'string') {\n throw new Error('Plugin instructions must be a string');\n }\n const trimmed = instructions.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction normalizePluginToolEntries(entries: MastraCodePluginToolEntries): {\n tools: MastraCodePluginTools;\n renderConfigs: Record<string, MastraCodeToolRenderConfig>;\n} {\n const tools: MastraCodePluginTools = {};\n const renderConfigs: Record<string, MastraCodeToolRenderConfig> = {};\n for (const [name, entry] of Object.entries(entries)) {\n if (!isToolEntryObject(entry)) {\n throw new Error(`Plugin tool \"${name}\" must be an object with a tool property`);\n }\n tools[name] = entry.tool;\n if (entry.render) renderConfigs[name] = entry.render;\n }\n return { tools, renderConfigs };\n}\n\nfunction isToolEntryObject(entry: MastraCodePluginToolEntries[string]): entry is MastraCodePluginToolEntries[string] {\n if (!entry || typeof entry !== 'object' || !('tool' in entry)) return false;\n const tool = (entry as { tool?: unknown }).tool;\n return !!tool && typeof tool === 'object' && !Array.isArray(tool);\n}\n\nfunction validatePluginConfigSchema(schema: unknown): MastraCodePluginConfigSchema | undefined {\n if (!schema || typeof schema !== 'object' || Array.isArray(schema)) return undefined;\n const validated: MastraCodePluginConfigSchema = {};\n for (const [key, option] of Object.entries(schema)) {\n if (!option || typeof option !== 'object' || Array.isArray(option)) continue;\n const record = option as Record<string, unknown>;\n if (record.type !== 'model' && record.type !== 'boolean' && record.type !== 'string') continue;\n validated[key] = {\n type: record.type,\n ...(typeof record.label === 'string' ? { label: record.label } : {}),\n ...(typeof record.description === 'string' ? { description: record.description } : {}),\n ...(typeof record.default === 'string' || typeof record.default === 'boolean' ? { default: record.default } : {}),\n };\n }\n return Object.keys(validated).length > 0 ? validated : undefined;\n}\n\nfunction resolvePluginConfigValues(\n schema: MastraCodePluginConfigSchema | undefined,\n recordValues: Record<string, unknown> | undefined,\n): MastraCodePluginConfigValues {\n const values: MastraCodePluginConfigValues = {};\n if (!schema) return values;\n for (const [key, option] of Object.entries(schema)) {\n const value = recordValues?.[key];\n if (option.type === 'boolean') {\n values[key] = typeof value === 'boolean' ? value : typeof option.default === 'boolean' ? option.default : false;\n continue;\n }\n values[key] = typeof value === 'string' ? value : typeof option.default === 'string' ? option.default : undefined;\n }\n return values;\n}\n\nexport function collectActivePluginTools(plugins: LoadedPlugin[]): MastraCodePluginTools {\n const tools: MastraCodePluginTools = {};\n for (const plugin of plugins) {\n if (plugin.status !== 'active') continue;\n for (const [name, tool] of Object.entries(plugin.tools)) {\n if (!(name in tools)) {\n tools[name] = tool;\n }\n }\n }\n return tools;\n}\n\nfunction markToolConflicts(plugins: LoadedPlugin[]): LoadedPlugin[] {\n const seen = new Map<string, string>();\n return plugins.map(plugin => {\n if (plugin.status !== 'active') return plugin;\n const conflicts = plugin.toolNames.filter(toolName => seen.has(toolName));\n for (const toolName of plugin.toolNames) {\n if (!seen.has(toolName)) seen.set(toolName, plugin.id);\n }\n return conflicts.length > 0 ? { ...plugin, status: 'conflicted', conflicts } : plugin;\n });\n}\n"],"mappings":"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"}