@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.
- package/CHANGELOG.md +38 -0
- package/dist/acp/agent.js +155 -167
- package/dist/acp/agent.js.map +1 -1
- package/dist/acp/event-mapper.js +193 -168
- package/dist/acp/event-mapper.js.map +1 -1
- package/dist/acp/index.js +60 -49
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/server.js +31 -30
- package/dist/acp/server.js.map +1 -1
- package/dist/acp.js +1 -4
- package/dist/agents/credential-resolver.js +40 -29
- package/dist/agents/credential-resolver.js.map +1 -1
- package/dist/agents/custom-provider-source.js +16 -9
- package/dist/agents/custom-provider-source.js.map +1 -1
- package/dist/agents/instructions.js +27 -36
- package/dist/agents/instructions.js.map +1 -1
- package/dist/agents/mastracode-gateway.js +355 -428
- package/dist/agents/mastracode-gateway.js.map +1 -1
- package/dist/agents/memory.js +87 -78
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/model.js +114 -119
- package/dist/agents/model.js.map +1 -1
- package/dist/agents/modes/build.js +12 -13
- package/dist/agents/modes/build.js.map +1 -1
- package/dist/agents/modes/explore.js +14 -13
- package/dist/agents/modes/explore.js.map +1 -1
- package/dist/agents/modes/plan.js +14 -15
- package/dist/agents/modes/plan.js.map +1 -1
- package/dist/agents/prompts/agent-instructions.js +78 -69
- package/dist/agents/prompts/agent-instructions.js.map +1 -1
- package/dist/agents/prompts/build.js +19 -16
- package/dist/agents/prompts/build.js.map +1 -1
- package/dist/agents/prompts/fast.js +8 -4
- package/dist/agents/prompts/fast.js.map +1 -1
- package/dist/agents/prompts/index.js +48 -47
- package/dist/agents/prompts/index.js.map +1 -1
- package/dist/agents/prompts/model.js +6 -5
- package/dist/agents/prompts/model.js.map +1 -1
- package/dist/agents/prompts/plan.js +20 -16
- package/dist/agents/prompts/plan.js.map +1 -1
- package/dist/agents/prompts/tool-guidance.js +77 -109
- package/dist/agents/prompts/tool-guidance.js.map +1 -1
- package/dist/agents/sandbox-filesystem.js +245 -259
- package/dist/agents/sandbox-filesystem.js.map +1 -1
- package/dist/agents/sandbox-reattach.js +9 -11
- package/dist/agents/sandbox-reattach.js.map +1 -1
- package/dist/agents/thread-caveman-state.js +92 -81
- package/dist/agents/thread-caveman-state.js.map +1 -1
- package/dist/agents/tool-availability.js +62 -80
- package/dist/agents/tool-availability.js.map +1 -1
- package/dist/agents/tools.js +99 -139
- package/dist/agents/tools.js.map +1 -1
- package/dist/agents/workspace.js +232 -225
- package/dist/agents/workspace.js.map +1 -1
- package/dist/analytics.js +139 -128
- package/dist/analytics.js.map +1 -1
- package/dist/auth/authorization-input.js +39 -25
- package/dist/auth/authorization-input.js.map +1 -1
- package/dist/auth/device-code.js +112 -80
- package/dist/auth/device-code.js.map +1 -1
- package/dist/auth/index.js +2 -9
- package/dist/auth/pkce.js +27 -16
- package/dist/auth/pkce.js.map +1 -1
- package/dist/auth/providers/anthropic.js +107 -93
- package/dist/auth/providers/anthropic.js.map +1 -1
- package/dist/auth/providers/github-copilot.js +304 -293
- package/dist/auth/providers/github-copilot.js.map +1 -1
- package/dist/auth/providers/openai-codex.js +442 -460
- package/dist/auth/providers/openai-codex.js.map +1 -1
- package/dist/auth/providers/xai.js +179 -145
- package/dist/auth/providers/xai.js.map +1 -1
- package/dist/auth/storage.js +182 -175
- package/dist/auth/storage.js.map +1 -1
- package/dist/auth/types.js +1 -1
- package/dist/clipboard/index.js +206 -172
- package/dist/clipboard/index.js.map +1 -1
- package/dist/constants.js +11 -16
- package/dist/constants.js.map +1 -1
- package/dist/error-classification.js +19 -11
- package/dist/error-classification.js.map +1 -1
- package/dist/evals/context-builder.js +145 -104
- package/dist/evals/context-builder.js.map +1 -1
- package/dist/evals/index.js +4 -7
- package/dist/evals/scorers/classify-command.js +62 -41
- package/dist/evals/scorers/classify-command.js.map +1 -1
- package/dist/evals/scorers/efficiency.js +239 -181
- package/dist/evals/scorers/efficiency.js.map +1 -1
- package/dist/evals/scorers/extract-tools.js +51 -47
- package/dist/evals/scorers/extract-tools.js.map +1 -1
- package/dist/evals/scorers/index.js +1 -5
- package/dist/evals/scorers/outcome.js +321 -212
- package/dist/evals/scorers/outcome.js.map +1 -1
- package/dist/goal-manager.js +266 -261
- package/dist/goal-manager.js.map +1 -1
- package/dist/goal-signal.js +14 -13
- package/dist/goal-signal.js.map +1 -1
- package/dist/headless/cli.js +153 -154
- package/dist/headless/cli.js.map +1 -1
- package/dist/headless/flags.js +180 -178
- package/dist/headless/flags.js.map +1 -1
- package/dist/headless/format.js +72 -71
- package/dist/headless/format.js.map +1 -1
- package/dist/headless/index.js +5 -31
- package/dist/headless/policy.js +35 -31
- package/dist/headless/policy.js.map +1 -1
- package/dist/headless/run-mc.js +332 -334
- package/dist/headless/run-mc.js.map +1 -1
- package/dist/headless/types.js +16 -7
- package/dist/headless/types.js.map +1 -1
- package/dist/hooks/config.js +56 -61
- package/dist/hooks/config.js.map +1 -1
- package/dist/hooks/executor.js +118 -116
- package/dist/hooks/executor.js.map +1 -1
- package/dist/hooks/index.js +4 -15
- package/dist/hooks/manager.js +221 -280
- package/dist/hooks/manager.js.map +1 -1
- package/dist/hooks/types.js +5 -4
- package/dist/hooks/types.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +632 -712
- package/dist/index.js.map +1 -1
- package/dist/ipc/ipc-reporter.js +19 -22
- package/dist/ipc/ipc-reporter.js.map +1 -1
- package/dist/lsp/client.js +248 -306
- package/dist/lsp/client.js.map +1 -1
- package/dist/lsp/index.js +1 -6
- package/dist/lsp/language.js +39 -43
- package/dist/lsp/language.js.map +1 -1
- package/dist/lsp/manager.js +78 -93
- package/dist/lsp/manager.js.map +1 -1
- package/dist/lsp/server.js +151 -120
- package/dist/lsp/server.js.map +1 -1
- package/dist/lsp/workspace.js +50 -47
- package/dist/lsp/workspace.js.map +1 -1
- package/dist/mcp/config.js +210 -199
- package/dist/mcp/config.js.map +1 -1
- package/dist/mcp/index.js +2 -9
- package/dist/mcp/manager.js +482 -475
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/types.js +1 -1
- package/dist/onboarding/custom-packs.js +14 -17
- package/dist/onboarding/custom-packs.js.map +1 -1
- package/dist/onboarding/custom-providers.js +22 -20
- package/dist/onboarding/custom-providers.js.map +1 -1
- package/dist/onboarding/index.d.ts +1 -1
- package/dist/onboarding/index.d.ts.map +1 -1
- package/dist/onboarding/index.js +3 -21
- package/dist/onboarding/om-settings.d.ts +5 -0
- package/dist/onboarding/om-settings.d.ts.map +1 -1
- package/dist/onboarding/om-settings.js +41 -20
- package/dist/onboarding/om-settings.js.map +1 -1
- package/dist/onboarding/packs.d.ts +4 -6
- package/dist/onboarding/packs.d.ts.map +1 -1
- package/dist/onboarding/packs.js +154 -105
- package/dist/onboarding/packs.js.map +1 -1
- package/dist/onboarding/settings.js +575 -517
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/permissions.js +112 -99
- package/dist/permissions.js.map +1 -1
- package/dist/plugin.js +21 -23
- package/dist/plugin.js.map +1 -1
- package/dist/plugins/dependencies.js +64 -87
- package/dist/plugins/dependencies.js.map +1 -1
- package/dist/plugins/install.js +159 -169
- package/dist/plugins/install.js.map +1 -1
- package/dist/plugins/loader.js +170 -185
- package/dist/plugins/loader.js.map +1 -1
- package/dist/plugins/manager.js +374 -380
- package/dist/plugins/manager.js.map +1 -1
- package/dist/plugins/manifest.js +38 -63
- package/dist/plugins/manifest.js.map +1 -1
- package/dist/plugins/package-link.js +48 -64
- package/dist/plugins/package-link.js.map +1 -1
- package/dist/plugins/paths.js +18 -19
- package/dist/plugins/paths.js.map +1 -1
- package/dist/plugins/registry.js +97 -81
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/scaffold.js +62 -98
- package/dist/plugins/scaffold.js.map +1 -1
- package/dist/plugins/types.js +1 -1
- package/dist/processors/plan-rejection-abort.js +45 -44
- package/dist/processors/plan-rejection-abort.js.map +1 -1
- package/dist/providers/amazon-bedrock-gateway.js +134 -125
- package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
- package/dist/providers/amazon-bedrock.js +68 -47
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/claude-max.js +153 -133
- package/dist/providers/claude-max.js.map +1 -1
- package/dist/providers/github-copilot.js +232 -230
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/openai-codex.js +271 -260
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/xai.js +57 -50
- package/dist/providers/xai.js.map +1 -1
- package/dist/schema.js +91 -89
- package/dist/schema.js.map +1 -1
- package/dist/theme-palette.js +18 -14
- package/dist/theme-palette.js.map +1 -1
- package/dist/tool-names.js +46 -37
- package/dist/tool-names.js.map +1 -1
- package/dist/tools/index.js +2 -8
- package/dist/tools/request-sandbox-access.js +71 -80
- package/dist/tools/request-sandbox-access.js.map +1 -1
- package/dist/tools/utils.js +26 -16
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/web-search.js +51 -55
- package/dist/tools/web-search.js.map +1 -1
- package/dist/utils/binaries.js +65 -61
- package/dist/utils/binaries.js.map +1 -1
- package/dist/utils/debug-log.js +51 -47
- package/dist/utils/debug-log.js.map +1 -1
- package/dist/utils/errors.js +157 -192
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/gateway-sync.js +49 -37
- package/dist/utils/gateway-sync.js.map +1 -1
- package/dist/utils/path-security.js +7 -6
- package/dist/utils/path-security.js.map +1 -1
- package/dist/utils/plan-diff.js +58 -39
- package/dist/utils/plan-diff.js.map +1 -1
- package/dist/utils/plans.js +92 -74
- package/dist/utils/plans.js.map +1 -1
- package/dist/utils/project.js +318 -256
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/signals-pubsub.js +117 -99
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/dist/utils/slash-command-loader.js +118 -154
- package/dist/utils/slash-command-loader.js.map +1 -1
- package/dist/utils/slash-command-processor.js +92 -83
- package/dist/utils/slash-command-processor.js.map +1 -1
- package/dist/utils/stdin-pipe.js +87 -63
- package/dist/utils/stdin-pipe.js.map +1 -1
- package/dist/utils/storage-factory.js +104 -84
- package/dist/utils/storage-factory.js.map +1 -1
- package/dist/utils/storage-maintenance.js +249 -211
- package/dist/utils/storage-maintenance.js.map +1 -1
- package/dist/utils/thread-lock.js +96 -92
- package/dist/utils/thread-lock.js.map +1 -1
- package/dist/utils/token-estimator.js +12 -12
- package/dist/utils/token-estimator.js.map +1 -1
- package/dist/utils/update-check.d.ts +1 -1
- package/dist/utils/update-check.js +341 -259
- package/dist/utils/update-check.js.map +1 -1
- package/dist/voice/stt-registry.js +131 -113
- package/dist/voice/stt-registry.js.map +1 -1
- package/package.json +12 -12
- package/dist/acp.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/evals/index.js.map +0 -1
- package/dist/evals/scorers/index.js.map +0 -1
- package/dist/headless/index.js.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/lsp/index.js.map +0 -1
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/types.js.map +0 -1
- package/dist/onboarding/index.js.map +0 -1
- package/dist/plugins/types.js.map +0 -1
- 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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"}
|
package/dist/plugins/loader.js
CHANGED
|
@@ -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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
76
|
+
return validatePluginExport(await importPluginModule(entryPath));
|
|
70
77
|
}
|
|
71
78
|
function resolvePluginRoot(record, options) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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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"}
|